home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 108.lha / Life / Sources / life.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-20  |  23.8 KB  |  856 lines

  1. /* :ts=2 */
  2. /*
  3. :.,/^}/s/;/;/g
  4.  */
  5. #include "include/debug.h"
  6. /*   LIFE.  Original Life program, with blit funcition and 10-blit
  7.  *   Life algorithm by Tomas Rokicki.
  8.  *   User interface by David Storer,  Cedar Rapids, Iowa.
  9.  *                     (Compuserve ID 71420,2672)
  10.  *   February, 1988.
  11.  *   Compiled with Manx Aztec C, 3.4a
  12.  */
  13. #include "life.h"
  14. #include "structures.h"
  15. #include "getfile.h"
  16. short *a, *b, *c, *d, *e, *t1=NULL, *t2=NULL, *t3=NULL, *t4=NULL, *t5=NULL ;
  17. short noplanes ;
  18. short running = FALSE ;              /* loop control flag */
  19. short singlestep = FALSE ;           /* single step control flag */
  20. short tilemode = FALSE ;        /* tile mode flag when name starts w/ '*' */ 
  21. short startpat, rr;
  22. struct GfxBase *GfxBase = NULL ;     /* the GfxBase */
  23. struct IntuitionBase *IntuitionBase = NULL ; /* the IntuitionBase */
  24.  
  25. struct IntuiMessage *message ;
  26. struct IntuiMessage messagecopy ;
  27. struct Screen *myscreen = NULL ;
  28. struct Window *mywin = NULL ;
  29. struct RastPort *rp = NULL ;
  30. struct ViewPort *vp = NULL ;
  31.  
  32. struct NewScreen mynewscreen = {
  33.    0,                                         /* left edge */
  34.    0,                                         /* top edge */
  35.    320,                                       /* width */
  36.    200,                                       /* height */
  37.    4,                                         /* depth */
  38.    1,                                         /* detail pen */
  39.    2,                                         /* block pen */
  40.    0,                                         /* screen mode */
  41.    CUSTOMSCREEN,                              /* type */
  42.    NULL,                                      /* use default font */
  43.    (UBYTE *)"LIFE by Tomas Rokicki & DWS",    /* title */
  44.    NULL,                                      /* initialize this gadget field */
  45.    NULL } ;                                   /* no bitmap supplied */
  46.  
  47. struct NewWindow mynewwin = {
  48.         0,                /* Left */
  49.         0,                /* Top */
  50.         HSIZE,        /* Width */
  51.         VSIZE+10,    /* Height */
  52.         1,                /* DPen */
  53.       2,                /* BPen */
  54.       MOUSEBUTTONS|    /* IDCMP */
  55.         VANILLAKEY  |
  56.       CLOSEWINDOW,
  57.  
  58.  /* BACKDROP   |  */
  59.         BORDERLESS |
  60.     ACTIVATE   |    
  61.         RMBTRAP    |
  62.         WINDOWCLOSE,    /* Flags */
  63.  
  64.         0,                /* Gadgets */
  65.         0,                /* Check */
  66.         (UBYTE *)"Life by Rokicki & Storer",        /* Title */
  67.         0,                /* Screen */
  68.         0,                /* Bitmap */
  69.         0,                /* MinWidth */
  70.         0,                /* MinHeight */
  71.         0,                /* MaxWidth */
  72.         0,                /* MaxHeight */
  73.         CUSTOMSCREEN    /* Screen type */
  74. };
  75.  
  76. UWORD colors[16] = {
  77.                      0x011c,     /*  0 0000         */
  78.                      0x0fff,     /*  1 0001         */
  79.                      0x011c,     /*  2 0010         */
  80.                      0x0fff,     /*  3 0011         */
  81.                      0x011c,     /*  4 0100         */
  82.                      0x0fff,     /*  5 0101         */
  83.                      0x011c,     /*  6 0110         */
  84.                      0x0fff,     /*  7 0111         */
  85.                      0x077a,     /*  8 1000         */
  86.                      0x0fff,     /*  9 1001         */
  87.                      0x077a,     /* 10 1010         */
  88.                      0x0fff,     /* 11 1011         */
  89.                      0x077a,     /* 12 1100         */
  90.                      0x0fff,     /* 13 1101         */
  91.                      0x077a,     /* 14 1110         */
  92.                      0x0fff };   /* 15 1111         */
  93. struct    spriteimage {        /* for defining a variable cursor */ 
  94.   UWORD posctl[2];
  95.   UWORD sprdata[32];
  96.   UWORD reserved[2];
  97. };
  98. struct spriteimage *ptr ;  /* pointer to new mouse pointer image data */
  99.  
  100. struct colonycursor {
  101.     UWORD cldata[16];
  102. };
  103. struct colonycursor *ptr2;  /* pointer to DrawImage version of colony  */
  104.  
  105. struct colonydata {
  106.     UBYTE cldata[16][16];
  107. };
  108.  
  109. struct colony {
  110.   char   keyassign;
  111.     USHORT width, height;
  112.     UBYTE  cldata[16][16];
  113. };
  114. #define MAXCOLONY 100
  115. /* The form in slot 0 is for setting up the background grid. */
  116. struct colony form[MAXCOLONY]  = {{'\0', 10, 10, { {1,1,0,0,0,1,0,0,0,0},
  117.                                                    {1,0,0,0,0,0,0,0,0,0},
  118.                                                    {0,0,0,0,0,0,0,0,0,0},
  119.                                                    {0,0,0,0,0,0,0,0,0,0},
  120.                                                    {0,0,0,0,0,0,0,0,0,0},
  121.                                                    {1,0,0,0,0,1,0,0,0,0},
  122.                                                    {0,0,0,0,0,0,0,0,0,0},
  123.                                                    {0,0,0,0,0,0,0,0,0,0},
  124.                                                    {0,0,0,0,0,0,0,0,0,0},
  125.                                                    {0,0,0,0,0,0,0,0,0,0}}}};
  126. short   erasemode = FALSE ;
  127. #define MAXNAME 19
  128. char names[MAXCOLONY][MAXNAME+1];  /* Here's a name for a pre-inited pat.*/
  129.                                    /*  = { "1-dot Eraser" } ;  */
  130.  
  131. char *name[MAXCOLONY];
  132. int  lastcolony ;
  133. char wintitle[40];
  134.  
  135. int         current = 1 ;        /* index to current form data */
  136. int     oldcurr ;       /* holds old value of current during erasemode */
  137.  
  138. struct Image cursorimage = {
  139.     0, 10,        /* LeftEdge, TopEdge     */
  140.     0, 0,     /* Width, Height (set before use by DrawImage)    */
  141.     1,                /* Depth                */
  142.   NULL,     /* *ImageData   assigned later */
  143.     1,                /* PlanePick             */
  144.     0,                /* PlaneOnOff            */
  145.     NULL          /* *NextImage            */
  146. };
  147.  
  148. struct Image       *ptr3;  /* pointer to new cursorimage */
  149.  
  150. int     rotmir  = 0 ;   /* current state of rotation-mirror fn */
  151.  
  152.   /* present rotmir = 0  1  2  3  4  5  6  7  */
  153.     /*    after   */
  154. UBYTE   rot90r[8] = { 3, 2, 7, 6, 1, 0, 5, 4 };   /* new rotmir */
  155. /*YTE   rot90r[8] = { 5, 2, 7, 0, 1, 6, 3, 4 };   /* new rotmir */
  156. UBYTE   mirva[8]  = { 2, 5, 0, 7, 6, 1, 4, 3 };   
  157.  
  158.  
  159. int     ireverse, jreverse; /* used to cause subscripts to run hi to low */
  160. int     imax, jmax ;        /* set from either height or width of current */
  161.                             /* form, depending on bit 0 of rotmir */
  162. printhelp()
  163. {
  164.   int i ;
  165.     char ctrl[4];
  166.  
  167.   printf("\14");  /* form feed to clear screen */
  168.     printf("Mouse Buttons:  ");
  169.     printf(
  170.     "    Left -- Place colony on display.  Right -- Rotate cursor.\n");
  171.     printf("Keyboard controls:");
  172.     printf(
  173.     "  DEL --  Back up one generation, if Depth is 2 or 3.\n");
  174.     printf(
  175.     "  Spacebar -- start/stop.           Backspace -- single generation.\n");
  176.     printf(
  177.     "  Return, Tab -- Reverse cursor.    ESC  -- End program.\n");
  178.     printf("Keypad controls:  ");
  179.     printf("RightShift-zero: Clear display.         '6' -- Random.\n");
  180.     printf(
  181.     "  Enter: Read/Save pattern on disk. '-' -- Erase mode.");
  182.     printf("    '.' -- Tile mode.\n");
  183.     printf(
  184.     "  '1', '2', '3' -- Set Depth.       '4' -- Refresh Grid.");
  185.     printf("  '5' -- Remove Grid.\n");
  186.     printf(
  187.     "  '7' -- Quick restore.             '8' -- Quick save.\n");
  188.     printf("Key assignments from file 'LIFE.KEY'.  ");
  189.     printf("Use keys to change cursor.\n");
  190.  
  191.     for ( i = 1; i < lastcolony; i++) {
  192.       if ( form[i].keyassign < ' ') {
  193.        ctrl[0] = '\'';
  194.        ctrl[1] = '^';
  195.              ctrl[2] = form[i].keyassign + '@';
  196.              ctrl[3] = '\0';
  197.         }
  198.         else {
  199.        ctrl[0] = ' ';
  200.        ctrl[1] = '\'';
  201.              ctrl[2] = form[i].keyassign;
  202.              ctrl[3] = '\0';
  203.         }
  204.     printf(" %s'=%-19s", ctrl, name[i] );
  205.       if ( i % 3 == 0)  printf("\n");
  206.   }
  207.     if (i % 3 != 1) printf("\n");
  208. } /* printhelp */
  209.  
  210. printheader()
  211. {
  212.   printf("\14\n\n\n\n\n\n\n\n");  /* form feed to clear screen */
  213.     printf("                             LIFE\n\n\n");
  214.     printf("                 Blit algorithm by Tomas Rokicki.\n");
  215.     printf("                 Interaction by David Storer.\n");
  216.     printf("\n\n\n\n\n");
  217.     printf(
  218.     "Use <left-Amiga-n and -m> to switch between Life display and Help.\n");
  219.     printf("Press RETURN key to begin.") ;
  220.     getchar(); /* Wait for user to acknowledge. */
  221. } /* printheader */
  222. /*
  223.  *   This routine takes present value of rotmir and from its bit pattern
  224.  *   determines the settings for imax, jmax, and ireverse, jreverse.
  225.  */
  226. next(cur)
  227. int cur;   /* current form slot */
  228. {
  229. #define ICTL 4
  230. #define JCTL 2
  231. #define MIR  1
  232.  
  233.   if ( rotmir & MIR ) {             /* determine if rotation has reversed */
  234.       imax = form[cur].width;     /* role of width and height */
  235.         jmax = form[cur].height;
  236.   }
  237.     else {
  238.       imax = form[cur].height;
  239.         jmax = form[cur].width;
  240.     }
  241.  
  242.     ireverse = ( rotmir & ICTL ) ?  imax-1  :  0 ;
  243.     jreverse = ( rotmir & JCTL ) ?  jmax-1  :  0 ;
  244.     /**debug*?
  245.     printf("curr=%d, imax=%d, jmax=%d, irev=%d, jrev=%d, rotmir=%d \n",
  246.             cur, imax,    jmax,    ireverse,jreverse,rotmir);
  247.   /**gubed */
  248. } /* next */
  249.  
  250. /*
  251.  *   getcolonies reads in the definitions of the colonies from the 
  252.  *   file LIFE.KEY in the current directory.  The subscript of the last
  253.  *   colony read is returned in lastcolony.
  254.  */ 
  255. getcolonies()
  256. {
  257. FILE   *fp ;
  258. int w, h, col ;
  259. int temp ;
  260. int i, j ;
  261. char key[2];
  262.  
  263.   for( i = 0; i < MAXCOLONY; i++) {
  264.        name[i] = &names[i][0];
  265.     };
  266.  
  267.   if( NULL == (fp = fopen("LIFE.KEY", "r") ))
  268.     cleanup("Can't open LIFE.KEY for input.");
  269.  
  270.     for(col = 1; col < MAXCOLONY; col++) {
  271.       if(EOF == fscanf(fp, "%20[~#]#", name[col] ) )
  272.           break;
  273.         if( 3 != fscanf(fp, "%1s%d%d", key, &w, &h) ) {
  274.           printf("Malformed LIFE.KEY input, Colony %d\n", col);
  275.             fclose(fp);
  276.             cleanup("Input terminated.");
  277.         };
  278.         form[col].keyassign = key[0];
  279.         if( (w > 16) || (w < 0) || (h > 16) || (h < 0) ) {
  280.           printf("Width and Height must be in range 1 to 16.");
  281.             fclose(fp);
  282.             cleanup("Input terminated.");
  283.         };
  284.         for (i = 0; i < h; i++) {
  285.           for (j = 0; j < w; j++) {
  286.               if( 1 != fscanf(fp, "%d", &temp) ) {
  287.                       printf("Malformed LIFE.KEY data, Colony %d cell %d,%d\n",
  288.                                                                 col,     i, j);
  289.                         fclose(fp);
  290.                         cleanup("Input terminated.");
  291.                 };
  292.                 form[col].cldata[i][j] = temp;
  293.             }
  294.         }
  295.         form[col].width = w;
  296.         form[col].height = h;
  297.     } /* outer for */
  298.     lastcolony = col;
  299.     fclose(fp);
  300. } /* getcolonies */
  301.  
  302. /* 
  303.  *   setcurr function converts a key value to a current form number 
  304.  */
  305. int setcurr(key)
  306. char key;
  307. {
  308.   int i, found;
  309.     found = FALSE ;
  310.     for( i = 0; i < lastcolony; i++)
  311.       if ( key == form[i].keyassign ) { 
  312.           found = TRUE ;
  313.             break ;
  314.         };
  315.     if( !found)
  316.       DisplayBeep(myscreen);
  317.     return( found ? i : -1);
  318. } /* setcur */
  319.  
  320. /*
  321.  *   This routine gets a raster for temporary storage.
  322.  */
  323. short *myalloc() 
  324. {
  325.    void *AllocMem() ;
  326.    void *p ;
  327.  
  328.    if ((p=AllocMem(2L*RASTSIZE, MEMF_CHIP | MEMF_CLEAR))==NULL) {
  329.       cleanup("Could not allocate raster data\n") ;
  330.    }
  331.    return(p);
  332. } /* myalloc */
  333.  
  334. #define ABS(a) ( (a>0) ? (a) : (-(a)) )
  335. setcolony(cur)
  336. int    cur;
  337. { UWORD row, bitmask;
  338.   int   i, j, k;
  339.   long  xoff, yoff ;
  340.  
  341.     next(cur);
  342.     for( k = 0, i = 0; i < imax; k++, i++) {
  343.       row = 0;
  344.         bitmask = 0x8000;
  345.       for( j = 0; j < jmax; j++) {
  346.           if ( rotmir & MIR )
  347.               row |= ( form[cur].cldata[ABS(j - jreverse)][ABS(i - ireverse)] ) ?
  348.                bitmask : 0 ;
  349.             else
  350.               row |= ( form[cur].cldata[ABS(i - ireverse)][ABS(j - jreverse)] ) ?
  351.                bitmask : 0 ;
  352.             bitmask >>= 1;
  353.             } /* inner for */
  354.           ptr2 -> cldata[k] = row; 
  355.  
  356.             /* The data needed for SetPointer is in a different format from that */
  357.             /* needed for DrawImage.  Here we take the DrawImage format and copy */
  358.             /* the relevant part to the memory allocated for the pointer image.  */
  359.             ptr -> sprdata[2 + k * 2] = row;
  360.  
  361.         }; /* outer for */
  362.         
  363.         xoff = yoff = -1L;
  364.         SetPointer(mywin, ptr, (long)(imax + 1),
  365.                                   (long)jmax,
  366.                                                  xoff,  /* x-offset */
  367.                                                         yoff); /* y-offset */
  368. } /* setcolony */
  369.  
  370. /* drawgrid sets up a tickmark every eighth pixel vert. & horiz. in     */
  371. /* in bitplane 4.  The color table set set so that any dead cells will */
  372. /* show either blue (background) or gridtick in blue-grey */
  373. drawgrid()
  374. {
  375.     register int x, y ;
  376.     for (y=0; y<VSIZE; y+=8)
  377.       for ( x=0; x<HWORDS; x++)
  378.         d[y*HWORDS+x] = 0x8080;
  379. } /*drawgrid */
  380.  
  381. /*
  382.  *   Here we set things up.
  383.  */
  384. initialize() 
  385. {
  386.    int cc;
  387.    int i;
  388.    void *AllocMem() ;
  389.  
  390.    initblitdata() ;
  391.    if ((IntuitionBase =
  392.                (struct IntuitionBase *)OpenLibrary("intuition.library",0L))==NULL ||
  393.        (GfxBase = 
  394.               (struct GfxBase *)OpenLibrary("graphics.library",0L)) ==NULL) {
  395.       cleanup("Couldn't open libraries.") ;
  396.    };
  397.  
  398.    if ((myscreen = (struct Screen *)OpenScreen(&mynewscreen))==NULL) {
  399.       cleanup("Couldn't open screen.") ;
  400.    };
  401.  
  402.    a = ((short *)(myscreen->BitMap.Planes[0])) + 200;
  403.    b = ((short *)(myscreen->BitMap.Planes[1])) + 200;
  404.    c = ((short *)(myscreen->BitMap.Planes[2])) + 200;
  405.    d = ((short *)(myscreen->BitMap.Planes[3])) + 200;
  406.    /* e = ((short *)(myscreen->BitMap.Planes[4])) + 200; */
  407.      e  = myalloc() ;       /* temp space for saving gen zero. */
  408.    t1 = myalloc() ;                /* temporary space for blitter Life Algorithm */
  409.    t2 = myalloc() ;                /* The fact that there are five temps is related*/
  410.    t3 = myalloc() ;                /* to the algorithm, not the number of bit planes*/
  411.    t4 = myalloc() ;
  412.    t5 = myalloc() ;
  413.  
  414.         mynewwin.Screen = myscreen;
  415.  
  416.         if ((mywin = (struct Window *)OpenWindow(&mynewwin)) == NULL)
  417.            cleanup("Can't open window");
  418.  
  419.         rp = mywin->RPort;
  420.         vp = &myscreen->ViewPort;
  421.     
  422.     if ((ptr=AllocMem(128L, MEMF_CHIP | MEMF_CLEAR))==NULL) 
  423.         cleanup("Could not allocate pointer data\n") ;
  424.  
  425.       if ((ptr2 = AllocMem(128L, MEMF_CHIP | MEMF_CLEAR))==NULL) 
  426.         cleanup("Could not allocate cursor data\n") ;
  427.  
  428.     if ((ptr3 = AllocMem(128L, MEMF_CHIP | MEMF_CLEAR))==NULL) 
  429.         cleanup("Could not allocate cursor image data\n") ;
  430.        
  431.         LoadRGB4(vp, colors, 16L);
  432.       *ptr3 = cursorimage;
  433.       ptr3->ImageData = (USHORT *)ptr2;
  434.         
  435.         rotmir = 0;
  436.         drawgrid();
  437.       current = oldcurr = 1;  /* start with form[1] */ 
  438.         setcolony(current);
  439.  
  440.  
  441.          /**DEBUG**?
  442.        printf("ptr2=%lx, ptr3=%lx\n", ptr2, ptr3);
  443.        printf("Formimage: TopEdge=%x, LeftEdge=%x\n", ptr3->TopEdge,
  444.                                                       ptr3->LeftEdge);
  445.        printf("Width=%x, Height=%x\n", ptr3->Width,
  446.                                        ptr3->Height);
  447.        printf("ImageData=%lx\n", ptr3->ImageData);
  448.        printf("End of initialize\n");
  449.          cc = getchar();     
  450.          if (cc== 'q' || cc == 'Q') cleanup("Abort");
  451.          /**DEBUG**/
  452. } /* initialize */
  453.  
  454.     /*
  455.      *   Exit routine.
  456.      */
  457. cleanup(s)
  458.   char *s;
  459. {
  460.    if (mywin)         { ClearPointer(mywin);          CloseWindow(mywin) ;
  461.                                                         mywin = NULL ;        }
  462.    if (myscreen)            { CloseScreen(myscreen) ;              myscreen = NULL ;     }
  463.    if (IntuitionBase) { CloseLibrary(IntuitionBase) ; IntuitionBase = NULL ;}
  464.    if (GfxBase)       { CloseLibrary(GfxBase) ;             GfxBase = NULL ;            }
  465.    if (ptr)                      { FreeMem(ptr, 128L);                        ptr = NULL ;                    }
  466.    if (ptr2)                     { FreeMem(ptr2, 128L);                    ptr2 = NULL ;                  }
  467.    if (ptr3)                    { FreeMem(ptr3, 128L);                    ptr3 = NULL ;         }
  468.    if (e)                         { FreeMem(e,  2L*RASTSIZE) ;        e  = NULL;                        }
  469.    if (t1)                         { FreeMem(t1, 2L*RASTSIZE) ;        t1 = NULL;                        }
  470.      if (t2)                         { FreeMem(t2, 2L*RASTSIZE) ;        t2 = NULL;                        }
  471.      if (t3)                         { FreeMem(t3, 2L*RASTSIZE) ;        t3 = NULL;                        }
  472.    if (t4)                         { FreeMem(t4, 2L*RASTSIZE) ;        t4 = NULL;                        }
  473.    if (t5)                         { FreeMem(t5, 2L*RASTSIZE) ;        t5 = NULL;                        }
  474.    printf("%s\n",s);
  475.    exit(0) ;
  476. }
  477.  
  478. #define PARITY (0x96)
  479. #define CARRY (0xe8)
  480. #define PARITY2 (0x3c)
  481. #define CARRY2 (0xc0)
  482. #define SPECIAL1 (0x12)
  483. #define SPECIAL2 (0xe0)
  484. #define COPY (0xf0)
  485. /*
  486.  *   Does one LIFE generation.  Fancy algorithm uses only 10 blits.  If
  487.  *   anyone can improve this, please let me know.
  488.  */
  489. dogeneration() 
  490. {
  491.    OwnBlitter() ;
  492. /*
  493.  *   Take horizontal sums.
  494.  */
  495.    blit(a, 0, 1,
  496.         a, 2, 1,
  497.         a, 1, 1,
  498.         t1, 1, 1,
  499.              MODULO, HSIZE-2, VSIZE-2, PARITY) ;
  500.    blit(a, 0, 1,
  501.         a, 2, 1,
  502.         a, 1, 1,
  503.         t2, 1, 1,
  504.              MODULO, HSIZE-2, VSIZE-2, CARRY) ;
  505. /*
  506.  *   Take sums for middle row.
  507.  */
  508.    blit(a, 0, 1, 
  509.         a, 2, 1,
  510.         a, 1, 1,
  511.         t3, 1, 1,
  512.              MODULO, HSIZE-2, VSIZE-2, PARITY2) ;
  513.    blit(a, 0, 1, 
  514.         a, 2, 1,
  515.         a, 1, 1,
  516.         t4, 1, 1,
  517.              MODULO, HSIZE-2, VSIZE-2, CARRY2) ;
  518. /*
  519.  *   Now, sum each of the three columns.
  520.  */
  521.    blit(t1, 1, 0,
  522.         t1, 1, 2,
  523.         t3, 1, 1,
  524.         t5, 1, 1,
  525.              MODULO, HSIZE-2, VSIZE-2, PARITY) ;
  526.    blit(t1, 1, 0,
  527.         t1, 1, 2,
  528.         t3, 1, 1,
  529.         t3, 1, 1,
  530.              MODULO, HSIZE-2, VSIZE-2, CARRY) ;
  531.    blit(t2, 1, 0,
  532.         t2, 1, 2,
  533.              t4, 1, 1,
  534.         t1, 1, 1,
  535.              MODULO, HSIZE-2, VSIZE-2, PARITY) ;
  536.    blit(t2, 1, 0,
  537.         t2, 1, 2,
  538.         t4, 1, 1,
  539.         t4, 1, 1,
  540.              MODULO, HSIZE-2, VSIZE-2, CARRY) ;
  541. /*
  542.  *   Now, check high two order bits, then combine with original and
  543.  *   low order bit.
  544.  */
  545.    blit(t1, 1, 1,
  546.         t4, 1, 1,
  547.         t3, 1, 1,
  548.         t2, 1, 1,
  549.              MODULO, HSIZE-2, VSIZE-2, SPECIAL1) ;
  550. /*
  551.  *   Before we do the final write, we copy bits down one generation.
  552.  */
  553.    switch (noplanes) {
  554. case 5:
  555.    blit(d, 1, 1,
  556.         d, 1, 1, 
  557.         d, 1, 1, 
  558.         e, 1, 1,
  559.              MODULO, HSIZE-2, VSIZE-2, COPY) ;
  560. case 4:
  561.    blit(c, 1, 1,
  562.         c, 1, 1,
  563.         c, 1, 1,
  564.         d, 1, 1,
  565.              MODULO, HSIZE-2, VSIZE-2, COPY) ;
  566. case 3:
  567.    blit(b, 1, 1,
  568.         b, 1, 1, 
  569.         b, 1, 1, 
  570.         c, 1, 1,
  571.              MODULO, HSIZE-2, VSIZE-2, COPY) ;
  572. case 2:
  573.    blit(a, 1, 1,
  574.         a, 1, 1,
  575.         a, 1, 1,
  576.         b, 1, 1,
  577.              MODULO, HSIZE-2, VSIZE-2, COPY) ;
  578. default: ;
  579. }
  580.    blit(t2, 1, 1,
  581.         t5, 1, 1,
  582.         a, 1, 1, 
  583.         a, 1, 1,
  584.              MODULO, HSIZE-2, VSIZE-2, SPECIAL2) ;
  585.    DisownBlitter() ;
  586. }
  587. /*
  588.  *   Random number generator; probably not a very good one.
  589.  */
  590. int rnd(i)
  591. int i ;
  592. {
  593.    static long seed = 323214521 ;
  594.    long rval ;
  595.  
  596.    seed = seed * 123213 + 121 ;
  597.    rval = (seed >> 5) & 65535 ;
  598.    return ((i * rval) >> 16) ;
  599. }
  600.  
  601. randompat()
  602. {
  603.     register int x, y, i;
  604.  
  605.         BltClear(a, 2L * RASTSIZE, 0);
  606.  
  607.         for (i=0; i<10000; i++) {
  608.                 x = rnd(HSIZE-4) + 2;
  609.                 y = rnd(VSIZE-4) + 2;
  610.                 a[y*HWORDS+(x>>4)] |= 1 << (15 - (x & 15)) ;
  611.                 }
  612. } /* randompat */
  613.  
  614.  
  615. previousgen()
  616. {
  617.     if ( noplanes > 1)     /* move previous generation back to 'a' raster */
  618.     blit(b, 1, 1,
  619.          b, 1, 1,
  620.          b, 1, 1,
  621.          a, 1, 1,
  622.               MODULO, HSIZE-2, VSIZE-2, COPY) ;
  623.     if ( noplanes > 2)     /* if 3 gens kept, move third back to second  */
  624.     blit(c, 1, 1,
  625.          c, 1, 1,
  626.          c, 1, 1,
  627.          b, 1, 1,
  628.               MODULO, HSIZE-2, VSIZE-2, COPY) ;
  629.  
  630. } /* previousgen */
  631.  
  632. changetitle(runflag, eraseflag, tileflag, gen)
  633.  short  runflag, eraseflag, tileflag ;
  634.  short  gen;
  635. {
  636.   int t ;
  637.   static char *title[] = {"Stop, Space to start.                    ",
  638.                           "Run,  Space to stop",
  639.                                                     "Tile mode.                               ",
  640.                                                     "Erase mode.  Keypad '-' exits"};
  641.     static char *temp = "            ";
  642.  
  643.     if (tileflag) {
  644.       title[2][12] = '\0';
  645.         strcat(title[2], name[current]);
  646.       t = 2;
  647.     }
  648.     else if (eraseflag)
  649.         t = 3;
  650.     else
  651.       t = (runflag) ? 1 : 0 ;
  652.     if (!runflag) {
  653.       title[0][22] = '\0';
  654.         sprintf(temp, "Gen. %d", gen);
  655.         strcat(title[0], temp);
  656.     }
  657.     SetWindowTitles(mywin, title[t], -1L);
  658. } /* changetitle */
  659.  
  660. domessage(x, y, gen) 
  661.   int x, y, gen;
  662. {
  663. #define KEYPAD (0x0100)   /* Qual bit set if key is on keypad */ 
  664. #define RTSHIFT (0x0002)   /* Qual bit set if right shift key down */
  665.     register int i, j ;
  666.     char key ;
  667.   int found;
  668.     BOOL keypad;        /* true if vanillakey was from keypad */
  669.  
  670.     switch(messagecopy.Class)
  671.     {
  672.         case MOUSEBUTTONS:
  673.             if (messagecopy.Code == SELECTDOWN )
  674.             {
  675.           ptr3->Width  = jmax;
  676.                 ptr3->Height = imax;
  677.                 ptr3 -> PlanePick = !erasemode;
  678.                 if (tilemode) {
  679.                     BltClear(a, 2L * RASTSIZE, 0);
  680.                   for( i = imax+2; i < VSIZE-imax-2; i+=imax)
  681.                       for( j = jmax+2; j < HSIZE-jmax-2; j+=jmax)
  682.                             DrawImage(rp, ptr3, (long)j, (long)i);
  683.                     tilemode = FALSE;
  684.                     movmem(a, e, 2*RASTSIZE);    /* save it.*/
  685.                     gen = 0;
  686.                     drawgrid();                /* redraw the grid. */
  687.                     changetitle(running, erasemode, tilemode, gen);
  688.                 }
  689.                 else
  690.                   {
  691.                   DrawImage(rp, ptr3, (long)x, (long)y);
  692.                     }
  693.             }
  694.             else if (messagecopy.Code == MENUDOWN )
  695.                 {
  696.                   rotmir = rot90r[rotmir] ; /* rotate 90 deg to right */
  697.               setcolony(current);
  698.                 }
  699.             break;
  700.         case VANILLAKEY:
  701.         key = (char) messagecopy.Code ;
  702.             keypad = (messagecopy.Qualifier & KEYPAD);
  703.             if (keypad) 
  704.               switch(key) {
  705.                   case '\r':    /* Enter key on keypad allows file input or output */
  706.                         if (dofile(myscreen, mywin, a)) /* solicit a file name and */
  707.                           gen = 0;                      /* read or write it */
  708.                             movmem(a, e, 2*RASTSIZE);    /* reset gen if read */
  709.                         break;
  710.                     case '0' :   /* Keypad zero plus right shift key erases display */
  711.                       if (messagecopy.Qualifier & RTSHIFT) {
  712.                         BltClear(a, 2L * RASTSIZE, 0);
  713.                           gen = 0 ;
  714.                         }
  715.                        break ;
  716.                     case '-':         /* Keypad '-' toggles erase mode */
  717.                         erasemode = !erasemode;
  718.                         tilemode = FALSE;     /* force to NOT tilemode */
  719.                         break;
  720.                     case '.' :   /* Keypad '.' toggles Tile Mode */
  721.                       tilemode = !tilemode;
  722.                         erasemode = FALSE;     /* force to NOT erasemode */
  723.                         break;
  724.                     case '1':
  725.                     case '2':
  726.                     case '3':
  727.                       noplanes = key - '0';
  728.                         break;
  729.                     case '4':    /* refresh grid */
  730.                       drawgrid();
  731.                         break;
  732.                     case '5':   /* erase grid */
  733.                         BltClear(d, 2L * RASTSIZE, 0);
  734.                       break;
  735.                     case '6':   /* generate random pattern */
  736.                       randompat();
  737.                         movmem(a, e, 2*RASTSIZE);    /* save it.*/
  738.                         gen = 0;
  739.                         break;
  740.                     case '7':
  741.                       movmem(e, a, 2*RASTSIZE);    /* restore it */
  742.                         gen = 0;
  743.                         break;
  744.                     case '9':
  745.                       movmem(a, e, 2*RASTSIZE);    /* save it */
  746.                         break;
  747.                     default:
  748.                         ;
  749.                 }
  750.             else /* not keypad */
  751.             switch(key) {
  752.               case '\r':            /* Return key does the mirror */
  753.                 case '\t':          /* Tab key also */
  754.                     rotmir = mirva[rotmir];  /* Do mirror about vert axis */
  755.                     break;
  756.               case ' ':       /* space-bar starts and stops */
  757.                     running = !running ;  /* toggle run mode */
  758.                     singlestep = FALSE ;
  759.                   break ;
  760.               case '\b':      /* back space single steps the display */
  761.                     running = TRUE ;         /* force run mode */
  762.             singlestep = TRUE ;      /* for one generation */
  763.                   break ;
  764.                 case '\177':    /* DEL key backs up, if possible to prev gen. */
  765.                     previousgen();
  766.                     gen--;
  767.                   break;
  768.                 case '\33':      /* Escape terminates program */
  769.                   cleanup("");
  770.               default : 
  771.                   found = setcurr( key );  /* set up for colony defined by 'key' */
  772.                     if (found != -1) {
  773.                         current = found;
  774.                         rotmir = 0;
  775.                     }
  776.             } /* switch */
  777.             
  778.             /* set title according to mode */
  779.           changetitle(running, erasemode, tilemode, gen); 
  780.         setcolony(current);
  781.             break;
  782.         case CLOSEWINDOW:
  783.                 cleanup("") ;
  784.         default:
  785.             ;
  786.     }; /* switch */
  787.     return(gen) ;
  788. } /* domessage */
  789.  
  790.  
  791. /*
  792.  *   Main routine.
  793.  */
  794. main ()
  795. {
  796.     int cc;
  797.     register int i ;
  798.     register int gen ; 
  799.     register int x, y ;
  800.  
  801.     printheader();
  802.     getcolonies();
  803.   initialize() ;
  804.   printhelp();     
  805.  
  806.   gen = 0 ;        /* generation counter */
  807.   noplanes = 3;    /* init to three so user can back up. */
  808.                      /* keypad '1', '2', and '3' will change this */
  809.     
  810.     running = FALSE;            /* begin in not-running mode */
  811.     for(;;){
  812.     changetitle(running, erasemode, tilemode, gen);
  813.     while(!running)   /*  initial pattern setup */
  814.     { 
  815.         if((message = (struct IntuiMessage *)GetMsg(mywin->UserPort)) != 0L ) {
  816.             messagecopy = *message;            /* make local copy for our use */
  817.             ReplyMsg(message);
  818.             gen = domessage(x, y, gen);
  819.       } /* if */
  820.         x = myscreen->MouseX ;
  821.         y = myscreen->MouseY - 10;
  822.         y = (y < 1) ? 1 : y;
  823.     } /* while for setup */ 
  824.  
  825.     do
  826.     {
  827.         if((message = (struct IntuiMessage *)GetMsg(mywin->UserPort)) != 0L )
  828.         {
  829.             messagecopy = *message;            /* make local copy for our use */
  830.  
  831.           /***DEBUG***?
  832.             printf("Before ReplyMsg.  x=%x  y=%x \n", x, y);
  833.             /**?  cc = getchar();
  834.             if (cc== 'q' || cc == 'Q') cleanup("Abort");   /** debug **?
  835.             printf("class=%lx   code=%lx \n", messagecopy.Class, 
  836.                                                 messagecopy.Code);
  837.                 printf("\n");
  838.             /**?  cc = getchar();
  839.             if (cc== 'q' || cc == 'Q') cleanup("Abort");   /** debug **?
  840.           /***DEBUG***/
  841.  
  842.             ReplyMsg(message);
  843.             gen = domessage(x, y, gen);
  844.       } /* if */
  845.         x = myscreen->MouseX ;
  846.         y = myscreen->MouseY - 10;
  847.         y = (y < 1) ? 1 : y;
  848.  
  849.         dogeneration() ;
  850.         gen++ ;
  851.     } while (running && !singlestep ); 
  852.     running = FALSE;
  853.     } /* for(;;) */
  854.  
  855. } /* main */
  856.