koreth@ssyx.ucsc.edu (Steven Grimm) (01/21/89)
Submitted-by: leo@philmds.dts.philips.nl (Leo de Wit)
Posting-number: Volume 1, Issue 96
Archive-name: leolife
[The binaries have been posted to the binaries group. -sg]
: This is a shar archive. Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
echo 'Extracting life.c'
sed 's/^X//' > life.c << '+ END-OF-FILE life.c'
X/******************************************************************************
X * *
X * COPYRIGHT (C) 1988 L.J.M. de Wit *
X * ALL RIGHTS RESERVED *
X * *
X * life.c version 1.0 of 11 Nov 1988 *
X * *
X * This software may be used and distributed freely if not used commercially *
X * and the originator (me) is mentioned. *
X * *
X ******************************************************************************
X *
X * NAME
X * life - the game of life (graphics demo if you want)
X *
X * SYNTAX
X * life.ttp [-d|-D] [-w wait] [01-pattern ...]
X *
X * DESCRIPTION
X * This program barely needs comments. 'Generations' are created on a grid,
X * on a step by step basis. The criterium used for a cell to survive
X * (resp. die), is that it has between BOT (3) and TOP (4) neighbours
X * (resp. has not).
X *
X * The program runs only in high and medium resolution modes (so everyone
X * should be able to run it); not supporting low res is entirely due to
X * laziness on my part 8-), but since no colours are involved (yet) it
X * seemed an unnecessary addition.
X *
X * For both resolutions supported you can choose a coarse grid (25 x 40)
X * and a fine one (50 x 80); default is coarse, and the -d or -D (double)
X * option selects the fine grid.
X *
X * The -w or -W option lets you specify an amount of time to wait between
X * generations (default is nowait).
X *
X * Any remaining arguments are taken to be the initial patterns to be placed
X * on the grid, a '0' representing an empty cell, a '1' a filled one. These
X * patterns are placed on subsequent rows, near the middle of the screen.
X * Some pattern sets generate repetitive populations, other die away, still
X * other generate nice ever-changing patterns. Experiment. Symmetric sets
X * are (possibly) favorite; this means using symmetric patterns, with the
X * first matching the last, the second the last but one, etc., and using an
X * odd number of patterns in the coarse grid case and an even number of
X * patterns in the fine grid case. You could alternative use point symmetry
X * instead of line symmetry; figure out for yourself how to arrange this.
X * If there are no remaining arguments after any flags, a random pattern is
X * generated.
X *
X * To finish the game, 'press any key ...'
X *
X * EXAMPLE
X * life -d -w 20 011110 110011 101101 001100 101101 110011 011110
X *
X * will have a fine grid, a wait pause of 20, and an initial pattern set
X * that looks like:
X * ****
X * ** **
X * * ** *
X * **
X * * ** *
X * ** **
X * ****
X * DECISIONS
X * Screen access is done directly, for speed reasons (we must be able to
X * print several hundreds of characters, several times per second, if we
X * want screen updates to appear - almost - immediate).
X * On the other hand, C proved to be quite fast enough, so there was no
X * need to resort to assembler.
X * Each resolution and each mode (coarse/fine) demands it own treatment,
X * so four separate (functional identical) functions were written, one
X * for each of them.
X *
X * By using a private startup routine (not included) instead of the
X * compiler supplied one, the size of the program could be kept
X * considerably smaller (not using stdio).
X */
X
X#include <osbind.h>
X
X#define FALSE 0
X#define TRUE 1
X
X#define CPUTC(c) bios(3,2,c) /* Write char c to console */
X#define SC_24 0xffffff /* Mask 24 bits */
X#define BOT 3 /* Min. # of neighbours to survive */
X#define TOP 4 /* Max. # of neighbours to survive */
X
X#define B_P_ROW 1280 /* Bytes per screen row */
X#define B_P_DROW 640 /* Bytes per half screen row */
X#define W_P_ROW 640 /* Words per screen row */
X#define W_P_DROW 320 /* Words per half screen row */
X#define L_P_ROW 320 /* Longs per screen row */
X#define L_P_DROW 160 /* Longs per half screen row */
X
X#define B_P_HLIN 80 /* Bytes per hires line */
X#define W_P_HLIN 40 /* Words per hires line */
X#define L_P_MLIN 40 /* Longs per meres line */
X
X#define STDROWS 25 /* Default # of grid rows */
X#define STDCOLS 40 /* Default # of grid columns */
X#define MAXARRSIZ (STDROWS*STDCOLS*4) /* Max.gridsize for either gridtype */
X
X#define BROW(bp,r) (*(bp) + Cols * (r)) /* Start of row r in block *bp */
X
X/* create some unsigned types */
Xtypedef unsigned char uchar;
Xtypedef unsigned short ushort;
Xtypedef unsigned long ulong;
X
Xtypedef uchar grid[MAXARRSIZ]; /* A 'grid of cells' type */
X
Xstatic grid *oldp, *newp; /* Pointers to old and new grid */
X
Xstatic short Rows; /* Actual # of rows in grid */
Xstatic short Cols; /* Actual # of columns in grid */
X
Xstatic ulong *start; /* Points to logical screen start */
X
Xint _mneed = 60000; /* For Lattice C: restricts the */
X /* memory used by the program, so */
X /* that Mallocs will find enough */
X /* memory left. */
X
Xstatic ushort dsized = FALSE; /* Boolean: fine grid used? */
X
Xstatic void init_grid(), /* Initiate one grid */
X calc_grid(), /* Calculate next grid */
X show_s1grid(), /* Show coarse grid med res */
X show_d1grid(), /* Show fine grid med res */
X show_s2grid(), /* Show coarse grid hi res */
X show_d2grid(); /* Show fine grid hi res */
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X short cntr = 0; /* # of generations */
X grid *swap; /* Temporary to change grid ptrs */
X register ulong *upn, *upo, uv; /* For clearing grids initially */
X register short cnt; /* Counting clear bytes */
X long i, waittime = 0; /* Counting wait loop */
X void (*showfunc)(); /* The display function being used */
X static void (*sfuncs[])() = { /* Possible display functions */
X (void (*)())0,(void (*)())0, /* Low res not implemented */
X show_s1grid, show_d1grid, /* Med res coarse and fine */
X show_s2grid, show_d2grid /* Hi res coarse and fine */
X };
X
X start = (ulong *)Logbase(); /* Cur. log. screen will be used */
X for (--argc, argv++;
X argc > 0 && **argv == '-';
X --argc, argv++) { /* Handle flag arguments */
X if (argv[0][1] == 'd' || argv[0][1] == 'D') { /* Double, i.e. fine */
X dsized = TRUE;
X } else if (argv[0][1] == 'w' || argv[0][1] == 'W') { /* Wait count */
X if (--argc <= 0) {
X Cconws("life: usage: life.ttp [-d|-D] [-w|-W wait] [01-pattern...]\r\n");
X Crawcin();
X Pterm(1);
X }
X waittime = atoi(*++argv);
X if (waittime < 0 || waittime > 10000) {
X Cconws("life: wait must be between 0 and 10000\r\n");
X Crawcin();
X Pterm(1);
X }
X } else { /* Illegal flag */
X Cconws("life: usage: life.ttp [-d|-D] [-w|-W wait] [01-pattern...]\r\n");
X Crawcin();
X Pterm(1);
X }
X }
X
X showfunc = sfuncs[2 * Getrez() + dsized]; /* Select display function */
X if (showfunc == (void (*)())0) { /* Low resolution not provided for */
X Cconws("life: must be medium/high resolution, sorry ...\r\n");
X Crawcin();
X Pterm(1);
X }
X
X Cconws("\33E\33f\33Y,1created 1988 * LIFE * by Leo de Wit");
X for (i = 1 << 18; --i >= 0; ) ; /* Wait some time */
X CPUTC('\33'); CPUTC('l'); /* Clear current line */
X
X if (dsized) { /* Fine grid chosen ... */
X Rows = STDROWS * 2; /* Twice as many rows ... */
X Cols = STDCOLS * 2; /* Twice as many cols ... */
X } else { /* Coarse grid chosen */
X Rows = STDROWS; /* Std. # of rows */
X Cols = STDCOLS; /* Std. # of cols */
X }
X
X newp = (grid *)Malloc(sizeof(grid)); /* Allocate one grid */
X oldp = (grid *)Malloc(sizeof(grid)); /* And another */
X if (newp == (grid *)-1 || oldp == (grid *)-1) {
X Cconws("life: memory allocation failed\r\n");
X Crawcin();
X Pterm(1);
X }
X uv = 0; /* Now clear them both ... */
X upn = (ulong *)newp;
X upo = (ulong *)oldp;
X for (cnt = sizeof(grid)/sizeof(ulong); --cnt >= 0; ) {
X *upn++ = *upo++ = uv;
X }
X
X init_grid(newp,argc,argv); /* Initiate grid *newp */
X waittime <<= 10; /* Scale waittime reasonably */
X
X for (;;) {
X (*showfunc)(newp,oldp); /* Write to logical screen */
X if (((cntr++ & 0x7) == 0) && Bconstat(2)) { /* Test constat once in 8 */
X break;
X }
X swap = newp; newp = oldp; oldp = swap; /* Exchange grid pointers */
X calc_grid(newp,oldp); /* Calculate new grid from old */
X for (i = waittime; --i >= 0; ) ; /* This is the wait loop */
X }
X
X Bconin(2); /* Read key pressed from queue */
X}
X
Xstatic void init_grid(bp,argc,argv) /* Initiate grid *bp */
Xgrid *bp;
Xint argc;
Xchar **argv;
X{
X short len, maxlen = 0, j, i, r0, c0;
X
X if (argc == 0) { /* No parameters: random pattern */
X short maxi = (Rows == STDROWS) ? 16 : 64; /* # of filled cells */
X
X for (i = 0; i < maxi; i++) {
X short ranrow = Rows/3+((unsigned)Random())*Rows/(3*SC_24);
X short rancol = Cols/3+((unsigned)Random())*Cols/(3*SC_24);
X
X BROW(bp,ranrow)[rancol] = '\1';
X }
X } else { /* Pattern parameters */
X for (i = 0; i < argc; i++) { /* Find longest string length */
X if ((len = strlen(argv[i])) > maxlen) {
X maxlen = len;
X }
X }
X r0 = (Rows - argc)/2; /* Start row */
X c0 = (Cols - maxlen)/2; /* Start column */
X for (i = 0; i < argc; i++) { /* Handle each string */
X len = strlen(argv[i]);
X for (j = 0; j < len; j++) { /* Set each cell */
X BROW(bp,r0+i)[c0+j] = argv[i][j] & 1;
X }
X }
X }
X}
X
Xstatic void calc_grid(newp,oldp) /* Calculate new grid from old */
Xgrid *newp, *oldp;
X{
X register short r, c; /* Current row, col */
X register uchar *cp, /* Ptr into new grid */
X *ocp; /* Ptr into old grid */
X
X for (r = Rows; --r >= 0; ) { /* Zero each row of grid */
X cp = BROW(newp,r+1);
X for (c = Cols; --c >= 0; ) { /* Zero each cell of row */
X *--cp = '\0';
X }
X }
X for (r = Rows - 1; --r >= 1; ) { /* Handle each row of old */
X ocp = BROW(oldp,r+1);
X --ocp;
X for (c = Cols - 1; --c >= 1; ) { /* Handle each cell of old row */
X if (*--ocp) { /* If it was filled ... */
X cp = &BROW(newp,r-1)[c-1]; /* Incr. each neighbour's count */
X (*cp++)++; (*cp++)++; (*cp++)++; /* Previous row in new grid */
X cp += Cols - 3;
X (*cp++)++; (*cp++)++; (*cp++)++; /* Same row in new grid */
X cp += Cols - 3;
X (*cp++)++; (*cp++)++; (*cp++)++; /* Next row in new grid */
X }
X }
X }
X for (r = Rows; --r >= 0; ) { /* Handle each row of new grid */
X cp = BROW(newp,r+1);
X for (c = Cols; --cp, --c >= 0; ) { /* Handle each cell of row */
X *cp = (*cp >= BOT && *cp <= TOP);/* Set it according to accum. cnt */
X }
X }
X}
X
Xstatic void show_s1grid(newp,oldp) /* Display coarse grid med res */
Xgrid *newp, *oldp;
X{
X register short r, c; /* Current row & column */
X register ulong val; /* Value to fill with */
X register ulong step = L_P_MLIN; /* Step to next screen line */
X register uchar *cp, /* Ptr into new grid */
X *ocp; /* Ptr into old grid */
X register ulong *sa, /* Current screen address */
X *basad; /* Screen address of end of row */
X
X basad = start + (Rows * L_P_ROW);
X for (r = Rows; basad -= L_P_ROW, --r >= 0; ) { /* Handle each row */
X cp = BROW(newp,r+1);
X ocp = BROW(oldp,r+1);
X for (c = Cols; --c >= 0; ) { /* Handle each column */
X if (*--cp != *--ocp) {
X val = -*cp; /* 0xffffffff : 0 */
X sa = basad + c;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val;
X }
X }
X }
X}
X
Xstatic void show_d1grid(newp,oldp) /* Display fine grid med res */
Xgrid *newp, *oldp;
X{
X register short r, c; /* Current row & column */
X register ulong val; /* Value to fill with */
X register ulong step = L_P_MLIN; /* Step to next screen line */
X register ushort *sp, /* Ptr into new grid */
X *osp; /* Ptr into old grid */
X register ulong *sa, /* Current screen address */
X *basad; /* Screen address of end of row */
X
X basad = start + (Rows * L_P_DROW);
X for (r = Rows; basad -= L_P_DROW, --r >= 0; ) { /* Handle each row */
X sp = (ushort *)BROW(newp,r+1);
X osp = (ushort *)BROW(oldp,r+1);
X for (c = Cols/2; --c >= 0; ) { /* Handle each column, two a time */
X if (*--sp != *--osp) {
X static ulong values[] = {0, 0xff00ff, 0xff00ff00, 0xffffffff};
X
X val = values[(*sp & 1) + (*sp >> 7)];
X sa = basad + c;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val;
X }
X }
X }
X}
X
Xstatic void show_s2grid(newp,oldp) /* Display coarse grid hi res */
Xgrid *newp, *oldp;
X{
X register short r, c; /* Current row & column */
X register ushort val; /* Value to fill with */
X register ulong step = W_P_HLIN; /* Step to next screen line */
X register uchar *cp, /* Ptr into new grid */
X *ocp; /* Ptr into old grid */
X register ushort *sa, /* Current screen address */
X *basad; /* Screen address of end of row */
X
X basad = ((ushort *)start) + (Rows * W_P_ROW);
X for (r = Rows; basad -= W_P_ROW, --r >= 0; ) { /* Handle each row */
X cp = BROW(newp,r+1);
X ocp = BROW(oldp,r+1);
X for (c = Cols; --c >= 0; ) { /* Handle each column */
X if (*--cp != *--ocp) {
X val = -*cp; /* 0xffffffff : 0 */
X sa = basad + c;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val;
X }
X }
X }
X}
X
Xstatic void show_d2grid(newp,oldp) /* Display fine grid hi res */
Xgrid *newp, *oldp;
X{
X register short r, c; /* Current row & column */
X register uchar val; /* Value to fill with */
X register ulong step = B_P_HLIN; /* Step to next screen line */
X register uchar *cp, /* Ptr into new grid */
X *ocp; /* Ptr into old grid */
X register uchar *sa, /* Current screen address */
X *basad; /* Screen address of end of row */
X
X basad = ((uchar *)start) + (Rows * B_P_DROW);
X for (r = Rows; basad -= B_P_DROW, --r >= 0; ) { /* Handle each row */
X cp = BROW(newp,r+1);
X ocp = BROW(oldp,r+1);
X for (c = Cols; --c >= 0; ) { /* Handle each column */
X if (*--cp != *--ocp) {
X val = -*cp; /* 0xff : 0 */
X sa = basad + c;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val; sa += step;
X *sa = val;
X }
X }
X }
X}
+ END-OF-FILE life.c
chmod 'u=rw,g=r,o=' 'life.c'
echo 'SENT: -rw-r----- 1 leo 19008 Jan 20 18:29 life.c'
echo -n 'RCVD: '
/bin/ls -l life.c
exit 0