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