Skip to content

Instantly share code, notes, and snippets.

@LyndonArmitage
Last active August 29, 2015 13:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LyndonArmitage/10275443 to your computer and use it in GitHub Desktop.
Save LyndonArmitage/10275443 to your computer and use it in GitHub Desktop.
Basic Conways Game Of Life in C
// compile with gcc gol.c -o gol -lncurses
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "ncurses.h"
#define TIME_TEST 1
#ifdef TIME_TEST
FILE * timeLog = NULL;
#endif
int getValue(int x, int y, int * grid, unsigned int width, unsigned int height);
void setValue(int value, int x, int y, int * grid, int * needsCheck, unsigned int width, unsigned int height);
void clearGrid(int * grid, unsigned int size, int value);
void drawGrid(int * grid, unsigned int width, unsigned int height);
void update(int * grid, int * needsCheck, unsigned int width, unsigned int height);
int getNeighbours(unsigned int x, unsigned int y, int * grid, unsigned int width, unsigned int height);
void randomGrid(int * grid, int * needsCheck, unsigned int size);
bool loadFile(char * filename, int * grid, int * needsCheck, unsigned int width, unsigned int height);
int main(void) {
srand( time(NULL) );
WINDOW * win = initscr();
noecho();
raw();
if(has_colors() == FALSE) {
endwin();
exit(1);
}
start_color();
init_pair(0, COLOR_BLACK, COLOR_BLACK);
init_pair(1, COLOR_BLACK, COLOR_WHITE);
unsigned int maxX, maxY;
getmaxyx(win, maxY, maxX);
unsigned int bottomY = maxY;
maxY -= 1;
int grid [maxX * maxY];
int needsCheck[maxX * maxY];
//clearGrid(grid, maxX * maxY, 0);
//clearGrid(needsCheck, maxX * maxY, 1);
randomGrid(grid, needsCheck, maxX * maxY);
int speed = 10;
int oldSpeed = 10;
timeout(speed);
char speedStr[10];
sprintf(speedStr, "%d", speed);
#ifdef TIME_TEST
timeLog = fopen("timelog.txt", "w");
if(timeLog == NULL) {
endwin();
printf("Error opening file for writing\n");
exit(1);
}
#endif
unsigned char showDebug = FALSE;
unsigned char quit = FALSE;
while(!quit) {
update(grid, needsCheck, maxX, maxY);
if(showDebug) {
drawGrid(needsCheck, maxX, maxY);
}
else {
drawGrid(grid, maxX, maxY);
}
move(bottomY, 0);
addstr(speedStr);
char c = getch();
switch(c) {
case 'q':
quit = TRUE;
break;
case 'r':
randomGrid(grid, needsCheck, maxX * maxY);
break;
case '-':
speed += 10;
timeout(speed);
sprintf(speedStr, "%d", speed);
move(bottomY, 0);
addstr(" ");
break;
case '+':
speed -= 10;
if(speed < 0) {
speed = 0;
}
sprintf(speedStr, "%d", speed);
timeout(speed);
move(bottomY, 0);
addstr(" ");
break;
case ' ':
if(speed < 0) {
speed = oldSpeed;
}
else {
oldSpeed = speed;
speed = -1;
}
sprintf(speedStr, "%d", speed);
timeout(speed);
move(bottomY, 0);
addstr(" ");
break;
case 'd':
showDebug = !showDebug;
break;
case 'c':
clearGrid(grid, maxX * maxY, 0);
clearGrid(needsCheck,maxX * maxY, 0);
break;
case 'l':
loadFile("infinite.txt", grid, needsCheck, maxX, maxY);
break;
case 'g':
loadFile("glider.txt", grid, needsCheck, maxX, maxY);
break;
case 'o':
loadFile("gilders.txt", grid, needsCheck, maxX, maxY);
break;
}
}
//printf("%d", getValue(10, 10, grid, maxX, maxY));
endwin();
#ifdef TIME_TEST
if(timeLog != NULL) {
fclose(timeLog);
}
#endif
return 0;
}
int getValue(int x, int y, int * grid, unsigned int width, unsigned int height) {
if(x <= -1) {
x = width - 1;
}
else if(x >= width) {
x = 0;
}
if(y <= -1) {
y = height - 1;
}
else if(y >= height) {
y = 0;
}
return grid[x +(width*y)];
//return getValue(x, y, grid, width, height);
}
void setValue(int value, int x, int y, int * grid, int * needsCheck, unsigned int width, unsigned int height) {
if(x <= -1) {
x = width - 1;
}
else if(x >= width) {
x = 0;
}
if(y <= -1) {
y = height - 1;
}
else if(y >= height) {
y = 0;
}
grid[x + (width*y)] = value;
if(needsCheck != NULL) {
// give the option of sending in null for big batches of changes like clears
// this way we dont repeatedly set things to a value
// also if a value hasnt changed
needsCheck[x + (width*y)] = 1; // we have changed
// next do our moores neighbours
int i;
for(i = x-1; i <= x+1; i ++) {
int j;
for(j = y-1; j<= y+1; j ++) {
setValue(1, i, j, needsCheck, NULL, width, height);
}
}
}
}
void clearGrid(int * grid, unsigned int size, int value) {
unsigned int i;
for(i = 0; i < size; i ++) {
grid[i] = value;
}
}
void drawGrid(int * grid, unsigned int width, unsigned int height) {
int x, y;
for(y = 0; y < height; y ++) {
for(x = 0; x < width; x ++) {
move(y, x);
if(getValue(x, y, grid, width, height) > 0) {
attron(COLOR_PAIR(1));
addch('#');
attroff(COLOR_PAIR(1));
}
else {
attron(COLOR_PAIR(0));
addch(' ');
attroff(COLOR_PAIR(0));
}
}
}
}
void update(int * grid, int * needsCheck, unsigned int width, unsigned int height) {
#ifdef TIME_TEST
clock_t start = clock();
#endif
int newGrid[width * height];
int newNeedsCheck[width * height];
clearGrid(newNeedsCheck, width * height, 0);
unsigned int x, y;
for(x = 0; x < width; x ++) {
for(y = 0; y < height; y ++) {
int state = getValue(x, y, grid, width, height);
if(getValue(x, y, needsCheck, width, height) == 0) {
setValue(state, x, y, newGrid, NULL, width, height);
continue;
}
int neighbours = getNeighbours(x, y, grid, width, height);
if(state == 0) {
// dead
if(neighbours == 3) {
setValue(1, x, y, newGrid, newNeedsCheck, width, height);
}
else {
// no change
setValue(0, x, y, newGrid, NULL, width, height);
}
}
else if(state == 1) {
// alive
if(neighbours < 2 || neighbours > 3) {
setValue(0, x, y, newGrid, newNeedsCheck, width, height);
}
else {
// no change
setValue(1, x, y, newGrid, NULL, width, height);
}
}
}
}
// replace old grid
unsigned int i;
for(i = 0; i < width*height; i ++) {
grid[i] = newGrid[i];
needsCheck[i] = newNeedsCheck[i];
}
#ifdef TIME_TEST
clock_t stop = clock();
double diff = ((double) (stop - start)) / CLOCKS_PER_SEC;
fprintf(timeLog, "%.20f\n", diff);
#endif
}
int getNeighbours(unsigned int x, unsigned int y, int * grid, unsigned int width, unsigned int height) {
int total = 0;
total += getValue(x-1, y, grid, width, height);
total += getValue(x-1, y-1, grid, width, height);
total += getValue(x-1, y+1, grid, width, height);
total += getValue(x, y-1, grid, width, height);
total += getValue(x, y+1, grid, width, height);
total += getValue(x+1, y-1, grid, width, height);
total += getValue(x+1, y+1, grid, width, height);
total += getValue(x+1, y, grid, width, height);
return total;
}
void randomGrid(int * grid, int * needsCheck, unsigned int size) {
unsigned int i;
for(i = 0; i < size; i ++) {
grid[i] = rand() % 10 + 1 < 5 ? 0 : 1;
needsCheck[i] = 1;
}
}
bool loadFile(char * filename, int * grid, int * needsCheck, unsigned int width, unsigned int height) {
FILE * fp = NULL;
char line[80];
fp = fopen(filename, "rt");
if(fp == NULL) return false;
clearGrid(grid, width * height, 0);
unsigned int y = 0;
while(fgets(line, 80, fp) != NULL && y < height) {
unsigned int length = strlen(line);
unsigned int x;
for(x = 0; x < length && x < width; x ++) {
char c = line[x];
if(c == '#') {
setValue(1, x, y, grid, NULL, width, height);
}
//else {
// setValue(0, x, y, grid, width, height);
//}
}
y ++;
}
fclose(fp);
clearGrid(needsCheck, width * height, 1);
return TRUE;
}
++++++++++++++++++++++
++++++++++++++++++++++
++++++++++++++++++++++
++++++++++++++++++++++
++++++++++++++++++++++
+++++++++++++++++###+#
+++++++++++++++++#++++
++++++++++++++++++++##
++++++++++++++++++##+#
+++++++++++++++++#+#+#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment