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