Last active
August 29, 2015 13:58
-
-
Save LyndonArmitage/10275443 to your computer and use it in GitHub Desktop.
Basic Conways Game Of Life in C
This file contains 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
#.. | |
.## | |
##. |
This file contains 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
// 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; | |
} |
This file contains 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
++++++++++++++++++++++ | |
++++++++++++++++++++++ | |
++++++++++++++++++++++ | |
++++++++++++++++++++++ | |
++++++++++++++++++++++ | |
+++++++++++++++++###+# | |
+++++++++++++++++#++++ | |
++++++++++++++++++++## | |
++++++++++++++++++##+# | |
+++++++++++++++++#+#+# |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment