v17i061: clife - Curses based Life simulator, Part01/01

J.E. King jek5036 at ultb.isc.rit.edu
Fri Mar 22 07:03:35 AEST 1991


Submitted-by: J.E. King <jek5036 at ultb.isc.rit.edu>
Posting-number: Volume 17, Issue 61
Archive-name: clife/part01

This is called clife, or a curses implementation life simulator. It
simulates the life 'function' which is described in the manual page.
Basically it could be thought of as a game, but it isn't.  That's 
why the manual page is under clife.6.

Jim King, (jek5036 at ultb.isc.rit.edu)

-- cut here -- cut here -- cut here -- cut here -- cut here -- cut here --
#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./Makefile`
then
echo "writing ./Makefile"
cat > ./Makefile << '\End\Of\Shar\'
CFLAGS        = -O
DEST	      = .
MANDEST       = /usr/man/man6
EXTHDRS	      = /usr/include/curses.h \
		/usr/include/sgtty.h \
		/usr/include/signal.h \
		/usr/include/stdio.h \
		/usr/include/sys/ioctl.h \
		/usr/include/sys/ttychars.h \
		/usr/include/sys/ttydev.h \
		/usr/include/sys/ttyio.h \
		/usr/include/time.h
HDRS	      =
LDFLAGS	      = -O
LIBS	      = -lcurses -ltermlib
LINKER	      = cc
MAKEFILE      = Makefile
OBJS	      = clife.o
PRINT	      = lpr
PROGRAM	      = clife
SRCS	      = clife.c

all:		$(PROGRAM)

$(PROGRAM):     $(OBJS)
		@echo -n "Loading $(PROGRAM) ... "
		@$(LINKER) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM)
		@echo "done"

clean:;		@rm -f $(OBJS)

depend:;	@mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DEST=$(DEST)

index:;		@ctags -wx $(HDRS) $(SRCS)

install:	$(PROGRAM)
		@echo Installing $(PROGRAM) in $(DEST)
		@install -s $(PROGRAM) $(DEST)
		@echo Copying manual pages...
		@cp clife.6 $(MANDEST)
		@chmod 644 $(MANDEST)/clife.6

print:;		@$(PRINT) $(HDRS) $(SRCS)

program:        $(PROGRAM)

tags:           $(HDRS) $(SRCS); @ctags $(HDRS) $(SRCS)

update:		$(DEST)/$(PROGRAM)

$(DEST)/$(PROGRAM): $(SRCS) $(LIBS) $(HDRS) $(EXTHDRS)
		@make -f $(MAKEFILE) DEST=$(DEST) 
###
clife.o: /usr/include/signal.h /usr/include/time.h /usr/include/stdio.h \
	/usr/include/curses.h /usr/include/sgtty.h /usr/include/sys/ioctl.h \
	/usr/sys/h/ttychars.h /usr/sys/h/ttydev.h /usr/sys/h/ttyio.h \
	/usr/sys/h/sgtty.h /usr/include/sys/ttychars.h \
	/usr/include/sys/ttydev.h /usr/include/sys/ttyio.h
\End\Of\Shar\
else
  echo "will not over write ./Makefile"
fi
if `test ! -s ./clife.6`
then
echo "writing ./clife.6"
cat > ./clife.6 << '\End\Of\Shar\'
.TH clife 6
.SH Name
clife \- Life simulation using curses
.SH Syntax
.B clife
\fI[-d] [-p]\fR
.SH Description
The
.PN clife
program is a simulator which has been around for quite some time.
The screen is set up, with random 'people' on the screen.  Each
person is represented by a '*'.  The rules are simple:  If there are
three people around any given square, a person is born there.  If
there are only two people around any given square, then it does not
change.  Any other number around a square kills the person there.
.PP
The clife (which stands for curses life) simulator will produce certain
distinguishable patterns attributable to the life equation.
.SH Options
The
.PN \-d
option allows you to draw your own pattern on the screen
and run it through the simulator.  This is done by moving around the
screen with the arrow keys and using space to put a person in the
square you are currently over, or if there is a person there already,
kill it.

The
.PN \-p
option will print out information about the life cycles on the bottom
of the screen.
.SH Author
Jim King, (jek5036 at ritvax.isc.rit.edu)
\End\Of\Shar\
else
  echo "will not over write ./clife.6"
fi
if `test ! -s ./clife.c`
then
echo "writing ./clife.c"
cat > ./clife.c << '\End\Of\Shar\'
/*
 * clife.c - curses life simulator.  Translated from Pascal to C implementing
 *           curses Oct 1988 by pulsar at lsrhs, not jek5036 at ritvax.isc.rit.edu
 *
 *      V2 - Draw your own pattern then 'life' it.
 */

#include <signal.h>
#include <time.h>
#include <stdio.h>
#include <curses.h>

				/* a value of -1 will make it go forever */
				/* a value of 0 will make it exit immed. */
#define	REPSTOP		-1	/* number of repetitions before stop */

int	present[23][80],	/* screen 1 cycle ago */
	past[23][80],		/* screen this cycle */
	total,			/* total # of changes */
	icnt,			/* counter to check for repetition */
	maxrow = 22,		/* some defines to represent the screen */
	maxcol = 79,
	minrow = 0,
	mincol = 0,
	pri = 0,		/* flag for printing stats on bottom line */
	draw = 0,		/* flag for drawing your own screen */
	i, j, k,		/* loop counters */
	cycle,			/* current cycle # */
	changes,		/* # of changes this cycle (live + die) */
	die,			/* number of deaths this cycle */
	live;			/* number of births this cycle */

WINDOW	*mns,				/* Main Screen */
	*info;				/* Bottom line */

/*
 * cleanup - cleanup then exit
 */

cleanup()
{
	move(23, 0);		/* go to bottom of screen */
	refresh();		/* update cursor */
	exit(1);		/* exit */
}

/*
 * initialize - init windows, variables, and signals
 */

initialize()
{
	srandom(getpid());	/* init random seed */
	initscr();		/* init curses */
	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);
	wprintw(info, "Life V2 by Jim King (pulsar at lsrhs)");
	wrefresh(info);
	sleep(3);
	if (!draw) {		/* if no draw, make random pattern */
		for (j = 0; j < maxrow; j++) {
			for (k = 0; k < maxcol; k++) {
				present[j][k] = random()%2;
				if (present[j][k] == 1) changes++, live++;
			}
		}
	}
}

/*
 * makscr - make your own screen using arrow keys and space bar
 */

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");
	wrefresh(info);
	curx = cury = 1;
	wmove(mns, cury-1, curx-1); wrefresh(mns);
	noecho(); crmode();
	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
 */

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();
}

/*
 * print - updates the screen according to changes from past to present
 */

print()		/* Updates the screen, greatly improved using curses */
{
	if (pri) {
		wmove(info, 0, 0);
		total += changes;
		wprintw(info, "Cycle %d | %d changes: %d died and %d born & %d total changes", ++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, "*");
			} else if (present[j][k] != past[j][k] && present[j][k] == 0) {
				wmove(mns, j, k);
				wprintw(mns, " ");
			}
		}
	}
	if (pri) wrefresh(info);
	wrefresh(mns);
}

/*
 * main - main procedure
 */

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]);
					exit(1);
			}
		}
	}

	if (draw)
		printf("User-built screen\n");
	if (pri)
		printf("Print statistics\n");

	sleep(2);

	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();
	}
}
\End\Of\Shar\
else
  echo "will not over write ./clife.c"
fi
echo "Finished archive 1 of 1"
exit

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent at sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent at uunet.uu.net.



More information about the Comp.sources.misc mailing list