Skip to content

Instantly share code, notes, and snippets.

@edma2
Created July 6, 2012 21:01
Show Gist options
  • Save edma2/3062733 to your computer and use it in GitHub Desktop.
Save edma2/3062733 to your computer and use it in GitHub Desktop.
/* 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