home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_08_01 / 8n01099a < prev    next >
Text File  |  1990-02-19  |  5KB  |  315 lines

  1. *****Listing 5*****
  2.  
  3. /*
  4.  *    life.c
  5.  *    copyright 1985,1988 Ronald Florence
  6.  *
  7.  *      compile: cc -O -s life.c keys.c -lcurses -ltermcap -o life
  8.  */
  9.  
  10.  
  11. #include    <curses.h>
  12. #include    <signal.h>
  13. #ifndef KEY_DOWN
  14. #include    "keys.h"
  15. #endif
  16.  
  17. #define ESC        0x1b
  18. #define    life        '@'
  19. #define    crowd        (life + 4)
  20. #define    lonely        (life + 2)
  21. #define    birth        (' ' + 3)
  22. #define    minwrap(a,d)    a = --a < 0 ? d : a
  23. #define    maxwrap(a,d)    a = ++a > d ? 0 : a
  24. #define wrap(a,z)    if (a < 0) (a) += z;        \
  25.             else if (a > z) (a) = 1;    \
  26.             else if (a == z) (a) = 0
  27. #define    MAXX        (COLS-1)
  28. #define    MAXY        (LINES-3)
  29. #define    boredom        5
  30.  
  31. typedef struct node    
  32. {
  33.   int    y, x;
  34.   struct node    *prev, *next;
  35. }  LIFE;
  36.  
  37. struct    
  38. {
  39.   int    y, x;
  40. } pos[8] = {    { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1},
  41.         {-1, 1}, {-1, 0}, {-1,-1}, { 0,-1}    
  42.        };
  43.  
  44. LIFE    *head, *tail;
  45.  
  46. extern    char    *malloc();
  47. char    
  48.   *rules[] = {
  49.     " ",
  50.     "The Rules of Life:",
  51.     " ",
  52.     "   1. A cell with more than three neighbors dies of overcrowding.",
  53.     "   2. A cell with less than two neighbors dies of loneliness.",
  54.     "   3. A cell is born in an empty space with exactly three neighbors.",
  55.     " ",
  56.     0
  57.     },
  58.   
  59.   *rules2[] = {
  60.     "Use the arrow keys or the vi cursor keys",
  61.     "(H = left, J = down, K = up, L = right)",
  62.     "to move the cursor around the screen.",  
  63.     "The spacebar creates and destroys life.",
  64.     "<Esc> starts the cycle of reproduction.",
  65.     "<Del> ends life.", 
  66.     " ",
  67.     "Press any key to play The Game of Life.",
  68.     0
  69.     };
  70.  
  71.  
  72. main(ac, av)
  73.      int    ac;
  74.      char    **av; 
  75. {
  76.   int    i = 0, k, die(); 
  77.         
  78.   initscr();
  79.   crmode();
  80.   noecho();
  81.   signal(SIGINT, die);
  82.   lookupkeys();
  83.   head = (LIFE *)malloc(sizeof(LIFE));
  84.   tail = (LIFE *)malloc(sizeof(LIFE)); /* lest we have an unanchored pointer */
  85.   head->next = tail;
  86.   tail->prev = head;
  87.   
  88.   if (ac > 1) 
  89.     readfn(*++av);
  90.   else
  91.     {
  92.       erase();
  93.       if (COLS > 40) 
  94.     for ( ; rules[i]; i++)
  95.       mvaddstr(i+1, 0, rules[i]);
  96.       for (k = 0; rules2[k]; k++)
  97.     mvaddstr(i+k+1, 0, rules2[k]);
  98.       refresh();
  99.       while (!getch())
  100.     ;
  101.       setup();
  102.     }
  103.   nonl();
  104.   while (TRUE)
  105.     {
  106.       display();  
  107.       mark_life();
  108.       update();
  109.     }
  110. }
  111.  
  112.  
  113. die()
  114. {
  115.   signal(SIGINT, SIG_IGN);
  116.   move(LINES-1, 0);
  117.   refresh();
  118.   endwin();
  119.   exit(0);
  120. }
  121.  
  122.  
  123. kill_life(ly, lx)
  124.      register  int    ly, lx;
  125. {
  126.   register  LIFE    *lp;
  127.   
  128.   for (lp = head->next; lp != tail; lp = lp->next)
  129.     if (lp->y == ly && lp->x == lx)  
  130.       {
  131.     lp->prev->next = lp->next;
  132.     lp->next->prev = lp->prev;
  133.     free(lp);
  134.     break;
  135.       }
  136. }
  137.  
  138.  
  139. display()
  140. {
  141.   int        pop = 0;
  142.   static int    gen, oldpop, boring;
  143.   char    c;
  144.   register  LIFE  *lp;
  145.  
  146.   erase();
  147.   for(lp = head->next; lp != tail; lp = lp->next) 
  148.     {
  149.       mvaddch(lp->y, lp->x, life);
  150.       pop++;
  151.     }  
  152.   if (pop == oldpop)
  153.     boring++;
  154.   else 
  155.     {
  156.       oldpop = pop;
  157.       boring = 0;
  158.     }
  159.   move(MAXY+1, 0);
  160.   if (!pop)  
  161.     {
  162.       printw("Life ends after %d generations.", gen);
  163.       die();
  164.     }
  165.   printw("generation - %-4d", ++gen);
  166.   printw(" population - %-4d", pop);
  167.   refresh();
  168.   if (boring == boredom) 
  169.     {
  170.       mvprintw(MAXY, 0, "Population stable.  Abort? ");
  171.       refresh();
  172.       while (!(c = getch()))
  173.     ;
  174.       if (toupper(c) == 'Y')
  175.     die();
  176.     }
  177. }
  178.  
  179.  
  180. mark_life()
  181. {
  182.   register  k, ty, tx;
  183.   register  LIFE  *lp;    
  184.  
  185.   for (lp = head->next; lp; lp = lp->next)  
  186.     for (k = 0; k < 8; k++) 
  187.       {
  188.     ty = lp->y + pos[k].y; 
  189.     wrap(ty, MAXY);
  190.     tx = lp->x + pos[k].x; 
  191.     wrap(tx, MAXX); 
  192.     stdscr->_y[ty][tx]++;
  193.       }
  194. }
  195.  
  196.  
  197. update()
  198. {
  199.   register  int    i, j, c;
  200.  
  201.   for (i = 0; i <= MAXY; i++)
  202.     for (j = 0; j <= MAXX; j++) 
  203.       {
  204.     c = stdscr->_y[i][j];
  205.     if (c >= crowd || c >= life && c < lonely) 
  206.       kill_life(i, j);
  207.     else if (c == birth) 
  208.       newlife(i, j);
  209.       }
  210. }
  211.         
  212.             
  213. setup()
  214. {
  215.   int    x, y, c, start = 0;
  216.  
  217.   erase();
  218.   y = MAXY/2;
  219.   x = MAXX/2;
  220.   while (!start) 
  221.     {
  222.       move(y, x);    
  223.       refresh();
  224.       switch (c = getkey())  
  225.     { 
  226.     case 'h' : 
  227.     case 'H' :
  228.     case ('H' - '@'):
  229.     case KEY_LEFT:
  230.     case KEY_BACKSPACE:
  231.       minwrap(x, MAXX);
  232.       break;
  233.     case 'j' :
  234.     case 'J' :
  235.     case ('J' - '@'):
  236.     case KEY_DOWN:
  237.       maxwrap(y, MAXY);
  238.       break;
  239.     case 'k' :
  240.     case 'K' :
  241.     case ('K' - '@'):
  242.     case KEY_UP:
  243.       minwrap(y, MAXY);
  244.       break;
  245.     case 'l' :
  246.     case 'L' :
  247.     case ('L' - '@'):
  248.     case KEY_RIGHT:
  249.       maxwrap(x, MAXX);
  250.       break;
  251.     case ' ' :
  252.       if (inch() == life)  
  253.         {
  254.           addch(' ');
  255.           kill_life(y, x);
  256.         }
  257.       else 
  258.         {
  259.           addch(life);
  260.           newlife(y, x);
  261.         }
  262.       break;
  263.     case 'q' :
  264.     case 'Q' :
  265.     case ESC :
  266.       ++start;
  267.       break;
  268.     }
  269.     }  
  270. }
  271.  
  272.  
  273. newlife(ny, nx)
  274.      int    ny, nx;
  275. {
  276.   LIFE    *new;
  277.   
  278.   new = (LIFE *)malloc(sizeof(LIFE));
  279.   new->y = ny;
  280.   new->x = nx;
  281.   new->next = head->next;
  282.   new->prev = head;
  283.   head->next->prev = new;
  284.   head->next = new;
  285. }
  286.  
  287.  
  288. readfn(f)
  289.      char    *f;
  290. {
  291.   FILE    *fl;
  292.   int    y, x;
  293.  
  294.   if ((fl = fopen(f, "r")) == NULL) 
  295.     errx("usage: life [file (line/col pts)]\n", NULL);
  296.   while (fscanf(fl, "%d%d", &y, &x) != EOF) 
  297.     {
  298.       if (y < 0 || y > MAXY || x < 0 || x > MAXX) 
  299.     errx("life: invalid data point in %s\n", f);
  300.       mvaddch(y, x, life);
  301.       newlife(y, x);
  302.     }
  303.   fclose(fl);
  304.   
  305. }
  306.  
  307.  
  308. errx(m,d)
  309.      char    *m, *d;
  310. {
  311.   fprintf(stderr, m, d);
  312.   endwin();
  313.   exit(0);
  314. }
  315.