/* Life.c Gary Teachout August 1989 lc -L Life To compile and link with Lattice 5.0 */ #include #include #include #define FPEN 1 #define DPEN 1 #define BPEN 0 #define SIZEX 160 #define SIZEY 94 #define PLANES 1 struct menubox { struct MenuItem item ; struct IntuiText text ; } ; struct IntuitionBase *IntuitionBase ; struct GfxBase *GfxBase ; struct IntuiMessage *mes ; struct Screen *screen ; struct Window *window ; ULONG class ; USHORT code ; struct NewScreen ns = { 0 , 0 , 320 , 200 , PLANES , DPEN , BPEN , 0 , CUSTOMSCREEN , NULL , NULL , NULL , NULL } ; UBYTE *title[ 2 ] = { " Life" , " Edit Seed" } ; struct NewWindow nw = { 0 , 0 , 320 , 200 , DPEN , BPEN , MENUPICK | MENUVERIFY | MOUSEBUTTONS , SMART_REFRESH | ACTIVATE | BACKDROP | BORDERLESS , NULL , NULL , NULL , NULL , NULL , 0 , 0 , 0 , 0 , CUSTOMSCREEN } ; USHORT chip pointer[ 20 ] = { 0x0000 , 0x0000 , 0x8000 , 0x0000 , 0xc000 , 0x0000 , 0xa000 , 0x0000 , 0x9000 , 0x0000 , 0x8800 , 0x0000 , 0x8400 , 0x0000 , 0x8000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 } ; struct Menu menulist[ 2 ] = { { NULL , 1 , 0 , 90 , 8 , MENUENABLED , " Control" , NULL } , { NULL , 1 , 0 , 90 , 8 , MENUENABLED , " Edit" , NULL } } ; struct menubox controlmenu[ 5 ] = { { { NULL , 0 , 0 , 140 , 11 , ITEMTEXT | ITEMENABLED | HIGHCOMP | COMMSEQ , 0 , NULL , NULL , 'S' , NULL , NULL } , { FPEN , BPEN , JAM1 , 10 , 2 , NULL , "Stop" , NULL } } , { { NULL , 0 , 11 , 140 , 11 , ITEMTEXT | ITEMENABLED | HIGHCOMP | COMMSEQ , 0 , NULL , NULL , 'G' , NULL , NULL } , { FPEN , BPEN , JAM1 , 10 , 2 , NULL , "Go" , NULL } } , { { NULL , 0 , 22 , 140 , 11 , ITEMTEXT | ITEMENABLED | HIGHCOMP | COMMSEQ , 0 , NULL , NULL , 'C' , NULL , NULL } , { FPEN , BPEN , JAM1 , 10 , 2 , NULL , "Custom Seed" , NULL } } , { { NULL , 0 , 33 , 140 , 11 , ITEMTEXT | ITEMENABLED | HIGHCOMP , 0 , NULL , NULL , 0 , NULL , NULL } , { FPEN , BPEN , JAM1 , 10 , 2 , NULL , "Random Seed" , NULL } } , { { NULL , 0 , 50 , 140 , 11 , ITEMTEXT | ITEMENABLED | HIGHCOMP | COMMSEQ , 0 , NULL , NULL , 'Q' , NULL , NULL } , { FPEN , BPEN , JAM1 , 10 , 2 , NULL , "Quit" , NULL } } } , seedsub[ 3 ] = { { { NULL , 130 , 0 , 120 , 11 , ITEMTEXT | ITEMENABLED | HIGHCOMP | COMMSEQ , 0 , NULL , NULL , '1' , NULL , NULL } , { FPEN , BPEN , JAM1 , 10 , 2 , NULL , "Small" , NULL } } , { { NULL , 130 , 11 , 120 , 11 , ITEMTEXT | ITEMENABLED | HIGHCOMP | COMMSEQ, 0 , NULL , NULL , '2' , NULL , NULL } , { FPEN , BPEN , JAM1 , 10 , 2 , NULL , "Medium" , NULL } } , { { NULL , 130 , 22 , 120 , 11 , ITEMTEXT | ITEMENABLED | HIGHCOMP | COMMSEQ , 0 , NULL , NULL , '3' , NULL , NULL } , { FPEN , BPEN , JAM1 , 10 , 2 , NULL , "Large" , NULL } } } , editmenu[ 4 ] = { { { NULL , 0 , 0 , 170 , 11 , ITEMTEXT | ITEMENABLED | HIGHCOMP | COMMSEQ | CHECKIT , 0x02 , NULL , NULL , 'A' , NULL , NULL } , { FPEN , BPEN , JAM1 , 25 , 2 , NULL , "Alive (White)" , NULL } } , { { NULL , 0 , 11 , 170 , 11 , ITEMTEXT | ITEMENABLED | HIGHCOMP | COMMSEQ | CHECKIT , 0x01 , NULL , NULL , 'D' , NULL , NULL } , { FPEN , BPEN , JAM1 , 25 , 2 , NULL , "Dead (Black)" , NULL } } , { { NULL , 0 , 22 , 170 , 11 , ITEMTEXT | ITEMENABLED | HIGHCOMP | COMMSEQ , 0 , NULL , NULL , 'B' , NULL , NULL } , { FPEN , BPEN , JAM1 , 25 , 2 , NULL , "Blank Field" , NULL } } , { { NULL , 0 , 33 , 170 , 11 , ITEMTEXT | ITEMENABLED | HIGHCOMP | COMMSEQ , 0 , NULL , NULL , 'C' , NULL , NULL } , { FPEN , BPEN , JAM1 , 25 , 2 , NULL , "Continue" , NULL } } } ; struct TextAttr stext = { "topaz.font" , 8 , 0 , 0 } ; UBYTE *cells1 , *cells2 , *old , *new ; short stopflag = 0 , reseed = 0 ; char *AllocMem() ; struct Screen *OpenScreen() ; struct Window *OpenWindow() ; struct IntuiMessage *GetMsg() ; void cleanup( void ) ; void stepauto( void ) ; void display( void ) ; UBYTE random( UBYTE ) ; void scramble( short ) ; short stringreq( UBYTE * , short ) ; void handlemsg( void ) ; void handlemenu( void ) ; void randrule( void ) ; void stoploop( void ) ; void editmode( void ) ; void main() { IntuitionBase = ( struct IntuitionBase * ) OpenLibrary( "intuition.library" , 33 ) ; if ( ! IntuitionBase ) cleanup() ; GfxBase = ( struct GfxBase * ) OpenLibrary( "graphics.library" , 33 ) ; if ( ! GfxBase ) cleanup() ; ns.Font = &stext ; screen = OpenScreen( &ns ) ; if ( ! screen ) cleanup() ; SetRGB4( &screen->ViewPort , 0 , 0 , 0 , 0 ) ; SetRGB4( &screen->ViewPort , 1 , 15 , 15 , 15 ) ; nw.Screen = screen ; window = OpenWindow( &nw ) ; if ( ! window ) cleanup() ; SetBPen( window->RPort , 0 ) ; SetAPen( window->RPort , 15 ) ; Move( window->RPort , 60 , 90 ) ; Text( window->RPort , "The Game of Life" , 16 ) ; Move( window->RPort , 60 , 102 ) ; Text( window->RPort , "by Gary Teachout" , 17 ) ; cells1 = AllocMem( 2 * SIZEX * SIZEY , MEMF_FAST | MEMF_CLEAR ) ; if ( ! cells1 ) cleanup() ; cells2 = cells1 + ( SIZEX * SIZEY ) ; menulist[ 0 ].FirstItem = &controlmenu[ 0 ].item ; controlmenu[ 0 ].item.ItemFill = ( APTR ) &controlmenu[ 0 ].text ; controlmenu[ 0 ].item.NextItem = &controlmenu[ 1 ].item ; controlmenu[ 1 ].item.ItemFill = ( APTR ) &controlmenu[ 1 ].text ; controlmenu[ 1 ].item.NextItem = &controlmenu[ 2 ].item ; controlmenu[ 2 ].item.ItemFill = ( APTR ) &controlmenu[ 2 ].text ; controlmenu[ 2 ].item.NextItem = &controlmenu[ 3 ].item ; controlmenu[ 3 ].item.ItemFill = ( APTR ) &controlmenu[ 3 ].text ; controlmenu[ 3 ].item.NextItem = &controlmenu[ 4 ].item ; controlmenu[ 4 ].item.ItemFill = ( APTR ) &controlmenu[ 4 ].text ; controlmenu[ 3 ].item.SubItem = &seedsub[ 0 ].item ; seedsub[ 0 ].item.ItemFill = ( APTR ) &seedsub[ 0 ].text ; seedsub[ 0 ].item.NextItem = &seedsub[ 1 ].item ; seedsub[ 1 ].item.ItemFill = ( APTR ) &seedsub[ 1 ].text ; seedsub[ 1 ].item.NextItem = &seedsub[ 2 ].item ; seedsub[ 2 ].item.ItemFill = ( APTR ) &seedsub[ 2 ].text ; menulist[ 1 ].FirstItem = &editmenu[ 0 ].item ; editmenu[ 0 ].item.ItemFill = ( APTR ) &editmenu[ 0 ].text ; editmenu[ 0 ].item.NextItem = &editmenu[ 1 ].item ; editmenu[ 1 ].item.ItemFill = ( APTR ) &editmenu[ 1 ].text ; editmenu[ 1 ].item.NextItem = &editmenu[ 2 ].item ; editmenu[ 2 ].item.ItemFill = ( APTR ) &editmenu[ 2 ].text ; editmenu[ 2 ].item.NextItem = &editmenu[ 3 ].item ; editmenu[ 3 ].item.ItemFill = ( APTR ) &editmenu[ 3 ].text ; SetMenuStrip( window , &menulist[ 0 ] ) ; SetWindowTitles( window , NULL , title[ 0 ] ) ; ShowTitle( screen , TRUE ) ; Delay( 100 ) ; old = cells1 ; new = cells2 ; scramble( 25 ) ; display() ; old = cells2 ; new = cells1 ; for ( ; ; ) { stepauto() ; display() ; if ( old == cells2 ) { old = cells1 ; new = cells2 ; } else { old = cells2 ; new = cells1 ; } } cleanup() ; } void cleanup() { if ( cells1 ) FreeMem( cells1 , 2 * SIZEX * SIZEY ) ; if ( window ) CloseWindow( window ) ; if ( screen ) CloseScreen( screen ) ; if ( GfxBase ) CloseLibrary( GfxBase ) ; if ( IntuitionBase ) CloseLibrary( IntuitionBase ) ; exit() ; } void stepauto() { short x , y ; UBYTE *oc , *n , *yp , *ym , *xp , *xm , *yy , *mm , *pm , *mp , *pp , t ; oc = old ; n = new ; yy = old ; for ( y = 0 ; y < SIZEY ; y ++ ) { yp = old + ( ( ( y + 1 ) % SIZEY ) * SIZEX ) ; ym = old + ( ( ( y + SIZEY - 1 ) % SIZEY ) * SIZEX ) ; xp = yy + 1 ; xm = yy + SIZEX - 1 ; mm = ym + SIZEX - 1 ; mp = yp + SIZEX - 1 ; pm = ym + 1 ; pp = yp + 1 ; t = *yp + *ym + *( xp ++ ) + *xm + *mm + *( pm ++ ) + *mp + *( pp ++ ) ; if ( *( oc ++ ) ) *( n ++ ) = ( ( t == 2 ) || ( t == 3 ) ) ? 1 : 0 ; else *( n ++ ) = ( t == 3 ) ? 1 : 0 ; mm = ym ; mp = yp ; yp ++ ; ym ++ ; xm = yy ; for ( x = 2 ; x < SIZEX ; x ++ ) { t = *( yp ++ ) + *( ym ++ ) + *( xp ++ ) + *( xm ++ ) + *( mm ++ ) + *( pm ++ ) + *( mp ++ ) + *( pp ++ ) ; if ( *( oc ++ ) ) *( n ++ ) = ( ( t == 2 ) || ( t == 3 ) ) ? 1 : 0 ; else *( n ++ ) = ( t == 3 ) ? 1 : 0 ; } xp = yy ; pm -= SIZEX ; pp -= SIZEX ; t = *yp + *ym + *xp + *xm + *mm + *pm + *mp + *pp ; if ( *( oc ++ ) ) *( n ++ ) = ( ( t == 2 ) || ( t == 3 ) ) ? 1 : 0 ; else *( n ++ ) = ( t == 3 ) ? 1 : 0 ; yy += SIZEX ; } } void display() { USHORT x , y , d , i , k , m , *wp , *wpc ; UBYTE *c ; do { reseed = 0 ; i = screen->BitMap.BytesPerRow >> 1 ; wp = ( USHORT * ) screen->BitMap.Planes[ 0 ] + ( 12 * i ) ; wpc = ( USHORT * ) screen->BitMap.Planes[ 0 ] + ( 13 * i ) ; c = new ; for ( y = 0 ; y < SIZEY ; y ++ ) { for ( x = 0 ; x < SIZEX ; x += 8 ) { d = 0 ; for ( m = 0xc000 , k = 0 ; k < 8 ; m = m >> 2 , k ++ ) { if ( *( c + k ) & 1 ) d |= m ; } *wp = d ; wp ++ ; *wpc = d ; wpc ++ ; c += 8 ; } wp += i ; wpc += i ; handlemsg() ; if ( reseed ) break ; } } while ( reseed ) ; } UBYTE random( a ) UBYTE a ; { #define RANDSHIFT 8 #define RANDTAB 23 #define RANDCOMP 8388608 static UBYTE fp = 1 ; static long v[ RANDTAB ] , rr ; short vi ; if ( fp ) { CurrentTime( &v[ 0 ] , &v[ 1 ] ) ; srand( v[ 1 ] ) ; for ( vi = 0 ; vi < RANDTAB ; vi ++ ) v[ vi ] = rand() >> RANDSHIFT ; rr = rand() >> RANDSHIFT ; fp = 0 ; } vi = RANDTAB * rr / RANDCOMP ; rr = v[ vi ] ; v[ vi ] = rand() >> RANDSHIFT ; return ( UBYTE ) ( ( a * rr ) / RANDCOMP ) ; } void scramble( s ) short s ; { short x , y ; for ( x = 0 ; x < ( SIZEX * SIZEY ) ; x ++ ) *( new + x ) = 0 ; for ( y = ( SIZEY - s ) >> 1 ; y < ( ( SIZEY + s ) >> 1 ) ; y ++ ) { for ( x = ( SIZEX - s ) >> 1 ; x < ( ( SIZEX + s ) >> 1 ) ; x ++ ) { *( new + x + ( y * SIZEX ) ) = random( 2 ) ; } } } void handlemsg() { while ( mes = GetMsg( window->UserPort ) ) { class = mes->Class ; code = mes->Code ; ReplyMsg( mes ) ; switch ( class ) { case MENUVERIFY : Wait( 1 << window->UserPort->mp_SigBit ) ; while ( class != MENUPICK ) { if ( mes = GetMsg( window->UserPort ) ) { class = mes->Class ; code = mes->Code ; ReplyMsg( mes ) ; } } case MENUPICK : handlemenu() ; break ; } } } void handlemenu() { if ( ! MENUNUM( code ) ) { switch ( ITEMNUM( code ) ) { case 0 : stoploop() ; break ; case 1 : stopflag = 0 ; break ; case 2 : editmode() ; break ; case 3 : switch ( SUBNUM( code ) ) { case 0 : scramble( 5 ) ; break ; case 1 : scramble( 25 ) ; break ; case 2 : scramble( 80 ) ; break ; } reseed = 1 ; break ; case 4 : /* quit */ cleanup() ; break ; } } } void stoploop() { if ( ! stopflag ) { stopflag = 1 ; while ( stopflag ) { Wait( 1 << window->UserPort->mp_SigBit ) ; handlemsg() ; } } } void editmode() { UBYTE live = 1 ; short x , y , ox , oy , mx , my ; SetWindowTitles( window , NULL , title[ 1 ] ) ; ClearMenuStrip( window ) ; display() ; editmenu[ 0 ].item.Flags = editmenu[ 0 ].item.Flags | CHECKED ; editmenu[ 1 ].item.Flags = editmenu[ 1 ].item.Flags & ( ~ CHECKED ) ; SetMenuStrip( window , &menulist[ 1 ] ) ; SetPointer( window , pointer , 7 , 7 , -1 , 0 ) ; stopflag = 0 ; reseed = 0 ; while( ! reseed ) { Wait( 1 << window->UserPort->mp_SigBit ) ; while ( mes = GetMsg( window->UserPort ) ) { class = mes->Class ; code = mes->Code ; ReplyMsg( mes ) ; switch ( class ) { case MENUVERIFY : Wait( 1 << window->UserPort->mp_SigBit ) ; while ( class != MENUPICK ) { if ( mes = GetMsg( window->UserPort ) ) { class = mes->Class ; code = mes->Code ; ReplyMsg( mes ) ; } } case MENUPICK : switch ( ITEMNUM( code ) ) { case 0 : live = 1 ; break ; case 1 : live = 0 ; break ; case 2 : for ( y = 0 ; y < ( SIZEY * SIZEX ) ; y ++ ) *( new + y ) = 0 ; SetRast( window->RPort , 0 ) ; break ; case 3 : reseed = 1 ; break ; } break ; case MOUSEBUTTONS : if ( code == SELECTDOWN ) { ox = oy = -1 ; while ( code != SELECTUP ) { mx = window->MouseX & 0xfffe ; my = window->MouseY & 0xfffe ; x = mx >> 1 ; y = ( my >> 1 ) - 6 ; if ( ( ( x != ox ) || ( y != oy ) ) && ( y >= 0 ) ) { *( new + x + ( y * SIZEX ) ) = live ; if ( live ) SetAPen( window->RPort , 1 ) ; else SetAPen( window->RPort , 0 ) ; WritePixel( window->RPort , mx , my ) ; WritePixel( window->RPort , mx + 1 , my ) ; WritePixel( window->RPort , mx , my + 1 ) ; WritePixel( window->RPort , mx + 1 , my + 1 ) ; ox = x ; oy = y ; } while ( mes = GetMsg( window->UserPort ) ) { if ( mes->Class == MOUSEBUTTONS ) code = mes->Code ; ReplyMsg( mes ) ; } } } break ; } } } ClearPointer( window ) ; ClearMenuStrip( window ) ; SetMenuStrip( window , &menulist[ 0 ] ) ; SetWindowTitles( window , NULL , title[ 0 ] ) ; }