Last active
August 29, 2015 14:10
-
-
Save markjgap/0007ed6319c21c8983c2 to your computer and use it in GitHub Desktop.
Written in C, program is an example of discrete event simulation, where a world of entities live, die, or are born based on their surrounding neighbors. Each time step simulates another round of living or dying.
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
#include <stdlib.h> | |
#include <stdio.h> | |
#include <unistd.h> | |
#include <sys/time.h> | |
#include <string.h> | |
/* | |
* An example of discrete event simulation, where a world of entities live, die, or are born based on their surrounding neighbors. | |
* Each time step simulates another round of living or dying. This cellular automation can take any initial configuration and | |
* be observed as it evolves through its life creating unique patterns. | |
*/ | |
///////////////// Forward Declarations ///////////////// | |
int *init_board(int rows, int columns); | |
int getPos(int x, int y, int columns); | |
void printBoard(int *board, int rows, int columns, int step); | |
int *tick(int *board, int rows, int columns); | |
int countNeighbors(int *board, int rows, int columns, int x, int y); | |
/////////////// Main /////////////// | |
int main(int argc, char *argv[]) { | |
struct timeval start_time; // holds beginning time | |
struct timeval end_time; // holds completion time | |
// checks command line input contains 3 arguments | |
// If not 3, prints a usage message | |
if(argc != 3){ | |
printf("Usage: %s <file> <num>\n", argv[0]); | |
printf(" Note: <num> = 1 or 0\n"); | |
printf("Example:\n"); | |
printf(" linux> %s file.txt 0\n", argv[0]); | |
printf(" linux> %s file.txt 1\n", argv[0]); | |
exit(1); | |
} | |
char *filename = argv[1]; // saves string of text file passed into gol | |
FILE *file = fopen(filename, "r"); // opens and read text file | |
if(file == NULL) { | |
printf("%s: File open failed.\n", argv[1]); | |
exit(1); | |
} | |
int arg_input = strtol(argv[2], NULL, 10); // converts string into int | |
// verifies only 1 or 0 is inputted | |
// 1 enables gol board print | |
// 0 disables gol board print | |
if (arg_input != 0 && arg_input != 1){ | |
printf("Usage: %s <file> <num>\n", argv[0]); | |
printf(" Note: <num> = 1 or 0\n"); | |
printf("Example:\n"); | |
printf(" linux> %s file.txt 0\n", argv[0]); | |
printf(" linux> %s file.txt 1\n", argv[0]); | |
exit(1); | |
} | |
// board initialization | |
int rows, columns, step, x, y; | |
int ret = fscanf(file, "%d", &rows); // first line in file is row size | |
ret = fscanf(file, "%d", &columns); // second line in file is column size | |
ret = fscanf(file, "%d", &step); // third line in file is number of iterations | |
int *board = init_board(rows, columns); | |
int pairs = 0; | |
ret = fscanf(file, "%d", &pairs); // fouth line is total of live cells to start | |
while(ret != -1) { | |
ret = fscanf(file, "%d %d", &y, &x); | |
board[getPos(x,y,columns)] = 1; | |
} | |
fclose(file); | |
int i = 0; | |
// begin timer | |
ret = gettimeofday(&start_time, NULL); | |
while(i <= step) { | |
// prints board if it is enabled. argv[2] = 1 | |
if(arg_input == 1){ | |
printBoard(board, rows, columns, i); | |
} | |
board = tick(board, rows, columns); | |
i++; | |
} | |
// end timer | |
ret = gettimeofday(&end_time, NULL); | |
// calculates the time difference from start to end. | |
struct timeval diff; | |
diff.tv_sec = end_time.tv_sec - start_time.tv_sec; | |
diff.tv_usec = end_time.tv_usec - start_time.tv_usec; | |
double seconds = (double)diff.tv_sec; | |
double micro = (double)diff.tv_usec; | |
micro /= 1000000.0; | |
printf("Total time for %d iterations of %dx%d world is %f secs\n\n" | |
, step, rows, columns,seconds+micro); | |
free(board); | |
return 0; | |
} | |
/////////////// Functions //////////////// | |
/* | |
* Function initializes board with 0 (non-live cells) | |
* @param rows - number of rows on board | |
* @param columns - number of columns to print | |
* @return - 0 at specified coordinates | |
*/ | |
int *init_board(int rows, int columns) { | |
int *board = malloc(sizeof(int)*rows*columns); | |
if(board == NULL) { | |
printf("Malloc failed. Exiting."); | |
exit(1); | |
} | |
int i; | |
for(i = 0; i < rows*columns; i++) { | |
board[i] = 0; | |
} | |
return board; | |
} | |
/* | |
* Function updates board | |
* @param board - pointer to board | |
* @param rows - row size | |
* @param columns - column size | |
* @return - updated board | |
*/ | |
int *tick(int *board, int rows, int columns) { | |
// allocates space for new board | |
int *temp = malloc(sizeof(int)*rows*columns); | |
if(temp == NULL) { | |
printf("Malloc failed. Exiting."); | |
exit(1); | |
} | |
int x, y, count; | |
for(y = 0; y < rows; y++) { | |
for(x = 0; x < columns; x++) { | |
count = countNeighbors(board, rows, columns, x, y); | |
if(board[getPos(x,y,columns)] == 1) { | |
if(count < 2 || count > 3) temp[getPos(x,y,columns)] = 0; | |
else temp[getPos(x,y,columns)] = 1; | |
} | |
else { | |
if(count == 3) temp[getPos(x,y,columns)] = 1; | |
else temp[getPos(x,y,columns)] = 0; | |
} | |
} | |
} | |
free(board); // frees old board memory | |
return temp; | |
} | |
/* | |
* Function counts live cells around a particular center cell | |
* @param board - pointer to board | |
* @param rows - row size | |
* @param column column size | |
* @param x - x coordinate of center cell | |
* @param y - y coordinate of center cell | |
* @return - number of live cells around center cell. | |
*/ | |
int countNeighbors(int *board, int rows, int columns, int x, int y) { | |
int count = 0; | |
int n1, n2, n3, n4, n5, n6, n7, n8; // the surrounding cells | |
int l = x-1; | |
int r = x+1; | |
int u = y-1; | |
int d = y+1; | |
if(l < 0) l = columns-1; | |
if(r >= columns) r = 0; | |
if(u < 0) u = rows-1; | |
if(d >= rows) d = 0; | |
n1 = getPos(l, u, columns); // top left corner cell | |
n2 = getPos(x, u, columns); // top cell | |
n3 = getPos(r, u, columns); // top right corner cell | |
n4 = getPos(l, y, columns); // left cell | |
n5 = getPos(r, y, columns); // right cell | |
n6 = getPos(l, d, columns); // bottom left corner cell | |
n7 = getPos(x, d, columns); // bottom cell | |
n8 = getPos(r, d, columns); // bottom right corner cell | |
// total number of live cells around center cell | |
count = board[n1] + board[n2] + board[n3] + board[n4] + board[n5] + | |
board[n6] + board[n7] + board[n8]; | |
return count; | |
} | |
/* | |
* Function prints board status with '@' representing live cells | |
* and '-' represents non-live cells. | |
* @param board - pointer to current board | |
* @param rows - row size | |
* @param column - column size | |
* @param step - number of iterations to do | |
*/ | |
void printBoard(int *board, int rows, int columns, int step) { | |
system("clear"); // helps keep the print out in a consistant location | |
printf("Time Step: %d\n", step); | |
int x, y; | |
int count; | |
for(y = 0; y < rows; y++) { | |
for(x = 0; x < columns; x++) { | |
count = countNeighbors(board, rows, columns, x, y); | |
if(board[getPos(x,y,columns)] == 0) printf("- "); | |
else printf("@ "); | |
} | |
printf("\n"); | |
} | |
usleep(200000); // pauses program for .2 seconds to view board changes | |
} | |
/* | |
* Function takes coordinates of a 2D array and converts to an index of a 1D array | |
* @param x - column number of cell | |
* @param y - row number of cell | |
* @param columns - column size | |
* @return - equivalent index position in a 1D array. | |
*/ | |
int getPos(int x, int y, int columns) { | |
return (columns*y)+x; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment