Game-o'-Life
Stacey Campbell
staceyc at sco.COM
Mon Oct 2 07:37:36 AEST 1989
This is the Game-o'-Life. It should compile on almost
anything with a curses library (BSD, SYSV, XENIX etc).
The design is based on watching a running program and
trying to figure out the algorithm. Cycles of 16 or
less are found and noted, this value can be increased in
the source.
#!/bin/sh
# shar: Shell Archiver (v1.22)
#
# Run the following text with /bin/sh to create:
# README
# life.c
# Makefile
# style
# line
# sym
# death
#
sed 's/^X//' << 'SHAR_EOF' > README &&
XThis is the Game-o'-Life. It should compile on almost
Xanything with a curses library (BSD, SYSV, XENIX etc).
XThe design is based on watching a running program and
Xtrying to figure out the algorithm. Cycles of 16 or
Xless are found and noted, this value can be increased in
Xthe source.
X
XA couple of example files are included: style, line, sym
Xand death. If you come up with a good file then please
Xmail it so I can have a look.
X
XUsage: life [file]
X
XThis game is probably too dinky for comp.sources.games.
X
XStacey Campbell
X
Xuunet!sco!staceyc
SHAR_EOF
chmod 0664 README || echo "restore of README fails"
sed 's/^X//' << 'SHAR_EOF' > life.c &&
X/*
X * Game-o'-Life
X *
X * Stacey Campbell - SCO - late September 1989 - uunet!sco!staceyc
X */
X
X#include <signal.h>
X#include <stdio.h>
X#include <curses.h>
X
X#define Y_MAX 21
X#define X_MAX 30
X#define NO_LIFE '.'
X#define LIFE '@'
X#define DIR_COUNT 8
X#define OVERCROWDED 3
X#define BREED_COUNT 3
X#define LONELY 1
X#define LEGAL(y, x) ((y) >= 0 && (x) >= 0 && (y) < Y_MAX && (x) < X_MAX)
X#define BITS_IN_BYTE 8
X#define CYCLE_SIZE (((Y_MAX * X_MAX) / BITS_IN_BYTE) + 1)
X#define CYCLE_LIMIT 16
X
Xtypedef struct delta_t {
X int dy;
X int dx;
X } delta_t;
Xtypedef int board_t;
X
Xtypedef struct cycle_t {
X unsigned char board[CYCLE_SIZE];
X struct cycle_t *next;
X } cycle_t;
X
Xstatic delta_t Dirs[DIR_COUNT] =
X {{-1 ,0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}};
X
Xint Life();
Xint DeathCheck();
Xint Breed();
Xvoid InitBoard();
Xvoid DisplayBoard();
Xvoid InitSignals();
Xvoid SigExit();
Xvoid ErrorExit();
Xvoid InitCycleCheck();
Xint CycleCheck();
Xvoid CompressCycle();
X
Xint main(argc, argv)
X
Xint argc;
Xchar *argv[];
X
X {
X board_t board[Y_MAX][X_MAX];
X int status;
X int cycle = 0;
X int generation = 1;
X
X InitBoard(board, argc, argv);
X InitCycleCheck(board);
X initscr();
X InitSignals();
X do {
X DisplayBoard(stdscr, board, generation);
X status = Life(board);
X if (status && ! cycle)
X {
X cycle = CycleCheck(board);
X if (cycle)
X {
X wmove(stdscr, Y_MAX + 1, 0);
X wprintw(stdscr, "Cycles every %d", cycle);
X if (cycle == 1)
X waddstr(stdscr, " generation.\n");
X else
X waddstr(stdscr, " generations.\n");
X wrefresh(stdscr);
X }
X }
X ++generation;
X sleep(1);
X } while (status && cycle != 1);
X DisplayBoard(stdscr, board, generation);
X if (cycle != 1)
X {
X wmove(stdscr, Y_MAX + 1, 0);
X waddstr(stdscr, "Extinction.");
X }
X wmove(stdscr, LINES - 1, 0);
X wrefresh(stdscr);
X endwin();
X
X return 0;
X }
X
Xstatic int Life(board)
X
Xboard_t board[Y_MAX][X_MAX];
X
X {
X int i, j;
X int alive = 0;
X board_t death_board[Y_MAX][X_MAX];
X board_t life_board[Y_MAX][X_MAX];
X
X for (i = 0; i < Y_MAX; ++i)
X for (j = 0; j < X_MAX; ++j)
X alive += Breed(life_board, board, i, j);
X for (i = 0; i < Y_MAX; ++i)
X for (j = 0; j < X_MAX; ++j)
X alive += DeathCheck(death_board, board, i, j);
X for (i = 0; i < Y_MAX; ++i)
X for (j = 0; j < X_MAX; ++j)
X board[i][j] = life_board[i][j] || death_board[i][j];
X
X return alive;
X }
X
Xstatic int Breed(new_board, old_board, y, x)
X
Xboard_t new_board[Y_MAX][X_MAX];
Xboard_t old_board[Y_MAX][X_MAX];
Xint y;
Xint x;
X
X {
X int i;
X int ny, nx;
X int neighbors = 0;
X
X for (i = 0; i < DIR_COUNT; ++i)
X {
X ny = y + Dirs[i].dy;
X nx = x + Dirs[i].dx;
X if (LEGAL(ny, nx) && old_board[ny][nx])
X ++neighbors;
X }
X new_board[y][x] = neighbors == BREED_COUNT;
X
X return new_board[y][x];
X }
X
Xstatic int DeathCheck(new_board, board, y, x)
X
Xboard_t new_board[Y_MAX][X_MAX];
Xboard_t board[Y_MAX][X_MAX];
Xint y;
Xint x;
X
X {
X int i;
X int ny, nx;
X int neighbors = 0;
X
X if (board[y][x])
X for (i = 0; i < DIR_COUNT; ++i)
X {
X ny = y + Dirs[i].dy;
X nx = x + Dirs[i].dx;
X if (LEGAL(ny, nx) && board[ny][nx])
X ++neighbors;
X }
X new_board[y][x] = ! (neighbors <= LONELY || neighbors >= OVERCROWDED);
X
X return new_board[y][x];
X }
X
Xstatic void DisplayBoard(win, board, generation)
X
XWINDOW *win;
Xboard_t board[Y_MAX][X_MAX];
Xint generation;
X
X {
X int i, j;
X static char life[2] = {NO_LIFE, LIFE};
X
X for (i = 0; i < Y_MAX; ++i)
X for (j = 0; j < X_MAX; ++j)
X mvwaddch(win, i, j * 2, life[board[i][j]]);
X wmove(win, Y_MAX, 0);
X wprintw(win, "Generation: %d\n", generation);
X wmove(win, Y_MAX + 2, 0);
X wrefresh(win);
X }
X
Xstatic void InitBoard(board, argc, argv)
X
Xboard_t board[Y_MAX][X_MAX];
Xint argc;
Xchar *argv[];
X
X {
X int i, j;
X int file_empty;
X int line_empty;
X FILE *fp;
X char buffer[X_MAX + 2];
X static char *ch_board[Y_MAX] = {
X "", "", "", "", "",
X " *",
X " * *",
X " * *",
X " * *",
X " * *",
X " * *",
X " * *",
X " *",
X 0};
X
X if (argc == 1)
X {
X file_empty = 0;
X for (i = 0; i < Y_MAX; ++i)
X {
X if (! file_empty)
X file_empty = ch_board[i] == 0;
X line_empty = file_empty;
X for (j = 0; j < X_MAX; ++j)
X {
X if (! line_empty)
X line_empty = ch_board[i][j] == '\0';
X if (! line_empty)
X board[i][j] = ch_board[i][j] != ' ';
X else
X board[i][j] = 0;
X }
X }
X return;
X }
X if (argc > 2)
X ErrorExit(argv[0], "usage: %s [init-file]", argv[0]);
X if ((fp = fopen(argv[1], "r")) == NULL)
X ErrorExit(argv[0], "cannot read: %s", argv[1]);
X file_empty = 0;
X for (i = 0; i < Y_MAX; ++i)
X {
X memset(buffer, 0, sizeof(buffer));
X if (! file_empty)
X file_empty = fgets(buffer, sizeof(buffer), fp) == NULL;
X buffer[strlen(buffer) - 1] = '\0';
X for (j = 0; j < X_MAX; ++j)
X board[i][j] = buffer[j] != ' ' && buffer[j] != '\0' &&
X buffer[j] != NO_LIFE;
X }
X (void)fclose(fp);
X }
X
Xstatic void ErrorExit(prog, s1, s2)
X
Xchar *prog;
Xchar *s1;
Xchar *s2;
X
X {
X fprintf(stderr, "%s ", prog);
X fprintf(stderr, s1, s2);
X fprintf(stderr, "\n");
X exit(1);
X }
X
Xstatic void InitSignals()
X
X {
X signal(SIGINT, SigExit);
X signal(SIGQUIT, SigExit);
X }
X
Xstatic void SigExit(signo)
X
Xint signo;
X
X {
X endwin();
X if (signo == SIGQUIT)
X {
X signal(SIGQUIT, SIG_DFL);
X kill(getpid(), SIGQUIT);
X pause();
X }
X exit(1);
X }
X
Xstatic cycle_t *TopCycle;
Xstatic int CycleCount;
X
Xstatic void InitCycleCheck(board)
X
Xboard_t board[Y_MAX][X_MAX];
X
X {
X TopCycle = (cycle_t *)malloc(sizeof(cycle_t));
X TopCycle->next = 0;
X CompressCycle(board, TopCycle);
X CycleCount = 1;
X }
X
Xstatic int CycleCheck(board)
X
Xboard_t board[Y_MAX][X_MAX];
X
X {
X cycle_t *check_p;
X cycle_t *cycle_p, *old_p, *very_old_p;
X int i = 1;
X
X check_p = (cycle_t *)malloc(sizeof(cycle_t));
X CompressCycle(board, check_p);
X old_p = 0;
X very_old_p = 0;
X cycle_p = TopCycle;
X while (cycle_p)
X if (memcmp(cycle_p->board, check_p->board,
X sizeof(check_p->board)) == 0)
X {
X free((cycle_t *)check_p);
X return i;
X }
X else
X {
X ++i;
X very_old_p = old_p;
X old_p = cycle_p;
X cycle_p = cycle_p->next;
X }
X
X if (CycleCount >= CYCLE_LIMIT)
X if (very_old_p && very_old_p != TopCycle)
X {
X free((cycle_t *)old_p);
X very_old_p->next = 0;
X }
X old_p = TopCycle;
X TopCycle = check_p;
X TopCycle->next = old_p;
X ++CycleCount;
X return 0;
X }
X
Xvoid CompressCycle(board, cycle_p)
X
Xint board[Y_MAX][X_MAX];
Xcycle_t *cycle_p;
X
X {
X int i, j;
X int c_i, bit;
X
X c_i = 0;
X bit = 0;
X memset(cycle_p->board, '\0', sizeof(cycle_p->board));
X for (i = 0; i < Y_MAX; ++i)
X for (j = 0; j < X_MAX; ++j)
X {
X cycle_p->board[c_i] |= board[i][j] << bit;
X ++bit;
X if (bit == BITS_IN_BYTE)
X {
X ++c_i;
X bit = 0;
X }
X }
X }
SHAR_EOF
chmod 0664 life.c || echo "restore of life.c fails"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X# Makefile for life
X
X# System 5
X# LDLIBS= -lcurses
X
X# BSD
X# LDLIBS= -lcurses -ltermcap
X
X#XENIX
XLDLIBS= -ltcap -ltermlib
X
XOBJS= life.o
XSRC= life.c
XCFLAGS= -O
XEXE= life
XEXAMPLES= style line sym death
X
X$(EXE): $(OBJS)
X cc -o $(EXE) $(CFLAGS) $(OBJS) $(LDLIBS)
X
Xshar:
X xshar README life.c Makefile $(EXAMPLES) > $(EXE).shar
SHAR_EOF
chmod 0664 Makefile || echo "restore of Makefile fails"
sed 's/^X//' << 'SHAR_EOF' > style &&
X ** ***
X* ** ****
X** **
X **
X* *
X**
X**
X *
X *
SHAR_EOF
chmod 0664 style || echo "restore of style fails"
sed 's/^X//' << 'SHAR_EOF' > line &&
X..............................
X..............................
X..............................
X..............................
X..............................
X..............................
X..............................
X..............................
X..............**..............
X......*.......**.......*......
X....**.**... * * ...**.**....
X......*.......**.......*......
X..............**..............
X..............................
X..............................
X..............................
X..............................
X..............................
X..............................
X..............................
X..............................
SHAR_EOF
chmod 0664 line || echo "restore of line fails"
sed 's/^X//' << 'SHAR_EOF' > sym &&
X*.**..........................
X.*..***.......................
X*.*.**........................
X*..*..........................
X.**.*.........................
X.**..*........................
X.*............................
X..............................
X..............................
X..............................
X..............................
X..............................
X..............................
X..............................
X............................*.
X........................*..**.
X.........................*.**.
X..........................*..*
X........................**.*.*
X.......................***..*.
X..........................**.*
SHAR_EOF
chmod 0664 sym || echo "restore of sym fails"
sed 's/^X//' << 'SHAR_EOF' > death &&
X*............................*
X.*..........................*.
X..*........................*..
X...*......................*...
X....*....................*....
X.....*..................*.....
X......*................*......
X.......*..............*.......
X........*.....**.....*........
X......*..*....**....*..*......
X******.**.*. * * .*.**.******
X......*..*....**....*..*......
X........*.....**.....*........
X.......*..............*.......
X......*................*......
X.....*..................*.....
X....*....................*....
X...*......................*...
X..*........................*..
X.*..........................*.
X*............................*
SHAR_EOF
chmod 0664 death || echo "restore of death fails"
exit 0
--
Stacey Campbell - uunet!sco!staceyc - The Santa Cruz Operation
More information about the Alt.sources
mailing list