242 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			242 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* 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 <sys/types.h>
 | 
						|
#include <signal.h>
 | 
						|
#include <time.h>
 | 
						|
#include <curses.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <stdio.h>
 | 
						|
 | 
						|
#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();
 | 
						|
  }
 | 
						|
}
 |