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 >
Wrap
Text File
|
1990-02-19
|
5KB
|
315 lines
*****Listing 5*****
/*
* life.c
* copyright 1985,1988 Ronald Florence
*
* compile: cc -O -s life.c keys.c -lcurses -ltermcap -o life
*/
#include <curses.h>
#include <signal.h>
#ifndef KEY_DOWN
#include "keys.h"
#endif
#define ESC 0x1b
#define life '@'
#define crowd (life + 4)
#define lonely (life + 2)
#define birth (' ' + 3)
#define minwrap(a,d) a = --a < 0 ? d : a
#define maxwrap(a,d) a = ++a > d ? 0 : a
#define wrap(a,z) if (a < 0) (a) += z; \
else if (a > z) (a) = 1; \
else if (a == z) (a) = 0
#define MAXX (COLS-1)
#define MAXY (LINES-3)
#define boredom 5
typedef struct node
{
int y, x;
struct node *prev, *next;
} LIFE;
struct
{
int y, x;
} pos[8] = { { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1},
{-1, 1}, {-1, 0}, {-1,-1}, { 0,-1}
};
LIFE *head, *tail;
extern char *malloc();
char
*rules[] = {
" ",
"The Rules of Life:",
" ",
" 1. A cell with more than three neighbors dies of overcrowding.",
" 2. A cell with less than two neighbors dies of loneliness.",
" 3. A cell is born in an empty space with exactly three neighbors.",
" ",
0
},
*rules2[] = {
"Use the arrow keys or the vi cursor keys",
"(H = left, J = down, K = up, L = right)",
"to move the cursor around the screen.",
"The spacebar creates and destroys life.",
"<Esc> starts the cycle of reproduction.",
"<Del> ends life.",
" ",
"Press any key to play The Game of Life.",
0
};
main(ac, av)
int ac;
char **av;
{
int i = 0, k, die();
initscr();
crmode();
noecho();
signal(SIGINT, die);
lookupkeys();
head = (LIFE *)malloc(sizeof(LIFE));
tail = (LIFE *)malloc(sizeof(LIFE)); /* lest we have an unanchored pointer */
head->next = tail;
tail->prev = head;
if (ac > 1)
readfn(*++av);
else
{
erase();
if (COLS > 40)
for ( ; rules[i]; i++)
mvaddstr(i+1, 0, rules[i]);
for (k = 0; rules2[k]; k++)
mvaddstr(i+k+1, 0, rules2[k]);
refresh();
while (!getch())
;
setup();
}
nonl();
while (TRUE)
{
display();
mark_life();
update();
}
}
die()
{
signal(SIGINT, SIG_IGN);
move(LINES-1, 0);
refresh();
endwin();
exit(0);
}
kill_life(ly, lx)
register int ly, lx;
{
register LIFE *lp;
for (lp = head->next; lp != tail; lp = lp->next)
if (lp->y == ly && lp->x == lx)
{
lp->prev->next = lp->next;
lp->next->prev = lp->prev;
free(lp);
break;
}
}
display()
{
int pop = 0;
static int gen, oldpop, boring;
char c;
register LIFE *lp;
erase();
for(lp = head->next; lp != tail; lp = lp->next)
{
mvaddch(lp->y, lp->x, life);
pop++;
}
if (pop == oldpop)
boring++;
else
{
oldpop = pop;
boring = 0;
}
move(MAXY+1, 0);
if (!pop)
{
printw("Life ends after %d generations.", gen);
die();
}
printw("generation - %-4d", ++gen);
printw(" population - %-4d", pop);
refresh();
if (boring == boredom)
{
mvprintw(MAXY, 0, "Population stable. Abort? ");
refresh();
while (!(c = getch()))
;
if (toupper(c) == 'Y')
die();
}
}
mark_life()
{
register k, ty, tx;
register LIFE *lp;
for (lp = head->next; lp; lp = lp->next)
for (k = 0; k < 8; k++)
{
ty = lp->y + pos[k].y;
wrap(ty, MAXY);
tx = lp->x + pos[k].x;
wrap(tx, MAXX);
stdscr->_y[ty][tx]++;
}
}
update()
{
register int i, j, c;
for (i = 0; i <= MAXY; i++)
for (j = 0; j <= MAXX; j++)
{
c = stdscr->_y[i][j];
if (c >= crowd || c >= life && c < lonely)
kill_life(i, j);
else if (c == birth)
newlife(i, j);
}
}
setup()
{
int x, y, c, start = 0;
erase();
y = MAXY/2;
x = MAXX/2;
while (!start)
{
move(y, x);
refresh();
switch (c = getkey())
{
case 'h' :
case 'H' :
case ('H' - '@'):
case KEY_LEFT:
case KEY_BACKSPACE:
minwrap(x, MAXX);
break;
case 'j' :
case 'J' :
case ('J' - '@'):
case KEY_DOWN:
maxwrap(y, MAXY);
break;
case 'k' :
case 'K' :
case ('K' - '@'):
case KEY_UP:
minwrap(y, MAXY);
break;
case 'l' :
case 'L' :
case ('L' - '@'):
case KEY_RIGHT:
maxwrap(x, MAXX);
break;
case ' ' :
if (inch() == life)
{
addch(' ');
kill_life(y, x);
}
else
{
addch(life);
newlife(y, x);
}
break;
case 'q' :
case 'Q' :
case ESC :
++start;
break;
}
}
}
newlife(ny, nx)
int ny, nx;
{
LIFE *new;
new = (LIFE *)malloc(sizeof(LIFE));
new->y = ny;
new->x = nx;
new->next = head->next;
new->prev = head;
head->next->prev = new;
head->next = new;
}
readfn(f)
char *f;
{
FILE *fl;
int y, x;
if ((fl = fopen(f, "r")) == NULL)
errx("usage: life [file (line/col pts)]\n", NULL);
while (fscanf(fl, "%d%d", &y, &x) != EOF)
{
if (y < 0 || y > MAXY || x < 0 || x > MAXX)
errx("life: invalid data point in %s\n", f);
mvaddch(y, x, life);
newlife(y, x);
}
fclose(fl);
}
errx(m,d)
char *m, *d;
{
fprintf(stderr, m, d);
endwin();
exit(0);
}