Created
July 6, 2012 21:01
-
-
Save edma2/3062733 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Conway's Game of Life | |
* Author: Eugene Ma (edma2) */ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#define for_each_cell(g) \ | |
do { \ | |
int x, y; \ | |
for (y = 0; y < g->h; y++) { \ | |
for (x = 0; x < g->w; x++) { | |
#define end_for }}} while (0) | |
#define MAXLINE 100 | |
#define false 0 | |
#define true 1 | |
typedef int boolean; | |
typedef struct { | |
boolean alive; | |
} Cell; | |
typedef struct { | |
int w; | |
int h; | |
Cell *cells; | |
} Grid; | |
/* New grid of dimensions width w and height h. | |
* Cells are uninitialized and undefined. */ | |
Grid *Grid_new(int w, int h) { | |
Grid *g = malloc(sizeof(Grid)); | |
if (!g) return NULL; | |
g->w = w; | |
g->h = h; | |
g->cells = malloc(sizeof(Cell) * w * h); | |
if (!g->cells) { | |
free(g); | |
return NULL; | |
} | |
return g; | |
} | |
/* Get the cell at (x, y) in grid g. */ | |
Cell *Grid_get_cell(Grid *g, int x, int y) { | |
x %= g->w; | |
y %= g->h; | |
if (x < 0) | |
x = g->w + x; | |
if (y < 0) | |
y = g->h + y; | |
return &(g->cells[y * g->w + x]); | |
} | |
/* Kill cell at (x, y) in grid g. */ | |
void kill(Grid *g, int x, int y) { | |
Grid_get_cell(g, x, y)->alive = false; | |
} | |
/* Give life to cell at (x, y) in grid g. */ | |
void sustain(Grid *g, int x, int y) { | |
Cell *c = Grid_get_cell(g, x, y); | |
c->alive = true; | |
} | |
/* Is cell at (x, y) in grid g alive? */ | |
boolean alive(Grid *g, int x, int y) { | |
return Grid_get_cell(g, x, y)->alive; | |
} | |
/* Kill all cells in grid g. */ | |
void Grid_clear(Grid *g) { | |
for_each_cell(g) { | |
kill(g, x, y); | |
} end_for; | |
} | |
/* Free grid g entirely. */ | |
void Grid_free(Grid *g) { | |
free(g->cells); | |
free(g); | |
} | |
/* The number of neighbors for cell (x, y) in grid g */ | |
int neighbor_count(Grid *g, int x, int y) { | |
int count = 0; | |
if (alive(g, x-1, y-1)) count++; | |
if (alive(g, x-1, y)) count++; | |
if (alive(g, x-1, y+1)) count++; | |
if (alive(g, x, y-1)) count++; | |
if (alive(g, x, y+1)) count++; | |
if (alive(g, x+1, y-1)) count++; | |
if (alive(g, x+1, y)) count++; | |
if (alive(g, x+1, y+1)) count++; | |
return count; | |
} | |
/* Will the cell at (x, y) in grid g survive (or come back to life)? */ | |
boolean survives(Grid *g, int x, int y) { | |
int n = neighbor_count(g, x, y); | |
if (alive(g, x, y)) { | |
if (n < 2) | |
return false; /* starve */ | |
else if (n < 4) | |
return true; | |
else | |
return false; /* over-population */ | |
} else { | |
if (n == 3) | |
return true; /* reproduction */ | |
} | |
return false; | |
} | |
/* Return new grid with new cell states. | |
* Old grid is destroyed (invalid pointer). */ | |
Grid *Grid_advance(Grid *old) { | |
Grid *future = Grid_new(old->h, old->w); | |
if (!future) return NULL; | |
for_each_cell(old) { | |
if (survives(old, x, y)) | |
sustain(future, x, y); | |
else | |
kill(future, x, y); | |
} end_for; | |
Grid_free(old); | |
return future; | |
} | |
void Grid_print(Grid *g) { | |
for_each_cell(g) { | |
if (alive(g, x, y)) | |
printf("*"); | |
else | |
printf("_"); | |
if (x == g->w - 1) | |
printf("\n"); | |
} end_for; | |
} | |
int Grid_load_shape(Grid *g, int top_left_x, int top_left_y, char *path) { | |
FILE *fp = fopen(path, "r"); | |
if (!fp) return -1; | |
char buf[MAXLINE]; | |
int x, y; | |
for (y = top_left_y; fgets(buf, sizeof(buf), fp); y++) { | |
char *cp; | |
for (cp = buf, x = top_left_x; *cp; x++, cp++) { | |
if (*cp == '.') | |
sustain(g, x, y); | |
else | |
kill(g, x, y); | |
} | |
} | |
return 0; | |
} | |
int main(void) { | |
Grid *g; | |
g = Grid_new(40, 40); | |
Grid_clear(g); | |
Grid_load_shape(g, 1, 1, "shapes/glider"); | |
Grid_load_shape(g, 6, 27, "shapes/glider"); | |
Grid_load_shape(g, 10, 11, "shapes/beacon"); | |
Grid_load_shape(g, 20, 8, "shapes/glider"); | |
int i; | |
for (i = 0; true; i++) { | |
Grid_print(g); | |
printf("timer: %d\n", i); | |
g = Grid_advance(g); | |
usleep(80000); | |
} | |
Grid_free(g); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment