staceyc@sco.COM (Stacey Campbell) (10/02/89)
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