[comp.sources.games] v08i085: life - Conway's simulation of birth and death, Part01/02

billr@saab.CNA.TEK.COM (Bill Randle) (02/07/90)

Submitted-by: local%rupley.UUCP@cs.arizona.edu
Posting-number: Volume 8, Issue 85
Archive-name: life/Part01

[From the author...]
[[There appears to be no "life", the Conway population simulation, in
comp.sources.{games|misc|unix}.  An X version was posted recently to
comp.sources.x.  If only for historical interest, perhaps there should
be one that works on standard terminals.  This version is adapted from
code written by Leor Zolman, the creator of BDS C. It compiles and runs
under SysV or BSD, using curses or termcap.

John Rupley
rupley!local@cs.arizona.edu]]

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 2)."
# Contents:  README MANIFEST Makefile.bsd life.1 life.c life.c.zolman
#   life.sh patterns patterns/oscpuls.4 patterns/squarex xpatterns
# Wrapped by billr@saab on Tue Feb  6 09:40:19 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(2716 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThere appears to be no "life", the Conway population simulation, in
Xcomp.sources.{games|misc|unix}.  An X version was posted recently to
Xcomp.sources.x.  If only for historical interest, perhaps there should
Xbe one that works on standard terminals.  This version is adapted from
Xcode written by Leor Zolman, the creator of BDS C. It compiles and runs
Xunder SysV or BSD, using curses or termcap.
X
XThe original Leor Zolman code is in the file life.c.zolman (posted with
Xhis permission).  It is from the late '70's and ran on 8080 hardware.
X
XThe algorithm for tracking evolution of the population is primitive, 
Xbut a more elaborate one seems unnecessary, since 90+ percent of real 
Xtime is spent in output.
X
XPatterns either can be entered interactively or read from a file.  A 
Xstarter set of data files is supplied. Some of these, in the directory 
X./xpatterns, are from the X posting by Mark Moraes; the remainder, in 
X./patterns, were resurrected from an 8080 assembler version of life, 
Xthat ran under N* DOS (a pre-CP/M OS; dumping a hard-sectored 5-1/4 inch
Xfloppy, and then decoding the pattern storage, was interesting).
X
XThe pattern evolves in a space (160 x 50 cells) larger than a 
Xtraditional (80 x 24) terminal screen.  The display can be set to track 
Xthe center or a corner of a pattern as it develops, or it can be set to 
Xshow a fixed sub-region of the full pattern space.
X
X
XTo compile and test under SysV or BSD, run "make" after editing the 
Xappropriate Makefile.{sys5|bsd}. Curses is the default and is 
Xrecommended.  If curses fails, try the termcap option:
X	make -f Makefile.??? XOPT=-DTCAP 
XThe only somewhat non-standard system routine is getopt(3). 
X
XA shell script, life.sh, is a wrapper for life with options for listing
Xinput patterns and running lists of patterns.  For testing, the defaults for
Xlife.sh are set for the directory structure created by unsharing.  Thus,
Xafter compilation, for a demo running all pattern files:
X	life.sh -m		#display list of pattern files
X	life.sh -a -g25 	#run 25 cycles of each pattern
X
XThe pattern space is wrapped -- edge to opposite edge, corner to other
Xcorners.  To watch the wrapping, compile with a space smaller than the
Xdisplay screen, e.g., 10 x 20, and run a moving pattern, e.g., glider,
Xwith a fixed display option, e.g., -c0:
X	life1020 -c0 ./patterns/glider
XA 10 x 20 compilation is included in the Makefile, as the target "life1020".  
X
XPlease send bug reports, comments, new favorite patterns, etc., to:
X
XJohn Rupley
X uucp: ..{cmcl2 | hao!ncar!noao}!arizona!rupley!local
X internet: rupley!local@cs.arizona.edu
X (H) 30 Calle Belleza, Tucson AZ 85716 - (602) 325-4533
X (O) Dept. Biochemistry, Univ. Arizona, Tucson AZ 85721 - (602) 621-3929
X
END_OF_FILE
if test 2716 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(1695 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X MANIFEST                   1	This shipping list
X Makefile.bsd               1	
X Makefile.sys5              2	
X README                     1	
X life.1                     1	
X life.c                     1	
X life.c.zolman              1	
X life.sh                    1	
X patterns                   1	
X patterns/center            2	
X patterns/glider            2	
X patterns/gliders.1         2	
X patterns/gliders.2         2	
X patterns/gliders.3         2	
X patterns/gliders.4         2	
X patterns/gliders.5         2	
X patterns/glidgun           2	
X patterns/line.horiz        2	
X patterns/line.vert         2	
X patterns/newgun            2	
X patterns/nonterm.1         2	
X patterns/nonterm.2         2	
X patterns/nonterm.3         2	
X patterns/nonterm.4         2	
X patterns/oscpuls.1         2	
X patterns/oscpuls.2         2	
X patterns/oscpuls.3         2	
X patterns/oscpuls.4         1	
X patterns/oscpulsb.1        2	
X patterns/oscpulsb.2        2	
X patterns/oscpulsb.3        2	
X patterns/oscpulsb.4        2	
X patterns/puffera           2	
X patterns/square            2	
X patterns/squarex           1	
X patterns/switch            2	
X xpatterns                  1	
X xpatterns/explodes         2	
X xpatterns/exploding.1      2	
X xpatterns/exploding.2      2	
X xpatterns/exploding.3      2	
X xpatterns/exploding.4      2	
X xpatterns/exploding.5      2	
X xpatterns/glider_l-d       2	
X xpatterns/glider_l-u       2	
X xpatterns/glider_r-d       2	
X xpatterns/glider_r-u       2	
X xpatterns/long_life_d      2	
X xpatterns/long_life_l      2	
X xpatterns/long_life_r      2	
X xpatterns/long_life_u      2	
END_OF_FILE
if test 1695 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'Makefile.bsd' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile.bsd'\"
else
echo shar: Extracting \"'Makefile.bsd'\" \(398 characters\)
sed "s/^X//" >'Makefile.bsd' <<'END_OF_FILE'
XXOPT =				# for command-line extra options 
XCFLAGS = -O -DBSD $(XOPT)
XLDFLAGS =
XLIBES = -lcurses -ltermcap
XTESTFLAGS = -c5 -g30
XTEST= gliders.4
XPATDIR= ./patterns
X
Xtest:	life
X	time life $(TESTFLAGS) $(PATDIR)/$(TEST)
X
Xlife:	life.c
X	cc life.c $(CFLAGS) $(LDFLAGS) $(LIBES) -o life
X
Xlife1020:	life.c
X	cc life.c $(CFLAGS) -DXMAX=10 -DYMAX=20 $(LDFLAGS) $(LIBES) -o life1020
X
Xclean:
X	rm life life1020
X
END_OF_FILE
if test 398 -ne `wc -c <'Makefile.bsd'`; then
    echo shar: \"'Makefile.bsd'\" unpacked with wrong size!
fi
# end of 'Makefile.bsd'
fi
if test -f 'life.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'life.1'\"
else
echo shar: Extracting \"'life.1'\" \(3701 characters\)
sed "s/^X//" >'life.1' <<'END_OF_FILE'
X.TH LIFE 1
X.SH LIFE
Xlife \- Conway's simulation of life
X.SH SYNOPSIS
X.B life 
X[
X.B -g
Xnumber,
X.B -o
Xoutput file,
X.B -c 
Xnumber
X]
X[\ data\ file\ ]
X.SH DESCRIPTION
XConway's  
X.B Life
Xsimulates population changes.
XA starting population is established as a pattern of filled cells in
Xa matrix of cells,
Xwhich is changed according to rules that relate the next generation
Xto the current one.
X.B Births 
X-- an empty cell of the matrix is filled if the number of filled
Xsurrounding cells is exactly three.
X.B Survivals
X-- a filled cell survives if the number of filled surrounding cells is
Xeither two or three.
XFilled cells with surroundings outside the limits ``die'' and become empty.
X.PP
X.in +3
X``Note that the Universe is a toroid; 
Xi.e, the left extreme is adjacent to the
Xright extreme, the top is adjacent to the bottom, and each corner is
Xadjacent to each other corner. 
XIn other words, there ARE NO EXTREMES!!
XOr, in a more physical illustration: 
Xif I could take a peek straight ahead
Xthrough the magical eyepiece of an infinitely powerful telescope, I'd be
Xable to see the back of my brain-damaged head....that is, of course,
Xassuming no galaxies or cats get in the way.''
X.in +35
XLeor Zolman
X.in -38
X.PP
XA fairly large matrix is needed to hold developing patterns, 
Xso interesting ones are not destroyed by truncation or, in this program,
Xby wrapping.
XOnly a portion of the matrix (the default size is 50 x 160) can be
Xdisplayed on a 24 x 80 terminal screen.
XThus, the 
X.B -c
Xoptions should be used to track a region of the evolving pattern, or to
Xfix on a selected region of the matrix.
X.SS "COMMAND LINE OPTIONS"
X.PP
X.TP 5
X\fB\-g number\fP		life ends after ``number'' generations
X.TP 5
X\fB\-o file\fP		copy pattern to ``file''
XAll of the pattern for each generation is copied to the file
Xspecified by the option argument.
XBlank regions outside the rectangle bounding the pattern are not copied.
X.TP 5
X\fB\-c number\fP		code for pattern display 
XThe portion of the pattern matrix displayed on a smaller screen is
Xspecified by a control code (default 5 = track center of pattern):
X.PP
X.in +3
X0	display fixed on center of input pattern.
X.sp
X1\-4	fixed at quadrant I\-IV of input pattern.
X.sp
X5	tracks center of evolving pattern.
X.sp
X6\-9	tracks quadrant I\-IV of evolving pattern.
X.in +5
X.sp
X(quadrants numbered counterclockwise from upper right)
X.in -8
X.PP
XStdin is read if no input file is given on the command line.
X.PP
X.B Life 
Xmay have been wrapped in a shell script, giving additional options, 
Xusage of which perhaps may be displayed by the option 
X.B -z
Xor
X.B -?.
X.SH FILES
XA set of pattern files is supplied for use as input to 
X.B Life.
X.SH AUTHOR
XThe simulation was invented by John Conway.
X.sp
XThis version is based upon code written by Leor Zolman, 
X``to exemplify PROPER use of 
X.B goto 
Xstatements in C programs!''
X.sp
XThe original code dates to the early days of BDS C, the 8080, 
Xand before Apple had produced the glint in IBM's eye that lead to 
Xconception of the PC.
XBDS C lacked some features of K&R C, but it was FAST in both 
Xcompilation and execution.
XBDS is an acronym for Brain Damaged Software.
X.sp
XModifications for UNIX with curses, and a bit more, by:
X.br
XJohn Rupley
X uucp: ..{cmcl2 | hao!ncar!noao}!arizona!rupley!local
X.br
X internet: rupley!local@cs.arizona.edu
X.SH BUGS
XCompared even to 8080 assembly versions, 
Xthis generic UNIX version is slow, because it is output-bound.
X.B Curses 
Xis somewhat better than line output under a
X.B termcap
Xterminal specification.
X.sp
XThe pattern display is one line and one column smaller than the terminal
Xscreen.
XThe last line is used for status comments;
Xthe last column is kept blank because of possible line-wrap problems.
X
END_OF_FILE
if test 3701 -ne `wc -c <'life.1'`; then
    echo shar: \"'life.1'\" unpacked with wrong size!
fi
# end of 'life.1'
fi
if test -f 'life.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'life.c'\"
else
echo shar: Extracting \"'life.c'\" \(24371 characters\)
sed "s/^X//" >'life.c' <<'END_OF_FILE'
X/*-
X * "LIFE" 
X *
X * The simulation invented by John Conway.
X *
X * This version written by Leor Zolman to exemplify PROPER use of "goto"
X * statements in C programs! 
X *
X * Note that the Universe is a toroid; i.e, the left extreme is adjacent to the
X * right extreme, the top is adjacent to the bottom, and each corner is
X * adjacent to each other corner. In other words, there ARE NO EXTREMES !!
X * Or, in a more physical illustration: If I could take a peek straight ahead
X * through the magical eyepiece of an infinitely powerful telescope, I'd be
X * able to see the back of my brain-damaged head....that is, of course,
X * assuming no galaxies or cats get in the way. 
X *							Leor Zolman
X */
X
X/*-
X * The original code dates to the early days of BDS C, the 8080, 
X * and before Apple had produced the glint in IBM's eye that lead to 
X * conception of the PC.
X *
X * BDS C lacked some features of K&R C, but it was FAST, in both 
X * compilation and execution.
X *
X * 3/1/89 -- Modifications for UNIX with curses or termcap, and a bit more.
X *
X * John Rupley
X *  uucp: ..{cmcl2 | hao!ncar!noao}!arizona!rupley!local
X *  internet: rupley!local@cs.arizona.edu
X *  (H) 30 Calle Belleza, Tucson AZ 85716 - (602) 325-4533
X */
X
X#include	<curses.h>
X
X#if defined(TCAP) && !defined(BSD)
X#include	<term.h>
X#endif				/* TCAP && !BSD */
X
X#include	<signal.h>
X
X#ifdef BSD
X/*-
X * SysV compatible getopt(3) needed. There are versions in comp.sources.unix.
X *
X * Some versions of curses lack pad structures, which allow somewhat
X * simpler handling of windows larger than the display screen. 
X */
X#define		NOPAD
X#include	<ctype.h>
X#include	<strings.h>
X#define strrchr	rindex
X#else				/* BSD */
X#include	<string.h>
Xvoid            exit();
Xunsigned        sleep();
X#endif				/* BSD */
X
X#define PAD
X#if defined(TCAP) || defined(NOPAD)
X#undef PAD
X#endif				/* TCAP || NOPAD */
X
X/*-
X * Put pretty high limits on size of cell array, so interesting patterns 
X * are not destroyed by truncation or wrapping; keep default smaller 
X * than 2^15, for compilers that limit size of aggregates.  
X */
X#ifndef XMAX
X#define XMAX	50
X#endif				/* XMAX */
X#ifndef YMAX
X#define YMAX	160
X#endif				/* YMAX */
Xchar            cell[XMAX][YMAX];	/* the universe matrix */
X
X/*-
X * To see how the toroid works, try reducing XMAX and YMAX 
X * to around 10 or 20.			 
X */
X
X/*-
X * [XY]SIZE determine the size of the part of the cell array displayed
X * on the terminal; values are set according to terminfo, in curse_on(),
X * to the size of the display screen.
X */
Xint             XSIZE, YSIZE;
X
X/*-
X * If the cell array is larger than the terminal screen, the part selected
X * for display is determined by the value of "center"; the display can be fixed 
X * at a point of the initial pattern, or it can track the evolving pattern;
X * the value of center defaults to TRACK_CENTER or it can be set from the
X * command line (-cn option);
X */
X
X/*-				/* display		initial pattern */
X/*-				/* -----   fixed at   --------------- */
X#define FIX_CENTER	0	/* center 		center	 */
X#define FIX_UPPER_R	1	/* 0,COLS-1		minx,maxy */
X#define FIX_UPPER_L	2	/* 0,0			minx,miny */
X#define FIX_LOWER_L	3	/* LINES-1,0		maxx,miny */
X#define FIX_LOWER_R	4	/* LINES-1,COLS-1	maxx,maxy */
X
X/*-				/* display		current pattern */
X/*-				/* -------   tracks     --------------- */
X#define TRACK_CENTER	5	/* center 		center	 */
X#define TRACK_UPPER_R	6	/* 0,COLS-1		minx,maxy */
X#define TRACK_UPPER_L	7	/* 0,0			minx,miny */
X#define TRACK_LOWER_L	8	/* LINES-1,0		maxx,miny */
X#define TRACK_LOWER_R	9	/* LINES-1,COLS-1	maxx,maxy */
X
X
X#define SLEEPTIME	0	/* Delay after each pattern display */
X#define BOREDOM_THRESHOLD 5	/* This is how many generations are allowed
X				 * to pass without a population change before
X				 * Divine intervention is called for. */
X
X/*
X * Control values read as command line options
X */
Xunsigned        gen_limit;	/* quit program after gen_limit iterations */
X				/* set by command line option, -gn */
Xint             center;		/* control of display-pattern correspondence */
X				/* set by command line option, -cn */
XFILE           *infile;		/* input stream (stdin default) */
X				/* loop over list of command line arguments */
Xchar           *infile_name;
XFILE           *outfile;	/* output stream (in __addition__ to stdout); */
Xchar           *outfile_name;	/* set by command line option, -ofile */
X
X/*
X * Control values set internally. 
X */
Xint             quitflag;	/* set by SIGINT in signal handler die() */
Xint             adjp_flag;	/* set if adjust_pattern() shifts pattern */
Xint             doneflag;	/* set if stasis = no change in pattern */
Xunsigned        boring;		/* count of how many generations go by
X				 * without population change	 */
Xunsigned        pop, gen;	/* current population and generation	 */
Xint             minx, maxx, miny, maxy;	/* values for pattern bounds */
Xint             dminx, dmaxx, dminy, dmaxy;	/* and for pattern display */
Xint             x_offset, y_offset;
X
X/*
X * Curses structures. 
X */
X#ifdef TCAP
Xchar           *CLEARS;
X#else				/* TCAP */
X#ifdef PAD
XWINDOW         *padwin;		/* full pattern (XMAX*YMAX) display info */
X#endif				/* PAD */
XWINDOW         *commentwin;	/* one line comment given at screen bottom */
X#endif				/* TCAP */
X
X/*
X * The main driving routine, to accept initial population configurations and
X * display their evolution according to a proximity-based formula. 
X */
X
Xmain(argc, argv)
X	int             argc;
X	char          **argv;
X{
X	void            startup();
X	void            quitit();
X	void            curse_on();
X	int             c;
X	char            string[BUFSIZ];
X
X	startup(argc, argv);
X	curse_on();
X	for (;;) {
X		if (setup())
X			quitit();
X		while (pop) {
X			if (quitflag)
X				quitit();
X			if (gen_limit && gen == gen_limit) {
X				sprintf(string, "Generation limit reached at %d.  Continue evolving? (y/n/q(default)) ", gen_limit);
X				c = user_query(string, "YNQ");
X				if (c == 1)
X					continue;
X				else if (c == 2)
X					break;
X				else
X					quitit();
X			}
X			if (center >= TRACK_CENTER)
X				adjp_flag = adjust_pattern(0);
X
X			dogen();/* do everything that counts */
X
X			if (boring == BOREDOM_THRESHOLD) {
X				boring++;
X				sprintf(string, "Population stable for %d generations. Continue evolving? (y(default)/n/q) ", BOREDOM_THRESHOLD);
X				c = user_query(string, "QNY");
X				if (c == 1)
X					quitit();
X				else if (c == 2)
X					break;
X				else
X					continue;
X			}
X			if (doneflag) {
X				sprintf(string, "Stasis at generation %d. Enter another pattern? (y/q(default)) ", gen);
X				c = user_query(string, "Y");
X				if (c == 1)
X					break;
X				else
X					quitit();
X			}
X			if (!pop && gen) {
X				sprintf(string, "Life ends at generation %d. Enter another pattern? (y/q(default)) ", gen);
X				c = user_query(string, "Y");
X				if (c == 1)
X					break;
X				else
X					quitit();
X			}
X		}
X	}
X}
X
X/* Signal handler -- set flag for exit. */
X
Xint
Xdie()
X{
X	quitflag = 1;
X	signal(SIGINT, die);
X	return;
X}
X
X/* Initialize the cell matrix to all dead. */
X
Xvoid
Xxclear()
X{
X	char           *memset();
X
X	memset(&cell[0][0], '\0', (XMAX * YMAX));
X}
X
X/* Clean up at exit. */
X
Xvoid
Xquitit()
X{
X	void            display_comment();
X
X	display_comment("");
X#ifdef TCAP
X	fflush(stdout);
X#else				/* TCAP */
X	endwin();
X#endif				/* TCAP */
X	if (outfile)
X		fprintf(outfile, "\f");
X	exit(0);
X}
X
X/* Set-up termcap or curses. */
X
Xvoid
Xcurse_on()
X{
X#ifdef TCAP
X	int             tgetent();
X	int             tgetnum();
X	char           *getenv();
X	char           *tgetstr();
X	char           *tbufptr;
X	char           *tptr;
X	char           *term;
X	static char     tbuf[BUFSIZ];
X	static char     t[1024];
X
X	signal(SIGINT, die);
X	tbufptr = tbuf;
X	tptr = t;
X	term = getenv("TERM");
X	tgetent(tptr, term);
X	CLEARS = tgetstr("cl", &tbufptr);
X	XSIZE = tgetnum("li") - 1;
X	YSIZE = tgetnum("co") - 1;
X	XSIZE = XSIZE >= XMAX ? (XMAX - 1) : XSIZE;
X	YSIZE = YSIZE >= YMAX ? (YMAX - 1) : YSIZE;
X	if (!term || !CLEARS || XSIZE < 1 || YSIZE < 1) {
X		fprintf(stderr, "life: failure in terminfo setup\n");
X		exit(1);
X	}
X	fputs(CLEARS, stdout);
X#else				/* TCAP */
X	signal(SIGINT, die);
X	initscr();
X	XSIZE = (LINES - 1) >= XMAX ? (XMAX - 1) : (LINES - 1);
X	YSIZE = (COLS - 1) >= YMAX ? (YMAX - 1) : (COLS - 1);
X	commentwin = newwin(1, YSIZE, XSIZE, 0);
X#ifdef PAD
X	padwin = newpad(XMAX, YMAX);
X#endif				/* PAD */
X#endif				/* TCAP */
X}
X
X/* Get user respose. */
X
Xint
Xuser_query(string, response)
X	char           *string, *response;
X{
X	void            display_comment();
X	int             c;
X	char           *ptr;
X
X	display_comment(string);
X	if (isatty(fileno(infile))) {
X#ifdef TCAP
X		c = getchar();
X#else				/* TCAP */
X		c = getch();	/* nice to need no newline */
X#endif				/* TCAP */
X		c = toupper(c);
X		if ((ptr = strrchr(response, c)) != (char *) 0)
X			return (ptr - response + 1);
X		else
X			return 0;
X	} else {
X		return 0;
X	}
X}
X
X/* Get command line information and user input, if appropriate. */
X
Xvoid
Xstartup(xargc, xargv)
X	int             xargc;
X	char          **xargv;
X{
X	extern char    *optarg;
X	extern int      optind;
X	int             getopt();
X	int             c;
X	static char     usage[2000] =
X	{
X	 "\n\
Xusage: life [-options] [file]\n\
Xread stdin if no file\n\
Xoptions:\n\
X -g#  exit life after # generations\n\
X -c#  control code for pattern-display correspondence\n\
X\t0 = display center fixed at center of _input_ pattern\n\
X\t[1-4] = display fixed at quadrant I-IV of _input_ pattern\n\
X\t5 = display center tracks center of evolving pattern (default)\n\
X\t[6-9] = display tracks quadrant I-IV of evolving pattern\n\
X\t\t(quadrants numbered counter-clockwise from upper right)\n\
X -ofile  copy all of pattern for each generation to file\n\
X\n"
X	};
X
X	center = TRACK_CENTER;
X	gen_limit = 0;
X	infile = (FILE *) 0;
X	while ((c = getopt(xargc, xargv, "g:c:o:?z")) != EOF) {
X		switch (c) {
X		case 'g':
X			if (!(gen_limit = atoi(optarg))) {
X				fprintf(stderr, "Bad value for gen_limit = %s\n", optarg);
X				fprintf(stderr, usage);
X				exit(1);
X			}
X			break;
X		case 'c':
X			if ((center = atoi(optarg)) >= 10) {
X				fprintf(stderr, "Bad value for center = %s\n", optarg);
X				fprintf(stderr, usage);
X				exit(1);
X			}
X			break;
X		case 'o':
X			if ((outfile = fopen(optarg, "w")) == (FILE *) 0) {
X				fprintf(stderr, "Can't open output file %s\n", optarg);
X				fprintf(stderr, usage);
X				exit(1);
X			}
X			outfile_name = optarg;
X			break;
X		case '?':	/* fall through */
X		case 'z':	/* fall through */
X		default:	/* getopt(3) defaults to '?' */
X			fprintf(stderr, usage);
X			exit(1);
X		}
X	}
X	if (optind < xargc) {
X		if ((infile = fopen(xargv[optind], "r")) == (FILE *) 0) {
X			fprintf(stderr, "Can't open file %s\n", xargv[optind]);
X			fprintf(stderr, usage);
X			exit(1);
X		}
X		infile_name = xargv[optind];
X	} else {
X		infile = stdin;
X		infile_name = "stdin";
X	}
X}
X
X/* Get initial pattern from user. */
X
Xint
Xsetup()
X{
X	void            xclear();
X	void            find_offset();
X	void            display();
X	char           *fgets();
X	int             y;
X	int             length;
X	char            string[BUFSIZ], *ptr;
X#ifdef PAD
X	int             i, j;
X#endif				/* PAD */
X
X#ifdef TCAP
X	fputs(CLEARS, stdout);
X#else				/* TCAP */
X	clear();
X	refresh();
X#ifdef PAD
X	def_prog_mode();
X	reset_shell_mode();
X#endif				/* PAD */
X#endif				/* TCAP */
X	xclear();
X	fprintf(stdout, "\t *** BDS Life ***\n\n");
X	if (isatty(fileno(infile))) {
X		fprintf(stdout, "Enter initial configuration (single period to end):\n\n");
X	}
X	adjp_flag = 0;
X	boring = 0;
X	pop = gen = 0;
X	y = minx = maxx = miny = maxy = 0;
X	while ((fgets(string, sizeof(string), infile) > 0) && *string != '.') {
X		if ((length = strlen(string)) > (YMAX)) {
X			string[YMAX - 1] = '\0';
X			fprintf(stdout, "Truncated to %d chars\n", YMAX);
X		} else {
X			/* fgets() retains \n */
X			string[length - 1] = '\0';
X		}
X		ptr = string;
X		y = 0;
X		while (*ptr) {
X			if (*ptr++ != ' ') {
X				cell[maxx][y] = 10;
X				++pop;
X			}
X			++y;
X		}
X		--y;
X		if (y > maxy)
X			maxy = y;
X		++maxx;
X		if (maxx >= XMAX) {
X			fprintf(stdout, "Limit of %d lines reached\n", XMAX);
X			break;
X		}
X	}
X	--maxx;
X	if (!pop)
X		return 1;
X	adjust_maxmin();	/* find pattern in cell[][] */
X	adjust_pattern(1);	/* force centering of pattern in cell[][] */
X	find_offset();		/* find correspondence pattern <--> display */
X#ifndef TCAP
X#ifdef PAD
X	reset_prog_mode();
X	wclear(padwin);		/* clean up pattern pad, and blank screen */
X	prefresh(padwin, 0, 0, 0, 0, XSIZE, YSIZE);
X	for (i = minx; i <= maxx; i++) {	/* copy cell[][] to pad */
X		for (j = miny; j <= maxy; j++)
X			if (cell[i][j]) {
X				mvwaddch(padwin, i, j, '*');
X			}
X	}
X#endif				/* PAD */
X	clear();		/* clean up stdscr */
X	refresh();
X#endif				/* TCAP */
X	display();
X	gen++;
X	sleep((unsigned) (SLEEPTIME ? 2 * SLEEPTIME : 2));
X	return 0;
X}
X
X/* Display comment line at bottom of screen. */
X
Xvoid
Xdisplay_comment(comm_string)
X	char           *comm_string;
X{
X#ifdef TCAP
X	fprintf(stdout, "\r%s", comm_string);
X	fflush(stdout);
X#else				/* TCAP */
X	werase(commentwin);
X	wmove(commentwin, 0, 0);
X	wprintw(commentwin, comm_string);
X/* 	touchwin(commentwin); */
X	wrefresh(commentwin);
X#endif				/* TCAP */
X	if (outfile)
X		fprintf(outfile, "\n%s\n", comm_string);
X}
X
X/* Display the current generation. */
X
Xvoid
Xdisplay()
X{
X	void            quitit();
X	void            display_comment();
X	char            string[BUFSIZ];
X	int             i, j;
X#ifdef TCAP
X	int             x_line;
X	int             del_x, del_y, jmaxy;
X#endif				/* TCAP */
X
X	if (quitflag)
X		quitit();
X#ifdef TCAP
X	fputs(CLEARS, stdout);
X	fprintf(stdout, "\r");
X	x_line = 0;
X	del_x = dminx - x_offset;
X	del_y = dminy - y_offset;
X	for (j = 0; j < del_x; j++) {
X		fprintf(stdout, "\n");
X		x_line++;
X	}
X	for (i = dminx; i <= dmaxx; i++) {
X		for (j = 0; j < del_y; j++) {
X			fprintf(stdout, "%c", ' ');
X		}
X		for (jmaxy = dmaxy; jmaxy >= dminy; jmaxy--) {
X			if (cell[i][jmaxy])
X				break;
X		}
X		for (j = dminy; j <= jmaxy; j++) {
X			fprintf(stdout, "%c",
X				cell[i][j] ? '*' : ' ');
X		}
X		x_line++;
X		fprintf(stdout, "\n");
X	}
X	for (i = x_line; i < XSIZE; i++)
X		fprintf(stdout, "\n");
X#else				/* TCAP */
X#ifdef PAD
X	clearok(curscr, TRUE);
X/* 	touchwin(padwin); */
X	prefresh(padwin, dminx, dminy, dminx - x_offset, dminy - y_offset,
X		 dmaxx - x_offset, dmaxy - y_offset);
X#else				/* PAD */
X	clear();
X	for (i = dminx; i <= dmaxx; i++) {
X		for (j = dminy; j <= dmaxy; j++)
X			if (cell[i][j])
X				mvaddch(i - x_offset, j - y_offset, '*');
X	}
X/* 	touchwin(stdscr); */
X	refresh();
X#endif				/* PAD */
X#endif				/* TCAP */
X	if (outfile) {
X		for (i = minx; i <= maxx; i++) {
X			fprintf(outfile, "\n");
X			for (j = miny; j <= maxy; j++)
X				fprintf(outfile, "%c",
X					cell[i][j] ? '*' : ' ');
X		}
X	}
X	sprintf(string, "%04d   %03d  %s", gen, pop, infile_name);
X	display_comment(string);
X	if (SLEEPTIME)
X		sleep((unsigned) SLEEPTIME);
X}
X
X/*-
X * Set delimiters of region of pattern = cell array to be displayed, 
X * and set offset values used for matching cell pattern to screen display.
X *
X * Globals to be set before function invocation:
X * minx, miny, maxx, maxy = lower and upper limits of x,y coords of
X * active region of pattern;
X * XSIZE, YSIZE = upper bounds of screen (origin at 0,0).
X *
X * Globals set within function:
X * dminx, dminy, dmaxx, dmaxy = lower and upper limits of x,y coords of
X * __sub__region of pattern that is copied to display;
X * x_offset, y_offset = values subtracted from pattern coordinates, 
X * to give display coordinates.
X */
X
Xvoid
Xfind_offset()
X{
X	void            expandx(), expandy();
X	void            quitit();
X	void            find_offset();
X	int             ax, ay;
X	int             xlim, ylim;
X	int             xpat, ypat;
X	int             dx, dy;
X	int             xend, yend;
X	int		hold_the_center;
X
X	xlim = XSIZE - 1;
X	ylim = YSIZE - 1;
X	xend = XMAX - 1;
X	yend = YMAX - 1;
X	xpat = maxx - minx;
X	ypat = maxy - miny;
X	dx = xlim - xpat;
X	dy = ylim - ypat;
X	ax = xlim - maxx;
X	ay = ylim - maxy;
X	switch (center) {
X	case FIX_CENTER:
X		/* 
X		 * Not nice, but need dmax - dmin == lim to get full screen
X		 * display for FIXed-display options; for these, 
X		 * find_offset() is entered only once, at gen = 0, and
X		 * after pattern has been centered by pattern_adjust(). 
X		 */
X		x_offset = minx - dx / 2;
X		y_offset = miny - dy / 2;
X		expandx(xend, xlim);
X		expandy(yend, ylim);
X		while (dmaxx - dminx < xlim) {
X			if (dminx)
X				--dminx;
X			else if (dmaxx - dminx < xlim && dmaxx < xend)
X				++dmaxx;
X		}
X		while (dmaxy - dminy < ylim) {
X			if (dminy)
X				--dminy;
X			else if (dmaxy - dminy < ylim && dmaxy < yend)
X				++dmaxy;
X		}
X		return;
X	case TRACK_CENTER:
X		x_offset = minx - dx / 2;
X		y_offset = miny - dy / 2;
X		break;
X	case FIX_UPPER_L:
X	case TRACK_UPPER_L:
X		x_offset = minx;
X		y_offset = miny;
X		break;
X	case FIX_LOWER_L:
X	case TRACK_LOWER_L:
X		x_offset = -ax;
X		y_offset = miny;
X		break;
X	case FIX_UPPER_R:
X	case TRACK_UPPER_R:
X		x_offset = minx;
X		y_offset = -ay;
X		break;
X	case FIX_LOWER_R:
X	case TRACK_LOWER_R:
X		x_offset = -ax;
X		y_offset = -ay;
X		break;
X	default:
X		fprintf(stderr, "Impossible value of center = %d\n", center);
X		quitit();
X	}
X	expandx(xend, xlim);
X	expandy(yend, ylim);
X
X	/*
X	 * Low limits (eg testing toroidal wrapping), with YMAX ~ YSIZE <
X	 * COLS, can give problems when shifting pattern to corners -- so do
X	 * below for FIXed displays, to center poor off-center displays;
X	 */
X	if (center < TRACK_CENTER) {
X		if (dmaxx - dminx < xlim || dmaxy - dminy < ylim) {
X			hold_the_center = center;
X			center = FIX_CENTER;
X			find_offset();
X			center = hold_the_center;
X		}
X	}
X}
X
Xvoid
Xexpandx(xend, xlim)
X	int             xend, xlim;
X{
X	dminx = minx;
X	while (dminx && dminx - x_offset > 0)
X		dminx--;
X	while (dminx - x_offset < 0)
X		dminx++;
X	dmaxx = maxx;
X	while (dmaxx < xend && dmaxx - x_offset < xlim)
X		dmaxx++;
X	while (dmaxx - x_offset > xlim)
X		dmaxx--;
X}
X
Xvoid
Xexpandy(yend, ylim)
X	int             yend, ylim;
X{
X	dminy = miny;
X	while (dminy && dminy - y_offset > 0)
X		dminy--;
X	while (dminy - y_offset < 0)
X		dminy++;
X	dmaxy = maxy;
X	while (dmaxy < yend && dmaxy - y_offset < ylim)
X		dmaxy++;
X	while (dmaxy - y_offset > ylim)
X		dmaxy--;
X}
X
X/* Adjust values of maxx, minx, etc; dogen() may change range of pattern. */
X
Xint
Xadjust_maxmin()
X{
X	int             ominx, ominy, omaxx, omaxy;
X
X	ominx = minx;
X	ominy = miny;
X	omaxx = maxx;
X	omaxy = maxy;
X	if (minx && prow(minx - 1))
X		minx--;
X	if (miny && pcol(miny - 1))
X		miny--;
X	if ((maxx < (XMAX - 1)) && prow(maxx + 1))
X		maxx++;
X	if ((maxy < (YMAX - 1)) && pcol(maxy + 1))
X		maxy++;
X
X	while (!prow(minx))
X		minx++;
X	while (!prow(maxx))
X		maxx--;
X	while (!pcol(miny))
X		miny++;
X	while (!pcol(maxy))
X		maxy--;
X	if (ominx != minx || ominy != miny || omaxx != maxx || omaxy != maxy)
X		return 1;
X	else
X		return 0;
X}
X
X/* Test if given column is populated. */
X
Xint
Xpcol(n)
X{
X	int             i, hi;
X
X	hi = (maxx >= (XMAX - 1)) ? XMAX - 1 : maxx + 1;
X	for (i = (minx <= 0 ? 0 : minx - 1); i <= hi; ++i)
X		if (cell[i][n])
X			return 1;
X	return 0;
X}
X
X/* Test if given row is populated. */
X
Xint
Xprow(n)
X{
X	int             i, hi;
X
X	hi = (maxy >= (YMAX - 1)) ? (YMAX - 1) : maxy + 1;
X	for (i = (miny <= 0 ? 0 : miny - 1); i <= hi; ++i)
X		if (cell[n][i])
X			return 1;
X	return 0;
X}
X
X
X/*-
X * Compute next generation. Algorithm used is a two-pass cuteness suggested
X * to me by Ward Christensen (he uses it on a machine-language version on a
X * 1024 character display, and it cranks out 20 generations a second at 2
X * MHz.) The algorithm uses the low order 3 bits of each 1-byte cell as a
X * neighbor count. The first pass finds all live cells and increments the
X * count of each of the 8 neighbors of such live cells. For the first pass,
X * dead cells are totally ignored. The second pass then comes along and
X * checks the counts off all cells within the active square to determine who
X * lives and who dies. Note that this is a significant improvement over the
X * "obvious" method of examining all 8 neighbors of each and every cell, dead
X * or alive, in the array. 
X *							Leor Zolman
X */
X
Xint
Xdogen()
X{
X	void            pass1();
X	int             oldpop;
X
X	oldpop = pop;
X	pass1();
X	if (pass2())
X		return 1;
X	if (pop == oldpop)
X		boring++;
X	else
X		boring = 0;
X	return 0;
X}
X
X/*-
X * In pass1, use mod(a,b) where needed to wrap pattern array into toroid:
X * 		cell[0][i] = cell[XMAX][i]
X *		cell[i][0] = cell[i][YMAX]
X * Filled cell in column 0 increments counts in column YMAX - 1, etc.
X * There are, of course, no rows cell[XMAX][i] or columns cell[i][YMAX].
X */
X
X#define mod(a,b)	((a) < 0 ? (b) + (a) : ((a) < (b) ? (a) : (a) - (b)))
X
Xvoid
Xpass1()
X{
X	int             bigflag;
X	int             i, j;
X	int             k, l;
X	char            c;
X
X	bigflag = (minx < 2 || maxx > (XMAX - 3) ||
X		   miny < 2 || maxy > (YMAX - 3));
X	for (i = minx; i <= maxx; ++i) {
X		for (j = miny; j <= maxy; ++j) {
X			c = cell[i][j];
X			if (c >= 10) {
X				if (bigflag) {
X					for (k = -1; k <= 1; k++)
X						for (l = -1; l <= 1; l++)
X							cell[mod(i + k, XMAX)][mod(j + l, YMAX)]++;
X				} else {
X					for (k = -1; k <= 1; k++)
X						for (l = -1; l <= 1; l++)
X							cell[i + k][j + l]++;
X				}
X			}
X		}
X	}
X	/* wrapped perhaps? update range of the pattern, before pass2 */
X	if (bigflag) {
X		minx = miny = 0;
X		maxx = XMAX - 1;
X		maxy = YMAX - 1;
X		adjust_maxmin();
X	}
X}
X
X/* Update pattern in cell[][] and curses struct pad at same time. */
X
Xint
Xpass2()
X{
X	void            find_offset();
X	void            display();
X	int             i, j, i1, j1, i2, j2;
X	char            c;
X
X	/* leave set if no change in pattern */
X	doneflag = 1;
X#ifdef PAD
X	/* clear pad only if pattern shifted */
X	if (adjp_flag == 1) {
X		wclear(padwin);
X		adjp_flag = 0;
X	}
X#endif				/* PAD */
X	i1 = (minx <= 0) ? 0 : (minx - 1);
X	j1 = (miny <= 0) ? 0 : (miny - 1);
X	i2 = (maxx >= (XMAX - 1)) ? (XMAX - 1) : (maxx + 1);
X	j2 = (maxy >= (YMAX - 1)) ? (YMAX - 1) : (maxy + 1);
X	for (i = i1; i <= i2; ++i) {
X		for (j = j1; j <= j2; ++j) {
X			c = cell[i][j];
X			if (c > 10) {
X				if (c < 13 || c > 14) {
X					cell[i][j] = 0;
X					pop--;
X					doneflag = 0;
X#ifdef PAD
X					mvwaddch(padwin, i, j, ' ');
X#endif				/* PAD */
X				} else {
X					cell[i][j] = 10;
X#ifdef PAD
X					mvwaddch(padwin, i, j, '*');
X#endif				/* PAD */
X				}
X			} else if (c == 3) {
X				cell[i][j] = 10;
X				pop++;
X				doneflag = 0;
X#ifdef PAD
X				mvwaddch(padwin, i, j, '*');
X#endif				/* PAD */
X			} else {
X				cell[i][j] = 0;
X			}
X		}
X	}
X	if (!pop || doneflag) {
X		return 1;
X	}
X	adjust_maxmin();
X	if (center >= TRACK_CENTER)
X		find_offset();
X	display();
X	++gen;
X	return 0;
X}
X
X/* Keep pattern away from edges, if possible. */
X
Xint
Xadjust_pattern(force_it)
X	int             force_it;
X{
X	/* 
X	 * for overflow in x and y directions;
X	 * must enter both procedures adjx() and adjy() 
X	 * on each call of adjust_pattern()
X	 */
X	if (adjx(force_it) + adjy(force_it))
X		return 1;
X	else
X		return 0;
X}
X
X/* Adjust vertical position. */
X
Xint
Xadjx(force_it)
X	int             force_it;
X{
X	int             delta, i, j;
X	int             savdelta;
X
X	delta = (((XMAX - 1) - maxx) - minx) / 2;
X	if (!delta) {
X		return 0;
X	} else if (minx == 0 || (force_it && delta > 0)) {
X		delta = delta + maxx;
X		savdelta = delta;
X		for (i = maxx; i >= minx; --i) {
X			for (j = miny; j <= maxy; ++j) {
X				cell[delta][j] = cell[i][j];
X				cell[i][j] = 0;
X			}
X			--delta;
X		}
X		minx = delta + 1;
X		maxx = savdelta;
X		return 1;
X	} else if (maxx == (XMAX - 1) || (force_it && delta < 0)) {
X		delta = delta + minx;
X		savdelta = delta;
X		for (i = minx; i <= maxx; ++i) {
X			for (j = miny; j <= maxy; ++j) {
X				cell[delta][j] = cell[i][j];
X				cell[i][j] = 0;
X			}
X			++delta;
X		}
X		maxx = delta - 1;
X		minx = savdelta;
X		return 1;
X	} else
X		return 0;
X}
X
X/* Adjust horizontal position. */
X
Xint
Xadjy(force_it)
X	int             force_it;
X{
X	int             delta, i, j;
X	int             savdelta;
X
X	delta = (((YMAX - 1) - maxy) - miny) / 2;
X	if (!delta) {
X		return 0;
X	} else if (miny == 0 || (force_it && delta > 0)) {
X		delta = delta + maxy;
X		savdelta = delta;
X		for (i = maxy; i >= miny; --i) {
X			for (j = minx; j <= maxx; ++j) {
X				cell[j][delta] = cell[j][i];
X				cell[j][i] = 0;
X			}
X			--delta;
X		}
X		miny = delta + 1;
X		maxy = savdelta;
X		return 1;
X	} else if (maxy == (YMAX - 1) || (force_it && delta < 0)) {
X		delta = delta + miny;
X		savdelta = delta;
X		for (i = miny; i <= maxy; ++i) {
X			for (j = minx; j <= maxx; ++j) {
X				cell[j][delta] = cell[j][i];
X				cell[j][i] = 0;
X			}
X			++delta;
X		}
X		maxy = delta - 1;
X		miny = savdelta;
X		return 1;
X	} else
X		return 0;
X}
END_OF_FILE
if test 24371 -ne `wc -c <'life.c'`; then
    echo shar: \"'life.c'\" unpacked with wrong size!
fi
# end of 'life.c'
fi
if test -f 'life.c.zolman' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'life.c.zolman'\"
else
echo shar: Extracting \"'life.c.zolman'\" \(8276 characters\)
sed "s/^X//" >'life.c.zolman' <<'END_OF_FILE'
X/*
X%CC1 $1.C -X 
X%CLINK $1 -S
X%DELETE $1.CRL 
X*/
X/*
X	"LIFE"
X
X	The simulation invented by John Conway
X
X	This version written by Leor Zolman to exemplify
X	PROPER use of"goto" statements in C programs!
X
X	Note that the Universe is a toroid; i.e,
X	the left extreme is adjacent to the right extreme,
X	the top is adjacent to the bottom, and each corner
X	is adjacent to each other corner.
X	In other words, there ARE NO EXTREMES !!
X	Or, in a more physical illustration: If I could
X	take a peek straight ahead through the magical
X	eyepiece of an infinitely powerful telescope,
X	I'd be able to see the back of my brain-damaged 
X	head....that is, of course, assuming no galaxies
X	or cats get in the way.
X
X*/
X
X#define CLEARS "\033*"	/* string to clear the screen on
Xyour terminal(Escape E does it
Xon mine.I strongly feel the
XHeathkit / Zenith H19 terminal is
Xthe best buy in the market for
Xserial console terminals.
XGratuitous plug ends.)
X*/
X#define TWIDTH 80	/* # of columns on your terminal	*/
X#define XSIZE 60	/* length of cell array	(max # of lines)*/
X#define YSIZE 79	/* width of cell (terminal width - 1)	*/
X/* To see how the toroid works,
X			   try reducing XSIZE and YSIZE to
X			   around 10 or 20.			*/
X
X#define BOREDOM_THRESHOLD 5  /* This is how many generations
Xare allowed to pass without a
Xpopulation change before Divine
Xintervention is called for. */
X
Xchar *gets();        /* routine to accept a line of input	*/
Xchar cell[XSIZE][YSIZE];        /* the universe matrix		*/
Xint minx, maxx, miny, maxy, pop, gen;        /* misc. variables	*/
Xchar doneflag;        /* This goes true when we want to stop	*/
Xint boring;        /* keeps count of how many generations
X			   go by without a population change	*/
Xchar center;        /* 1 = center display; 0 = left
X						   justify	*/
X/*
X	The main driving routine, to accept random initial
X	and population configurations, and display their
X	evolution according to a proximity-based formula.
X*/
X
Xmain()
X{
X	char c;
X	printf("%s\n\t *** BDS Life ***\n", CLEARS);
X	printf("\nDo you wish to have the display centered\n");
X	printf(" (and thereby slowed down a bit) (y/n) ?");
X	center = toupper(getchar()) == 'Y';
X	putchar('\n');
X
X	for (;;)
X	{
X		clear();
X		setup();
X		if (!pop)
X			break;
X		adjust();
X		display();
X		while (pop)
X		{
X			adjust();
X			dogen();
X			if (kbhit())
X			{
X				getchar();
X				printf("\nThe Wrath Of God Strikes!!!!! KA-BEEP!\7\n");
X				break;
X			}
X			display();
X			if (boring == BOREDOM_THRESHOLD)
X			{
X				boring++;
X				printf("\nNo change in population for");
X				printf(" %d ", BOREDOM_THRESHOLD);
X				printf("generations. Abort (y/n) ");
X				c = toupper(getchar());
X				putchar('\n');
X				if (c == 'Y')
X					break;
X			}
X			if (doneflag)
X				break;
X		}
X	}
X}
X
X/* Initialize the cell matrix to all dead */
X
Xclear()
X{
X	setmem(cell, (XSIZE * YSIZE), 0);
X}
X
X/* Get initial set-up from user */
X
Xsetup()
X{
X	char c;
X	int y;
X	char string[YSIZE], *ptr;
X	y = pop = gen = minx = maxx = miny = maxy = 0;
X	boring = 0;
X	printf("\nEnter initial configuration (single period to end):\n");
X
X	while (*gets(string) != '.')
X	{
X		ptr = string;
X		while (*ptr)
X		{
X			if (*ptr++ != ' ')
X			{
X				cell[maxx][y] = 10;
X				++pop;
X			}
X			++y;
X			if (y == YSIZE)
X			{
X				printf("Truncated to %d chars\n",
X				YSIZE);
X				break;
X			}
X		}
X		--y;
X		++maxx;
X		if (y > maxy)
X			maxy = y;
X		if (maxx == XSIZE)
X			break;
X		y = 0;
X	}
X	--maxx;
X}
X
X/* Display the current generation */
X
Xdisplay()
X{
X	int i, j, k, l, j9;
X	char c;
X
X	if (!pop)
X	{
X		printf("\nLife ends at %d\n", gen);
X		return;
X	}
X	if (minx && prow(minx - 1))
X		minx--;
X	if (miny && pcol(miny - 1))
X		miny--;
X	if ((maxx < (XSIZE - 1)) && prow(maxx + 1))
X		maxx++;
X	if ((maxy < (YSIZE - 1)) && pcol(maxy + 1))
X		maxy++;
X
X	while (!prow(minx))
X		minx++;
X	while (!prow(maxx))
X		maxx--;
X	while (!pcol(miny))
X		miny++;
X	while (!pcol(maxy))
X		maxy--;
X
X	puts(CLEARS);
X	if (center)
X	{
X		i = (TWIDTH - 33) / 2;
X		for (j = 0; j < i; j++)
X			putchar(' ');
X	}
X	printf("generation = %1d   population = %1d\n",
X	gen, pop);
X	++gen;
X
X	j9 = maxy - miny + 1;
X	for (i = minx; i <= maxx; i++)
X	{
X		if (center && j9 < TWIDTH)
X		{
X			l = (TWIDTH - j9) / 2;
X			for (k = 0; k < l; k++)
X				putchar(' ');
X		}
X		for (j = miny; j <= maxy; j++)
X			putchar(cell[i][j] ? '*' : ' ');
X		if (i != maxx)
X			putchar('\n');
X	}
X}
X
X/* Test if given column is populated */
X
Xpcol(n)
X{
X	int i, hi;
X	hi = (maxx == (XSIZE - 1)) ? maxx : maxx + 1;
X	for (i = minx ? minx - 1 : minx; i <= hi; ++i)
X		if (cell[i][n])
X			return 1;
X	return 0;
X}
X
X/* Test if given row is populated */
X
Xprow(n)
X{
X	int i, hi;
X	hi = (maxy == (YSIZE - 1)) ? maxy : maxy + 1;
X	for (i = miny ? miny - 1 : miny; i <= hi; ++i)
X		if (cell[n][i])
X			return 1;
X	return 0;
X}
X
X
X/*
X   Compute next generation. Algorithm used is a two-pass
X   cuteness suggested to me by Ward Christensen (he uses
X   it on a machine-language version on a 1024 character
X   display, and it cranks out 20 generations a second at
X   2 MHz.)
X   The algorithm uses the low order 3 bits of each 1-byte
X   cell as a neighbor count. The first pass finds all live
X   cells and increments the count of each of the 8 neighbors
X   of such live cells. For the first pass, dead cells are
X   totally ignored. The second pass then comes along and
X   checks the counts off all cells within the active square
X   to determine who lives and who dies. Note that this is a
X   significant improvement over the "obvious" method of
X   examining all 8 neighbors of each and every cell, dead
X   or alive, in the array.
X*/
X
Xdogen()
X{
X	int i, j, i2, j2;
X	int bigflag;
X	int k, l;
X	int oldpop;
X	char c;
X	int pass;
X	doneflag = 1;
X	oldpop = pop;
X	bigflag = (minx < 2 || maxx > (XSIZE - 3) ||
X	    miny < 2 || maxy > (YSIZE - 3));
X	i2 = (maxx == (XSIZE - 1)) ? maxx : maxx + 1;
X	j2 = (maxy == (YSIZE - 1)) ? maxy : maxy + 1;
X	for (pass = 0; pass < 2; pass++)
X		for (i = minx ? minx - 1 : minx; i <= i2; ++i)
X			for (j = miny ? miny - 1 : miny; j <= j2; ++j)
X			{
X				c = cell[i][j];
X				if (!pass)
X				{
X					if (c >= 10)
X						if (bigflag)
X							for (k = -1; k <= 1; k++)
X								for (l = -1; l <= 1; l++)
X									cell[mod(i + k, XSIZE)][mod(j + l, YSIZE)]++;
X						else
X							for (k = -1; k <= 1; k++)
X								for (l = -1; l <= 1; l++)
X									cell[i + k][j + l]++;
X				}
X				else
X					if (c > 10)
X						if (c < 13 || c > 14)
X						{
X							cell[i][j] = 0;
X							pop--;
X							doneflag = 0;
X						}
X				else
X				    cell[i][j] = 10;
X					else
X						if (c == 3)
X						{
X							cell[i][j] = 10;
X							pop++;
X							doneflag = 0;
X						}
X				else
X				    cell[i][j] = 0;
X			}
X	if (pop == oldpop)
X		boring++;
X	else
X	    boring = 0;
X}
X
X
Xint mod(a, b)
X{
X	if (a < 0)
X		return b + a;
X	if (a < b)
X		return a;
X	return a - b;
X}
X
X
X/* If we're about to run off the matrix, adjust accordingly (if possible) */
X
Xadjust()
X{
X	adjx();        /* for overflow in x direction	*/
X	adjy();        /* and also in y direction	*/
X}
X
X/* Adjust vertical position */
X
Xadjx()
X{
X	int delta, i, j;
X	int savdelta;
X	if (maxx - minx + 1 > XSIZE - 2)
X		return;
X	if (minx == 0)
X	{
X		delta = (XSIZE - maxx) / 2 + maxx;
X		savdelta = delta;
X		for (i = maxx; i >= 0; --i)
X		{
X			for (j = miny; j <= maxy; ++j)
X			{
X				cell[delta][j] = cell[i][j];
X				cell[i][j] = 0;
X			}
X			--delta;
X		}
X		minx = delta + 1;
X		maxx = savdelta;
X	}
X
X	if (maxx == (XSIZE - 1))
X	{
X		delta = minx / 2;
X		savdelta = delta;
X		for (i = minx; i < XSIZE; ++i)
X		{
X			for (j = miny; j <= maxy; ++j)
X			{
X				cell[delta][j] = cell[i][j];
X				cell[i][j] = 0;
X			}
X			++delta;
X		}
X		maxx = delta - 1;
X		minx = savdelta;
X	}
X}
X
X
X/* Adjust horizontal position */
X
Xadjy()
X{
X	int delta, i, j;
X	int savdelta;
X	if (maxy - miny + 1 > YSIZE - 2)
X		return;
X	if (miny == 0)
X	{
X		delta = (YSIZE - maxy) / 2 + maxy;
X		savdelta = delta;
X		for (i = maxy; i >= 0; --i)
X		{
X			for (j = minx; j <= maxx; ++j)
X			{
X				cell[j][delta] = cell[j][i];
X				cell[j][i] = 0;
X			}
X			--delta;
X		}
X		miny = delta + 1;
X		maxy = savdelta;
X	}
X
X	if (maxy == (YSIZE - 1))
X	{
X		delta = miny / 2;
X		savdelta = delta;
X		for (i = miny; i < YSIZE; ++i)
X		{
X			for (j = minx; j <= maxx; ++j)
X			{
X				cell[j][delta] = cell[j][i];
X				cell[j][i] = 0;
X			}
X			++delta;
X		}
X		maxy = delta - 1;
X		miny = savdelta;
X	}
X}
X
X/*
X	This is done so that the Wrath Of God doesn't mess up the
X	display:
X*/
X
Xputchar(c)
Xchar c;
X{
X	putch(c);
X}
X
END_OF_FILE
if test 8276 -ne `wc -c <'life.c.zolman'`; then
    echo shar: \"'life.c.zolman'\" unpacked with wrong size!
fi
# end of 'life.c.zolman'
fi
if test -f 'life.sh' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'life.sh'\"
else
echo shar: Extracting \"'life.sh'\" \(2056 characters\)
sed "s/^X//" >'life.sh' <<'END_OF_FILE'
X#\- run Life with options
X#usage: % [-options] [filelist]
X#options:
X#-m	display list of pattern files
X#-a	execute Life successively with all pattern files listed by -m;
X#	INT signal (DEL) results in user query: 
X#		continue with next file?, or exit
X#-g#, -c#, -ooutputfile		options as for unwrapped Life
X#
X#Note--
X#edit LIFEDIR and LIFE appropriately; 
X#the patterns in */xpatterns perhaps should be copied to */patterns;
X#script was written for ksh, but it seems pretty standard and should work 
X#under the Bourne shell.
X
XLIFEDIR=`pwd`/patterns
XLIFE=`pwd`/life
X
XUSAGE="\n\
Xusage: $0 [-options] [filelist]\n\
Xread stdin if no filelist\n\
Xoptions:\n\
X -m\tdisplay list of pattern files that can be read by Life\n\
X -a\texecute Life successively with all pattern files listed by -m\n\
X\t(INT signal (DEL) produces query = continue with next file?, or exit)\n\
X -g#\texit life after # generations\n\
X -c#\tcontrol code for pattern-display correspondence:\n\
X\t\t0 = display center fixed at center of _input_ pattern\n\
X\t\t[1-4] = display fixed at quadrant I-IV of _input_ pattern\n\
X\t\t5 = display center tracks center of evolving pattern (default)\n\
X\t\t[6-9] = display tracks quadrant I-IV of evolving pattern\n\
X\t\t\t(quadrants numbered counter-clockwise from upper right)\n\
X -ofile\tcopy all of pattern for each generation to file\n"
X
Xwhile [ "x"$1 != "x" ]
Xdo
X	case $1 in
X	-m)	cd $LIFEDIR;ls -C [a-z]*;exit 0;;
X	-a)	all=all
X		if [ -z "`echo $OPTS | egrep '\-c'`" ]
X		then
X			OPTS="$OPTS -c0"
X		fi
X		shift;;
X	-c*|-g*|-o*)	OPTS="$OPTS "$1;shift;;
X	--)	LIFEDIR="";shift;;
X	-*)	echo $USAGE;exit 0;;
X	core|life)	echo $1 is not a pattern file;exit 0;;
X	*)	break;;
X	esac
Xdone
X
Xif [ "x"$LIFEDIR != "x" ]
Xthen
X	cd $LIFEDIR
Xfi
X
Xif [ \( "x"$all = "xall" \) -o \( "x"$1 = "x*" \) ]
Xthen
X	set [a-z]*
Xelif [ $# -gt 0 ]
Xthen
X	set $@
Xelse
X	$LIFE $OPTS
X	exit 0
Xfi
X
Xif [ $# -gt 1 ]
Xthen
X	trap "echo \"continue (n/y(default)? \\c\"
X		read DUMMY
X		if [ \"x\"\$DUMMY = \"xn\" ] 
X		then 
X			exit 0
X		fi" 2
Xfi
X
Xwhile [ "x"$1 != "x" ]
Xdo
X	$LIFE $OPTS $1
X	shift
Xdone
Xexit 0
END_OF_FILE
if test 2056 -ne `wc -c <'life.sh'`; then
    echo shar: \"'life.sh'\" unpacked with wrong size!
fi
chmod +x 'life.sh'
# end of 'life.sh'
fi
if test ! -d 'patterns' ; then
    echo shar: Creating directory \"'patterns'\"
    mkdir 'patterns'
fi
if test -f 'patterns/oscpuls.4' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'patterns/oscpuls.4'\"
else
echo shar: Extracting \"'patterns/oscpuls.4'\" \(26 characters\)
sed "s/^X//" >'patterns/oscpuls.4' <<'END_OF_FILE'
X x
Xx x
Xx x
Xxxx
Xx x
Xx x
X x
END_OF_FILE
if test 26 -ne `wc -c <'patterns/oscpuls.4'`; then
    echo shar: \"'patterns/oscpuls.4'\" unpacked with wrong size!
fi
# end of 'patterns/oscpuls.4'
fi
if test -f 'patterns/squarex' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'patterns/squarex'\"
else
echo shar: Extracting \"'patterns/squarex'\" \(1937 characters\)
sed "s/^X//" >'patterns/squarex' <<'END_OF_FILE'
X                          xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
X                          x                    x                    x
X                          x                    x                    x
X                          x                    x                    x
X                          x                    x                    x
X                          x                    x                    x
X                          x                    x                    x
X                          x         xxxxxxxxxxxxxxxxxxxxxxx         x
X                          x         x          x          x         x
X                          x         x          x          x         x
Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
X                          x         x          x          x         x
X                          x         x          x          x         x
X                          x         xxxxxxxxxxxxxxxxxxxxxxx         x
X                          x                    x                    x
X                          x                    x                    x
X                          x                    x                    x
X                          x                    x                    x
X                          x                    x                    x
X                          x                    x                    x
X                          xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
X                                               x
X                                               x
X                                               x
X                                               x
X                                               x
X                                               x
X                                               x
X                                               x
X                                               x
END_OF_FILE
if test 1937 -ne `wc -c <'patterns/squarex'`; then
    echo shar: \"'patterns/squarex'\" unpacked with wrong size!
fi
# end of 'patterns/squarex'
fi
if test ! -d 'xpatterns' ; then
    echo shar: Creating directory \"'xpatterns'\"
    mkdir 'xpatterns'
fi
echo shar: End of archive 1 \(of 2\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0