home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / SIMTEL / CPMUG / CPMUG048.ARK / HLIFE.C < prev    next >
C/C++ Source or Header  |  1984-04-29  |  9KB  |  399 lines

  1.  
  2. /*
  3.     "LIFE"
  4.  
  5.     The game invented by John Conway
  6.  
  7.     *************************************************    
  8.     *    This version specially configured for    *
  9.     *    the H19 terminal (and its 25th line)    *
  10.     *************************************************
  11.     
  12.     This version written by Leor Zolman to exemplify
  13.     PROPER use of"goto" statements in C programs!
  14.  
  15.     Compile with the "-o" option to CC1 for best per-
  16.     formance.
  17.  
  18.     Note that the Universe is a toroid; i.e,
  19.     the left extreme is adjacent to the right extreme,
  20.     the top is adjacent to the bottom, and each corner
  21.     is adjacent to each other corner.
  22.     In other words, there ARE NO EXTREMES !!
  23.     Or, in a more physical illustration: If I could
  24.     take a peek straight ahead through the magical
  25.     eyepiece of an infinitely powerful telescope,
  26.     I'd be able to see the back of my brain-damaged 
  27.     head....that is, of course, assuming no galaxies
  28.     or cats get in the way.
  29.  
  30. */
  31.  
  32. #define SILENT 0    /* comment out this line to
  33.                 enable data display        */
  34.  
  35. #define CLEARS "\033E\033y1\033x1\033x5"
  36.  
  37. #define TWIDTH 80    /* # of columns on your terminal    */
  38. #define XSIZE 100    /* length of cell array    (max # of lines)*/
  39. #define YSIZE 90    /* width of cell array            */
  40.             /* To see how the toroid works,
  41.                try reducing XSIZE and YSIZE to
  42.                around 10 or 20.            */
  43.  
  44. #define BOREDOM_THRESHOLD 5  /* This is how many generations
  45.                 are allowed to pass without a
  46.                 population change before Divine 
  47.                 intervention is called for.    */
  48.  
  49. char *gets();        /* routine to accept a line of input    */
  50. char cell[XSIZE][YSIZE];     /* the universe matrix        */
  51. int minx, maxx, miny, maxy, pop, gen;    /* misc. variables    */
  52. char doneflag;          /* This goes true when we want to stop    */
  53. int boring;        /* keeps count of how many generations
  54.                go by without a population change    */
  55. /*
  56.     The main driving routine, to accept random initial
  57.     and population configurations, and display their
  58.     evolution according to a proximity-based formula.
  59. */
  60.  
  61. main()
  62. {
  63.     char c;
  64.     printf("%s\n\t**** BDS  Life ****\n\n",CLEARS);
  65.     printf(    "\tSpecial H19 Version\n\n");
  66.     for (;;) {
  67.       clear();
  68.       setup();
  69.       if (!pop) break;
  70.       adjust();
  71.       display();
  72.       while (pop) {
  73.         adjust();
  74.         dogen();
  75.         if (kbhit()) {
  76.             getchar();
  77.             puts("\033y1\033x1\033j\033Y89");
  78.             printf("The Wrath Of God Strikes! KA-BEEP!\7");
  79.             puts("\033K\033k\033y5\n");
  80.             sleep(10);
  81.             break;
  82.          }
  83.         if (doneflag) break;
  84.         display();
  85.         if (boring == BOREDOM_THRESHOLD) {
  86.           boring++;
  87.           printf("\033j\033y5\033y1\033x1\033Y8 No change in ");
  88.           printf("population for %d ",BOREDOM_THRESHOLD);
  89.           printf("generations. Abort? (y/n) ");
  90.           c = toupper(getchar());
  91.           puts("\033k");
  92.           if (c == 'Y') break;
  93.          }
  94.        }
  95.      }
  96.     puts("\033z");
  97.  }
  98.  
  99. /* Initialize the cell matrix to all dead */
  100.  
  101. clear()
  102. {
  103.     setmem(cell,(XSIZE*YSIZE),0);
  104. }
  105.  
  106. /* Get initial set-up from user */
  107.  
  108. setup()
  109. {
  110.     char c;
  111.     int y;
  112.     char string[YSIZE], *ptr;
  113.     y = pop = gen = minx = maxx = miny= maxy = 0;
  114.     boring = 0;
  115.     printf("\033y5");
  116.     printf("\n\nEnter initial configuration (single period to end):\n");
  117.  
  118.     while (*gets(string) != '.') {
  119.         ptr = string;
  120.         while (*ptr) {
  121.             if ( *ptr++ != ' ') {
  122.                 cell[maxx][y] = 10;
  123.                 ++pop;
  124.              }
  125.             ++y;
  126.             if (y==YSIZE) {
  127.              printf("Truncated to %d chars\n",
  128.                  YSIZE); break;
  129.              }
  130.          }
  131.         --y;
  132.         ++maxx;
  133.         if (y>maxy) maxy = y;
  134.         if (maxx==XSIZE) break;
  135.         y = 0;
  136.      }
  137.     --maxx;
  138.     printf(CLEARS);
  139. }
  140.  
  141. /* Display the current generation */
  142.  
  143. display()
  144. {
  145.     int i,j,k,l,j9;
  146.     char c;
  147.     char line;
  148.     char *cline;
  149.  
  150.     puts("\033x5");        /* shut off blinking cursor    */
  151.  
  152.     if (!pop) {
  153.         printf("\033y1\033x1\033j\033Y89Life ends at %d\033k\033y5\7",
  154.                gen);
  155.         sleep(20);
  156.         return;
  157.      }
  158.  
  159.     if(minx && prow(minx-1)) minx--;
  160.     if(miny && pcol(miny-1)) miny--;
  161.     if ((maxx < (XSIZE-1)) && prow(maxx+1)) maxx++;
  162.     if((maxy<(YSIZE-1)) && pcol(maxy+1))maxy++;
  163.     
  164.     while (!prow(minx)) minx++;
  165.     while (!prow(maxx)) maxx--;
  166.     while (!pcol(miny)) miny++;
  167.     while (!pcol(maxy)) maxy--;
  168.  
  169.     if (!doneflag) {
  170. #ifndef SILENT
  171.       printf("\033y1\033x1\033j\033Y87generation = %3d   population = %3d",
  172.         gen,pop);
  173.       puts("\033k\033E");
  174. #endif
  175.     ;}
  176.     else puts("\033y5\033E");
  177.  
  178.     ++gen;
  179.  
  180.     line = 255;
  181.  
  182.     if (maxx - minx < 23) {
  183.         line += (23 - (maxx - minx))/2;
  184.         printf("\033Y%co\033b",line+' ');
  185.      }
  186.  
  187.     j9 = maxy - miny + 1;
  188.     l = ' ' + (j9 < TWIDTH ? (TWIDTH - j9)/2 : 0);
  189.  
  190.     for (i = minx; i<=maxx; i++) {
  191.        cline = cell[i] + miny;
  192.  
  193.        if (line == 23) putchar('\n');
  194.         else line++;
  195.  
  196.        printf("\033Y%c%c\033l",line+' ',l);
  197.  
  198.        for(j=0; j<j9; j++)
  199.         putchar( *cline++ ? '*' : ' ');
  200.     }
  201.     printf("\033J");
  202. }
  203.  
  204. /* Test if given column is populated */
  205.  
  206. pcol(n)
  207. {
  208.     int i,hi;
  209.     hi = (maxx == (XSIZE-1)) ? maxx : maxx+1;
  210.     for (i = minx ? minx-1 : minx; i<=hi; ++i)
  211.         if (cell[i][n]) return 1;
  212.     return 0;
  213. }
  214.  
  215. /* Test if given row is populated */
  216.  
  217. prow(n)
  218. {
  219.     int i,hi;
  220.     hi = (maxy == (YSIZE-1)) ? maxy : maxy+1;
  221.     for (i = miny ? miny-1 : miny; i<=hi; ++i)
  222.         if (cell[n][i]) return 1;
  223.     return 0;
  224. }
  225.  
  226.  
  227. /*
  228.    Compute next generation. Algorithm used is a two-pass
  229.    cuteness suggested to me by Ward Christensen (he uses
  230.    it on a machine-language version on a 1024 character
  231.    display, and it cranks out 20 generations a second at
  232.    2 MHz.)
  233.    The algorithm uses the low order 3 bits of each 1-byte
  234.    cell as a neighbor count. The first pass finds all live
  235.    cells and increments the count of each of the 8 neighbors
  236.    of such live cells. For the first pass, dead cells are
  237.    totally ignored. The second pass then comes along and
  238.    checks the counts off all cells within the active square
  239.    to determine who lives and who dies. Note that this is a
  240.    significant improvement over the "obvious" method of
  241.    examining all 8 neighbors of each and every cell, dead
  242.    or alive, in the array.
  243. */
  244.  
  245. dogen()
  246. {
  247.     int i,j,i2,j2;
  248.     int bigflag;
  249.     int k,l;
  250.     int oldpop;
  251.     char c;
  252.     int pass;
  253.     doneflag = 1;
  254.     oldpop = pop;
  255.     bigflag =  (minx<2 || maxx>(XSIZE-3) ||
  256.         miny<2 || maxy>(YSIZE-3)) ;
  257.     i2 = (maxx==(XSIZE-1)) ? maxx : maxx+1;
  258.     j2 = (maxy==(YSIZE-1)) ? maxy : maxy+1;
  259.     for (pass = 0; pass < 2; pass++)
  260.     for (i=minx ? minx-1 : minx; i<=i2; ++i)
  261.       for (j=miny ? miny-1 : miny; j<=j2; ++j) {
  262.        c = cell[i][j];
  263.        if (!pass) {
  264.          if (c >= 10)
  265.         if (bigflag)
  266.           for (k = -1; k <= 1; k++)
  267.            for (l = -1; l <= 1; l++)
  268.             cell[mod(i+k,XSIZE)][mod(j+l,YSIZE)]++;
  269.         else
  270.           for (k = -1; k<=1; k++)
  271.            for (l = -1; l <= 1; l++)
  272.             cell[i+k][j+l]++;
  273.         }
  274.        else
  275.          if (c > 10)
  276.         if (c < 13 || c > 14) {
  277.             cell[i][j] = 0;
  278.             pop--;
  279.             doneflag = 0;
  280.          }
  281.         else cell[i][j] = 10;
  282.          else
  283.         if (c == 3) {
  284.             cell[i][j] = 10;
  285.             pop++;
  286.             doneflag = 0;
  287.          }
  288.         else cell[i][j] = 0;
  289.      }
  290.     if (pop == oldpop) boring++;
  291.       else boring = 0;
  292.     if (doneflag) {
  293.      printf("\033y1\033x1\033j\033Y89Static configuration reached\033k\7");
  294.      sleep(20);
  295.     }
  296. }
  297.  
  298.  
  299. int mod(a,b)
  300. {
  301.     if (a<0) return b+a;
  302.     if (a<b) return a;
  303.     return a-b;
  304. }
  305.  
  306.  
  307. /* If we're about to run off the matrix, adjust accordingly (if possible) */
  308.  
  309. adjust()
  310. {
  311.     adjx();        /* for overflow in x direction    */
  312.     adjy();        /* and also in y direction    */
  313. }
  314.  
  315. /* Adjust vertical position */
  316.  
  317. adjx()
  318. {
  319.     int delta, i,j;
  320.     int savdelta;
  321.     if (maxx - minx + 1 > XSIZE-2) return;
  322.     if (minx==0) {
  323.         delta = (XSIZE-maxx)/2+maxx;
  324.         savdelta = delta;
  325.         for (i=maxx; i >= 0; --i) {
  326.             for (j=miny; j<=maxy; ++j) {
  327.                 cell[delta][j] = cell[i][j];
  328.                 cell[i][j] = 0;
  329.              }
  330.         --delta;
  331.         }
  332.         minx = delta+1;
  333.         maxx = savdelta;
  334.     }
  335.  
  336.     if (maxx == (XSIZE-1)) {
  337.         delta = minx/2;
  338.         savdelta = delta;
  339.         for (i=minx; i<XSIZE; ++i) {
  340.             for (j=miny; j<=maxy; ++j) {
  341.                 cell[delta][j] = cell[i][j];
  342.                 cell[i][j] = 0;
  343.             }
  344.         ++delta;
  345.         }
  346.         maxx = delta-1;
  347.         minx = savdelta;
  348.     }
  349. }
  350.  
  351.  
  352. /* Adjust horizontal position */
  353.  
  354. adjy()
  355. {
  356.     int delta, i, j;
  357.     int savdelta;
  358.     if (maxy - miny + 1 > YSIZE -2) return;
  359.     if (miny == 0) {
  360.         delta = (YSIZE-maxy)/2+maxy;
  361.         savdelta = delta;
  362.         for (i=maxy; i>=0; --i) {
  363.             for (j=minx; j<=maxx; ++j) {
  364.                 cell[j][delta] = cell[j][i];
  365.                 cell[j][i] = 0;
  366.             }
  367.         --delta;
  368.         }
  369.         miny = delta+1;
  370.         maxy = savdelta;
  371.     }
  372.  
  373.     if (maxy == (YSIZE-1)) {
  374.         delta = miny/2;
  375.         savdelta = delta;
  376.         for (i=miny; i<YSIZE; ++i) {
  377.             for (j=minx; j<=maxx; ++j) {
  378.                 cell[j][delta] = cell[j][i];
  379.                 cell[j][i] = 0;
  380.             }
  381.         ++delta;
  382.         }
  383.         maxy = delta -1;
  384.         miny = savdelta;
  385.     }
  386. }
  387.  
  388. /*
  389.     This is done so that the Wrath Of God doesn't mess up the
  390.     display:
  391. */
  392.  
  393. putchar(c)
  394. char c;
  395. {
  396.     putch(c);
  397. }
  398.  
  399.