/* life - Conway's game of life Author: Jim King */ /* clife.c - curses life simulator. Translated from Pascal to C implementing * curses Oct 1988 by pulsar@lsrhs, not jek5036@ritvax.isc.rit.edu * life needs about 18kb stack space on MINIX. * * Flags: -d draw your own screen using arrows and space bar * -p print statistics on the bottom line during the game */ #include #include #include #include #include #include #include #if __minix_vmd /* Use a more random rand(). */ #define srand(seed) srandom(seed) #define rand() random() #endif /* A value of -1 will make it go forever */ /* A value of 0 will make it exit immediately */ #define REPSTOP -1 /* number of repetitions before stop */ int present[23][80]; /* screen 1 cycle ago */ int past[23][80]; /* screen this cycle */ int total; /* total # of changes */ int icnt; /* counter to check for repetition */ int maxrow = 22; /* some defines to represent the screen */ int maxcol = 79; int minrow = 0; int mincol = 0; int pri = 0; /* flag for printing stats on bottom line */ int draw = 0; /* flag for drawing your own screen */ int i, j, k; /* loop counters */ int cycle; /* current cycle # */ int changes; /* # of changes this cycle (live + die) */ int die; /* number of deaths this cycle */ int live; /* number of births this cycle */ WINDOW *mns; /* Main Screen */ WINDOW *info; /* Bottom line */ _PROTOTYPE(void cleanup, (int s)); _PROTOTYPE(void initialize, (void)); _PROTOTYPE(void makscr, (void)); _PROTOTYPE(void update, (void)); _PROTOTYPE(void print, (void)); _PROTOTYPE(int main, (int ac, char *av[])); /* Cleanup - cleanup then exit */ void cleanup(s) int s; { move(23, 0); /* go to bottom of screen */ refresh(); /* update cursor */ endwin(); /* shutdown curses */ exit(1); /* exit */ } /* Initialize - init windows, variables, and signals */ void initialize() { srand(getpid()); /* init random seed */ initscr(); /* init curses */ noecho(); curs_set(0); signal(SIGINT, cleanup); /* catch ^C */ mns = newwin(maxrow, maxcol, 0, 0); /* new window */ scrollok(mns, FALSE); info = newwin(1, 80, 23, 0); scrollok(info, FALSE); wclear(mns); wclear(info); wmove(info, 0, 0); wrefresh(info); if (!draw) { /* if no draw, make random pattern */ for (j = 0; j < maxrow; j++) { for (k = 0; k < maxcol; k++) { present[j][k] = rand() % 2; if (present[j][k] == 1) changes++, live++; } } } } /* Makscr - make your own screen using arrow keys and space bar */ void makscr() { int curx, cury; /* current point on screen */ char c; /* input char */ wclear(info); wmove(info, 0, 0); wprintw(info, "Use arrow keys to move, space to place / erase, ^D to start", NULL); wrefresh(info); curx = cury = 1; wmove(mns, cury - 1, curx - 1); wrefresh(mns); noecho(); for (;;) { c = wgetch(mns); if (c == '\004') break; else if (c == ' ') { if (present[cury][curx]) { --present[cury][curx]; changes++; die++; mvwaddch(mns, cury, curx, ' '); } else { ++present[cury][curx]; changes++; live++; mvwaddch(mns, cury, curx, '*'); } } else if (c == '\033') { wgetch(mns); switch (wgetch(mns)) { case 'A': --cury; break; case 'B': ++cury; break; case 'C': ++curx; break; case 'D': --curx; break; default: break; } } if (cury > maxrow) cury = minrow; if (cury < minrow) cury = maxrow; if (curx > maxcol) curx = mincol; if (curx < mincol) curx = maxcol; wmove(mns, cury, curx); wrefresh(mns); } wclear(info); } /* Update rules: 2 or 3 adjacent alive --- stay alive * 3 adjacent alive -- dead to live * all else die or stay dead */ void update() { /* Does all mathmatical calculations */ int howmany, w, x, y, z; changes = die = live = 0; for (j = 0; j < maxrow; j++) { for (k = 0; k < maxcol; k++) { w = j - 1; x = j + 1; y = k - 1; z = k + 1; howmany = (past[w][y] + past[w][k] + past[w][z] + past[j][y] + past[j][z] + past[x][y] + past[x][k] + past[x][z]); switch (howmany) { case 0: case 1: case 4: case 5: case 6: case 7: case 8: present[j][k] = 0; if (past[j][k]) changes++, die++; break; case 3: present[j][k] = 1; if (!past[j][k]) changes++, live++; break; default: break; } } } if (live == die) ++icnt; else icnt = 0; if (icnt == REPSTOP) cleanup(0); } /* Print - updates the screen according to changes from past to present */ void print() { /* Updates the screen, greatly improved using curses */ if (pri) { wmove(info, 0, 0); total += changes; cycle++; wprintw(info, "Cycle %5d | %5d changes: %5d died + %5d born = %5u total changes", (char *) cycle, changes, die, live, total); wclrtoeol(info); } for (j = 1; j < maxrow; j++) { for (k = 1; k < maxcol; k++) { if (present[j][k] != past[j][k] && present[j][k] == 1) { wmove(mns, j, k); wprintw(mns, "*", NULL); } else if (present[j][k] != past[j][k] && present[j][k] == 0) { wmove(mns, j, k); wprintw(mns, " ", NULL); } } } if (pri) wrefresh(info); wrefresh(mns); } /* Main - main procedure */ int main(ac, av) int ac; char *av[]; { if (ac > 1) { for (j = 1; j < ac; j++) { switch (av[j][1]) { case 'd': ++draw; break; case 'p': ++pri; break; default: fprintf(stderr, "%s: usage: %s [-d] [-p]\n", av[0], av[0]); exit(1); } } } initialize(); if (draw) makscr(); for (;;) { print(); for (j = 0; j < maxrow; j++) { for (k = 0; k < maxcol; k++) past[j][k] = present[j][k]; } update(); } }