#include #include #include #if need_getopt # include #endif #include "life.h" #define REP_COUNT 1024 #define GRID_WIDTH 79 #define GRID_HEIGHT 23 int width = GRID_WIDTH; int height = GRID_HEIGHT; int xterm_stuff = 1; /* * Driver code. */ void usage(void) { fprintf(stderr,"Usage: life [-h height] [-w width] [-r rep_count] [-s]\n"); } unsigned int grid_words(int width, int height) { unsigned int row_words; #if SYMBOLIC row_words = (width + 2 + BITS_PER_WORD - 1) / BITS_PER_WORD; #else row_words = (width + 2 + 31) >> 5; #endif return (height + 2) * row_words; } /* * The life array is potentially large, so we pack the bits into words * to save space. To simplify the transformation, we provide as a * boundary condition extra rows/columns at the top/bottom/left/right * edges of the two dimensional grid. (Large grids would be used, * for example, if we map a pixel of the display to a grid point.) */ unsigned int word_index(int r, int c) { unsigned int row_words, row_start, row_offset, grid_index; #if SYMBOLIC row_words = (width + 2 + BITS_PER_WORD - 1) / BITS_PER_WORD; #else row_words = (width + 2 + 31) >> 5; #endif row_start = (r + 1) * row_words; #if SYMBOLIC row_offset = (c + 1) / BITS_PER_WORD; #else row_offset = (c + 1) >> 5; #endif grid_index = row_start + row_offset; return grid_index; } unsigned int word_mask(int r, int c) { unsigned int word_offset, mask; #if SYMBOLIC word_offset = (c + 1) % BITS_PER_WORD; #else word_offset = (c + 1) & 0x1f; #endif mask = 1 << word_offset; return mask; } int cell_alive(unsigned int *grid, int r, int c) { unsigned int grid_index, mask; grid_index = word_index(r,c); mask = word_mask(r,c); if (grid[grid_index] & mask) return 1; else return 0; } void set_cell(unsigned int *grid, int r, int c, int status) { unsigned int grid_index, mask; grid_index = word_index(r,c); mask = word_mask(r,c); if (status) grid[grid_index] |= mask; else grid[grid_index] &= ~mask; } void show_grid(unsigned int *grid) { int r, c; if (xterm_stuff) printf("\033[H"); for (r = 0; r < height; r++) { for (c = 0; c < width; c++) { if (cell_alive(grid,r,c)) putchar('*'); else putchar(' '); } putchar('\n'); } } /* * Cheesy linear congruential random number generator. * Don't worry if you don't understand how it works. */ unsigned int rstate = 1; void srandgen(int val) { rstate = val; } /* * Maximal period criteria, from Knuth Vol 2, pg 16. * * ax+c mod m: (c,m)=1, b=a-1 is mult of p for all p | m, 4|b if 4|m * m = 2^32. any c prime will do. b even, 4 divides b, chose b = 4. */ unsigned int randgen(void) { rstate = 5 * rstate + 65521; return rstate % 65537; } int main(int argc, char **argv) { unsigned int seed = time((time_t *) 0); int option, i, r, c; unsigned int ix, m; unsigned int rep_count = REP_COUNT; int show_all = 0; unsigned int *grid, *grid2, *grid_tmp; while ((option = getopt(argc,argv,"h:r:sS:w:xX")) != EOF) switch (option) { case 'h': height = atoi(optarg); break; case 'r': rep_count = atoi(optarg); break; case 's': show_all = 1; break; case 'S': seed = atoi(optarg); break; case 'w': width = atoi(optarg); break; case 'x': xterm_stuff = 1; break; case 'X': xterm_stuff = 0; break; default: usage(); exit(1); break; } grid = malloc(sizeof *grid * grid_words(width,height)); grid2 = malloc(sizeof *grid2 * grid_words(width,height)); if (!grid || !grid2) { fprintf(stderr,"Insufficient memory for simulation\n"); exit(1); } srandgen(seed); for (r = 0; r < height; r++) for (c = 0; c < width; c++) { set_cell(grid,r,c,randgen()&1); } /* make sure the edges are zeros */ for (r = -1; r <= height; r++) { set_cell(grid,r,-1,0); set_cell(grid,r,width,0); set_cell(grid2,r,-1,0); set_cell(grid2,r,width,0); } for (c = -1; c <= width; c++) { set_cell(grid,-1,c,0); set_cell(grid,height,c,0); set_cell(grid2,-1,c,0); set_cell(grid2,height,c,0); } if (xterm_stuff) printf("\033[H\033[2J"); if (show_all) show_grid(grid); for (i = 0; i < rep_count; i++) { life_xform(grid,grid2); /* swap */ grid_tmp = grid2; grid2 = grid; grid = grid_tmp; if (show_all) show_grid(grid); } show_grid(grid); return 0; }