life.c

Go to the documentation of this file.
00001 /* life - Conway's game of life         Author: Jim King */
00002 
00003 /* clife.c - curses life simulator.  Translated from Pascal to C implementing
00004  *           curses Oct 1988 by pulsar@lsrhs, not jek5036@ritvax.isc.rit.edu
00005  *           life needs about 18kb stack space on MINIX.
00006  *
00007  * Flags:       -d  draw your own screen using arrows and space bar
00008  *              -p  print statistics on the bottom line during the game
00009  */
00010 
00011 #include <sys/types.h>
00012 #include <signal.h>
00013 #include <time.h>
00014 #include <curses.h>
00015 #include <stdlib.h>
00016 #include <unistd.h>
00017 #include <stdio.h>
00018 
00019 #if __minix_vmd         /* Use a more random rand(). */
00020 #define srand(seed)     srandom(seed)
00021 #define rand()          random()
00022 #endif
00023 
00024 /* A value of -1 will make it go forever */
00025 /* A value of 0 will make it exit immediately */
00026 #define REPSTOP         -1      /* number of repetitions before stop */
00027 
00028 int present[23][80];            /* screen 1 cycle ago */
00029 int past[23][80];               /* screen this cycle */
00030 int total;                      /* total # of changes */
00031 int icnt;                       /* counter to check for repetition */
00032 int maxrow = 22;                /* some defines to represent the screen */
00033 int maxcol = 79;
00034 int minrow = 0;
00035 int mincol = 0; 
00036 int pri = 0;                    /* flag for printing stats on bottom line */
00037 int draw = 0;                   /* flag for drawing your own screen */
00038 int i, j, k;                    /* loop counters */
00039 int cycle;                      /* current cycle # */
00040 int changes;                    /* # of changes this cycle (live + die) */
00041 int die;                        /* number of deaths this cycle */
00042 int live;                       /* number of births this cycle */
00043 
00044 WINDOW *mns;                    /* Main Screen */
00045 WINDOW *info;                   /* Bottom line */
00046 
00047 _PROTOTYPE(void cleanup, (int s));
00048 _PROTOTYPE(void initialize, (void));
00049 _PROTOTYPE(void makscr, (void));
00050 _PROTOTYPE(void update, (void));
00051 _PROTOTYPE(void print, (void));
00052 _PROTOTYPE(int main, (int ac, char *av[]));
00053 
00054 /* Cleanup - cleanup then exit */
00055 void cleanup(s)
00056 int s;
00057 {
00058   move(23, 0);                  /* go to bottom of screen */
00059   refresh();                    /* update cursor */
00060 
00061   endwin();                     /* shutdown curses */
00062   exit(1);                      /* exit */
00063 }
00064 
00065 /* Initialize - init windows, variables, and signals */
00066 
00067 void initialize()
00068 {
00069   srand(getpid());              /* init random seed */
00070   initscr();                    /* init curses */
00071   noecho();
00072   curs_set(0);
00073   signal(SIGINT, cleanup);      /* catch ^C */
00074   mns = newwin(maxrow, maxcol, 0, 0);   /* new window */
00075   scrollok(mns, FALSE);
00076   info = newwin(1, 80, 23, 0);
00077   scrollok(info, FALSE);
00078   wclear(mns);
00079   wclear(info);
00080   wmove(info, 0, 0);
00081   wrefresh(info);
00082   if (!draw) {                  /* if no draw, make random pattern */
00083         for (j = 0; j < maxrow; j++) {
00084                 for (k = 0; k < maxcol; k++) {
00085                         present[j][k] = rand() % 2;
00086                         if (present[j][k] == 1) changes++, live++;
00087                 }
00088         }
00089   }
00090 }
00091 
00092 /* Makscr - make your own screen using arrow keys and space bar */
00093 void makscr()
00094 {
00095   int curx, cury;               /* current point on screen */
00096   char c;                       /* input char */
00097 
00098   wclear(info);
00099   wmove(info, 0, 0);
00100   wprintw(info, "Use arrow keys to move, space to place / erase, ^D to start", NULL);
00101   wrefresh(info);
00102   curx = cury = 1;
00103   wmove(mns, cury - 1, curx - 1);
00104   wrefresh(mns);
00105   noecho();
00106   for (;;) {
00107         c = wgetch(mns);
00108         if (c == '\004')
00109                 break;
00110         else if (c == ' ') {
00111                 if (present[cury][curx]) {
00112                         --present[cury][curx];
00113                         changes++;
00114                         die++;
00115                         mvwaddch(mns, cury, curx, ' ');
00116                 } else {
00117                         ++present[cury][curx];
00118                         changes++;
00119                         live++;
00120                         mvwaddch(mns, cury, curx, '*');
00121                 }
00122         } else if (c == '\033') {
00123                 wgetch(mns);
00124                 switch (wgetch(mns)) {
00125                     case 'A':   --cury; break;
00126                     case 'B':   ++cury; break;
00127                     case 'C':   ++curx; break;
00128                     case 'D':   --curx; break;
00129                     default:    break;
00130                 }
00131         }
00132         if (cury > maxrow) cury = minrow;
00133         if (cury < minrow) cury = maxrow;
00134         if (curx > maxcol) curx = mincol;
00135         if (curx < mincol) curx = maxcol;
00136         wmove(mns, cury, curx);
00137         wrefresh(mns);
00138   }
00139   wclear(info);
00140 }
00141 
00142 /* Update rules:  2 or 3 adjacent alive --- stay alive
00143  *                3 adjacent alive -- dead to live
00144  *                all else die or stay dead
00145  */
00146 void update()
00147 {                               /* Does all mathmatical calculations */
00148   int howmany, w, x, y, z;
00149   changes = die = live = 0;
00150   for (j = 0; j < maxrow; j++) {
00151         for (k = 0; k < maxcol; k++) {
00152                 w = j - 1;
00153                 x = j + 1;
00154                 y = k - 1;
00155                 z = k + 1;
00156 
00157                 howmany = (past[w][y] + past[w][k] + past[w][z] +
00158                            past[j][y] + past[j][z] + past[x][y] +
00159                            past[x][k] + past[x][z]);
00160 
00161                 switch (howmany) {
00162                     case 0:
00163                     case 1:
00164                     case 4:
00165                     case 5:
00166                     case 6:
00167                     case 7:
00168                     case 8:
00169                         present[j][k] = 0;
00170                         if (past[j][k]) changes++, die++;
00171                         break;
00172                     case 3:
00173                         present[j][k] = 1;
00174                         if (!past[j][k]) changes++, live++;
00175                         break;
00176                     default:    break;
00177                 }
00178         }
00179   }
00180   if (live == die)
00181         ++icnt;
00182   else
00183         icnt = 0;
00184 
00185   if (icnt == REPSTOP) cleanup(0);
00186 }
00187 
00188 /* Print - updates the screen according to changes from past to present */
00189 void print()
00190 {       
00191 /* Updates the screen, greatly improved using curses */
00192   if (pri) {
00193         wmove(info, 0, 0);
00194         total += changes;
00195         cycle++;
00196         wprintw(info, "Cycle %5d | %5d changes: %5d died + %5d born = %5u total changes", (char *) cycle, changes, die, live, total);
00197         wclrtoeol(info);
00198   }
00199   for (j = 1; j < maxrow; j++) {
00200         for (k = 1; k < maxcol; k++) {
00201                 if (present[j][k] != past[j][k] && present[j][k] == 1) {
00202                         wmove(mns, j, k);
00203                         wprintw(mns, "*", NULL);
00204                 } else if (present[j][k] != past[j][k] && present[j][k] == 0) {
00205                         wmove(mns, j, k);
00206                         wprintw(mns, " ", NULL);
00207                 }
00208         }
00209   }
00210   if (pri) wrefresh(info);
00211   wrefresh(mns);
00212 }
00213 
00214 /* Main - main procedure */
00215 int main(ac, av)
00216 int ac;
00217 char *av[];
00218 {
00219   if (ac > 1) {
00220         for (j = 1; j < ac; j++) {
00221                 switch (av[j][1]) {
00222                     case 'd':   ++draw; break;
00223                     case 'p':   ++pri;  break;
00224                     default:
00225                         fprintf(stderr, "%s: usage: %s [-d] [-p]\n", av[0], av[0]);
00226                         exit(1);
00227                 }
00228         }
00229   }
00230 
00231   initialize();
00232   if (draw) makscr();
00233 
00234   for (;;) {
00235         print();
00236         for (j = 0; j < maxrow; j++) {
00237                 for (k = 0; k < maxcol; k++) past[j][k] = present[j][k];
00238         }
00239         update();
00240   }
00241 }

Generated on Fri Apr 14 22:57:08 2006 for minix by  doxygen 1.4.6