254 lines
5.8 KiB
C
254 lines
5.8 KiB
C
/* LIFE.C The much implemented game of Life invented by John Conway
|
|
|
|
This version was written to illustrate the use of the C88
|
|
screen and keyboard interface. Use C option for color display.
|
|
|
|
To generate:
|
|
A>C88 B:LIFE
|
|
A>ASM88 B:PCIO
|
|
A>BIND B:LIFE B:PCIO */
|
|
|
|
|
|
/*
|
|
global constant and data declarations
|
|
*/
|
|
|
|
#define ROWS 24
|
|
#define COLS 80
|
|
|
|
/* control key translations */
|
|
#define up_char 30
|
|
#define down_char 31
|
|
#define left_char 29
|
|
#define right_char 28
|
|
#define bol_char 200
|
|
#define eol_char 201
|
|
#define pageup_char 202
|
|
#define pagedown_char 203
|
|
#define bof_char 204
|
|
#define eof_char 205
|
|
#define Ins_char 206
|
|
#define Del_char 207
|
|
#define NextWord_char 208
|
|
#define PrevWord_char 209
|
|
|
|
/* function keys */
|
|
#define M1 210
|
|
#define M2 211
|
|
#define M3 212
|
|
#define M4 213
|
|
#define M5 214
|
|
#define M6 215
|
|
#define M7 216
|
|
#define M8 217
|
|
#define M9 218
|
|
#define M10 219
|
|
|
|
|
|
char world[ROWS][COLS],create_mode=1,quit_flag;
|
|
int population,generation,crow,ccol;
|
|
char color_opt,color;
|
|
|
|
main(argc,argv)
|
|
int argc;
|
|
char *argv[]; {
|
|
|
|
if (argc > 1 && toupper(*argv[1]) == 'C') color_opt=1;
|
|
scr_setup();
|
|
scr_clr();
|
|
instruct();
|
|
setup();
|
|
|
|
do {
|
|
generation++;
|
|
cycle();
|
|
screen();
|
|
}
|
|
while (population && !quit_flag);
|
|
scr_rowcol(ROWS,10);
|
|
if (population == 0)
|
|
puts("Nobody left, sorry about that. ");
|
|
else puts("bye ");
|
|
scr_curson();
|
|
}
|
|
|
|
instruct() { /* print instructions */
|
|
|
|
puts(" The game of Life by John Conway\n\n");
|
|
puts(" Use LIFE C with color monitor.\n");
|
|
puts(" If started with a number, a random pattern starts the game.\n\n");
|
|
puts(" Otherwise, move the cursor with the four arrow keys to create life.\n\n");
|
|
puts(" DEL changes cursor movement to mean that cells are deleted\n\n");
|
|
puts(" INS flips back to create mode.\n\n");
|
|
puts(" The '+' key will toggle the game on or off.\n\n");
|
|
puts(" Hit ESC to bail out.\n\n");
|
|
puts(" Enter starting number of cells or hit CR ");
|
|
}
|
|
|
|
setup() {
|
|
int rnumber;
|
|
int i,row,col,seed,rnum;
|
|
char ch;
|
|
|
|
rnumber=0;
|
|
while (1) {
|
|
while ((ch=scr_csts()) == 0) seed++;
|
|
if (ch < '0' || ch > '9') break;
|
|
scr_co(ch);
|
|
rnumber*=10;
|
|
rnumber+=ch-'0';
|
|
}
|
|
scr_cursoff();
|
|
scr_clr();
|
|
scr_rowcol(ROWS,20); /* print population message */
|
|
puts("Generation 0 Population 0");
|
|
|
|
srand(seed); /* initilize random number generator */
|
|
|
|
for (i=0; i < rnumber; i++) {
|
|
rnum=rand();
|
|
row=rnum%ROWS;
|
|
col=(rnum/ROWS)%COLS;
|
|
world[row][col]='X'; /* put in a cell */
|
|
scr_rowcol(row,col);
|
|
if (color_opt) scr_aputs("\2",++color | 0X80);
|
|
else scr_co(2);
|
|
}
|
|
if (rnumber == 0) create(1);
|
|
}
|
|
|
|
|
|
screen() { /* update the screen and set world back to x's */
|
|
int row,col;
|
|
char cell;
|
|
|
|
population=0;
|
|
for (row=0; row < ROWS; row++) {
|
|
for (col=0; col < COLS; col++) {
|
|
cell=world[row][col];
|
|
/* stay alive if 3 neighbors, born if next to 2 or 3 */
|
|
|
|
if (cell && (cell == 3 || cell == 'X'+2 || cell == 'X'+3)) {
|
|
population++;
|
|
if (cell < 'X') {
|
|
scr_rowcol(row,col);
|
|
if (color_opt) scr_aputs("\2",++color | 0X80);
|
|
else scr_co(2);
|
|
}
|
|
cell='X';
|
|
}
|
|
else {
|
|
if (cell >= 'X') {
|
|
scr_rowcol(row,col);
|
|
scr_co(' ');
|
|
}
|
|
cell=0;
|
|
}
|
|
world[row][col]=cell;
|
|
}
|
|
}
|
|
scr_rowcol(ROWS,31);
|
|
printf("%4d",generation);
|
|
scr_rowcol(ROWS,51);
|
|
printf("%4d",population);
|
|
}
|
|
|
|
|
|
create(suspend) /* see if need to create or kill cells */
|
|
char suspend; {
|
|
char ch,wait;
|
|
|
|
while ((ch=scr_csts()) || suspend) {
|
|
switch (ch) {
|
|
case up_char: crow=crow ? crow-1: ROWS-1;
|
|
break;
|
|
case down_char: crow=crow == ROWS-1 ? 0: crow+1;
|
|
break;
|
|
case left_char: ccol=ccol ? ccol-1: COLS-1;
|
|
break;
|
|
case right_char:ccol=ccol == COLS-1 ? 0: ccol+1;
|
|
break;
|
|
case bol_char: ccol=0;
|
|
break;
|
|
case eol_char: ccol=COLS-1;
|
|
break;
|
|
case '+': suspend=!suspend;
|
|
continue;
|
|
case Ins_char: create_mode=1;
|
|
continue;
|
|
case Del_char: create_mode=0;
|
|
continue;
|
|
case 0x1b: quit_flag=1; /* flag for stop */
|
|
return;
|
|
default: continue;
|
|
}
|
|
world[crow][ccol]= create_mode ? 'X': 0;
|
|
scr_rowcol(crow,ccol);
|
|
if (create_mode) {
|
|
if (color_opt) scr_aputs("\2",++color | 0X80);
|
|
else scr_co(2);
|
|
population++;
|
|
}
|
|
else {
|
|
wait=30;
|
|
while (wait--) {
|
|
if (color_opt) scr_aputs("\1",++color | 0X80);
|
|
else scr_co(1);
|
|
scr_rowcol(crow,ccol);
|
|
}
|
|
scr_co(' ');
|
|
}
|
|
}
|
|
}
|
|
|
|
cycle() { /* cycle to the next generation */
|
|
int row,col;
|
|
|
|
create(0);
|
|
/* take care of left and right column first */
|
|
for (row=0; row < ROWS; row++) {
|
|
if (world[row][0] >= 'X') add8(row,0);
|
|
if (world[row][COLS-1] >= 'X') add8(row,COLS-1);
|
|
}
|
|
|
|
/* take care of top and bottom line */
|
|
for (col=1; col < COLS-1;col++) {
|
|
if (world[0][col] >= 'X') add8(0,col);
|
|
if (world[ROWS-1][col] >= 'X') add8(ROWS-1,col);
|
|
}
|
|
|
|
/* fill in the box, ignoring border conditions */
|
|
for (row=1; row < ROWS-1; row++) {
|
|
for (col=1; col < COLS-1; col++) {
|
|
if (world[row][col] >= 'X' ) {
|
|
world[row-1][col-1]++;
|
|
world[row-1][col]++;
|
|
world[row-1][col+1]++;
|
|
world[row][col-1]++;
|
|
world[row][col+1]++;
|
|
world[row+1][col-1]++;
|
|
world[row+1][col]++;
|
|
world[row+1][col+1]++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
add8(row,col)
|
|
int row,col; {
|
|
int rrow,ccol,rr,cc;
|
|
|
|
for (rr=row-1; rr <= row+1; rr++) {
|
|
for (cc=col-1; cc <= col+1; cc++) {
|
|
rrow=rr != -1 ? rr : ROWS-1;
|
|
ccol=cc != -1 ? cc : COLS-1;
|
|
if (rrow >= ROWS) rrow=0;
|
|
if (ccol >= COLS) ccol=0;
|
|
world[rrow][ccol]++;
|
|
}
|
|
}
|
|
world[row][col]--;
|
|
}
|
|
|