Add files via upload
This commit is contained in:
parent
67a2c73583
commit
5a39e5d2b5
4
Makefile
Normal file
4
Makefile
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
all:
|
||||||
|
gcc main.c -std=c99 -o conway -g
|
||||||
|
debug:
|
||||||
|
gdb main
|
46
README.md
Normal file
46
README.md
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
# Conway game in ANSI C
|
||||||
|
|
||||||
|
```
|
||||||
|
Generation 0
|
||||||
|
.@...@@@@..@.@..@@@@..@.@....@@@..@.@@@.@@@@.@@@@.
|
||||||
|
.@.@@.@...@.@....@@.@.@.@.@.@....@@@@@@@@@@.@@.@..
|
||||||
|
@@.@@.@@..@@.@..@@@...@...@....@@@.@@@.@.@..@...@@
|
||||||
|
..@..@.@..@..@@.......@...@@...@..@.@@.@.@...@....
|
||||||
|
.....@.@.@.....@@..@@..@.@@@@@@.@..@@.@@@@@@@....@
|
||||||
|
@@@.@.@.@.@.....@@@...@..@..@.@@@@@.@....@.@@@@@..
|
||||||
|
@@@@@@.@@@@@...@@@@@@.@@@...@@@@...@@...@@@.@@@..@
|
||||||
|
.@@@@.@@.@.@..@.@..@@@..@..@.....@@@@@.@.@@.@..@@.
|
||||||
|
..@@.@@..@@..@@@....@.@..@@.......@.@.@@..@.@.@@..
|
||||||
|
@@.@.@.@@.@..@..@@.....@.@@..@....@.@@@@@.@@@@@@..
|
||||||
|
@...@@@.@.@@.@@@.@.@.@.@.@.........@@@@.@.@@@@.@..
|
||||||
|
@.@@@..@.@@.@@.@...@..@.@.@..@.@@.....@.@...@.@@..
|
||||||
|
.@.@@@@.@@@.......@@..@.@...@@.@...@.@@@@.@@.@..@@
|
||||||
|
@@@.@...@@@@.@....@@@.@@.@..@.@.@..@@.@.@.@@@@@@@.
|
||||||
|
.@@@.@..@@..@..@@@@.@..@@@......@@@@.@@@..@@...@@@
|
||||||
|
@@@@.........@.@.......@@.@@@@...@@.@@.@@@@@.@.@..
|
||||||
|
@..@@@@@......@@....@@@.....@.....@@@..@..@...@..@
|
||||||
|
@@..@..@.@@.@@..@@.@...@..@@@@.....@.@@........@@@
|
||||||
|
.@@...@@@........@@@@.@..@....@@@@@.@.@......@@...
|
||||||
|
@@.@@...@@...@@@@..@@.@@@@.....@.@.@@@@..@@.@.@.@@
|
||||||
|
```
|
||||||
|
|
||||||
|
An *ANSI C* implementation of [Conway's Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life)
|
||||||
|
|
||||||
|
Compile with `make`
|
||||||
|
|
||||||
|
## Example usages
|
||||||
|
|
||||||
|
* Basic (default is random)
|
||||||
|
`./conway`
|
||||||
|
* 20x20 calc grid, 5x10 view grid
|
||||||
|
`./conway --calc 20x20 --view 5x10`
|
||||||
|
* Change chars
|
||||||
|
`./conway --dead-c - --alive-c Q`
|
||||||
|
* No heading, get 10th gen
|
||||||
|
`./conway --no-head --gen 10`
|
||||||
|
* Input initial sequence
|
||||||
|
`./conway --cells 5,5.6,6.4,7.5,7.6,7`
|
||||||
|
|
||||||
|
## Demonstration
|
||||||
|
|
||||||
|
[![asciicast](https://asciinema.org/a/PovKEcCgJLJKQJjOlfyHlTpCb.svg)](https://asciinema.org/a/PovKEcCgJLJKQJjOlfyHlTpCb)
|
137
args.c
Normal file
137
args.c
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
/**
|
||||||
|
* @file args.c
|
||||||
|
* @author MatMasIt
|
||||||
|
* @brief Argument Parsing for the conway Game of Life program
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2022-03-12
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
// element considered, flags or vals
|
||||||
|
|
||||||
|
#define L_VAL 0 // Value
|
||||||
|
#define L_CAL 2 // --calc rowsxcols
|
||||||
|
#define T_CAL "--calc"
|
||||||
|
#define L_VIE 3 // --view rowsxcols
|
||||||
|
#define T_VIE "--view"
|
||||||
|
#define L_GEN 4 // --gen
|
||||||
|
#define T_GEN "--gen"
|
||||||
|
#define L_NHG 5 // --no-head
|
||||||
|
#define T_NHG "--no-head"
|
||||||
|
#define L_DED 6 // --dead-c
|
||||||
|
#define T_DED "--dead-c"
|
||||||
|
#define L_ALC 7 // --alive-c
|
||||||
|
#define T_ALC "--alive-c"
|
||||||
|
#define L_CEL 9 // --cells
|
||||||
|
#define T_CEL "--cells"
|
||||||
|
|
||||||
|
#define CR 20
|
||||||
|
#define CC 50
|
||||||
|
#define VR 20
|
||||||
|
#define VC 50
|
||||||
|
|
||||||
|
#define DEADC '.'
|
||||||
|
#define ALIVEC '@'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief struct containing program arguments
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint64_t calcRows;
|
||||||
|
uint64_t calcCols;
|
||||||
|
// --calc rxc
|
||||||
|
uint64_t viewRows;
|
||||||
|
uint64_t viewCols;
|
||||||
|
// --view rxc
|
||||||
|
uint64_t requestedGen; // --gen
|
||||||
|
bool headerShow; // --no-head
|
||||||
|
char deadc; // --dead-c
|
||||||
|
char alivec; // --alive-c
|
||||||
|
bool interactive;
|
||||||
|
char *cells; // x,y.x,y etc --cells
|
||||||
|
} args;
|
||||||
|
/**
|
||||||
|
* @brief parse
|
||||||
|
*
|
||||||
|
* @param argc argument count
|
||||||
|
* @param argv arguments pointer
|
||||||
|
* @return args argument struct
|
||||||
|
*/
|
||||||
|
args parseArgs(int argc, char **argv)
|
||||||
|
{
|
||||||
|
args a;
|
||||||
|
a.calcRows = CR;
|
||||||
|
a.calcCols = CC;
|
||||||
|
a.viewRows = VR;
|
||||||
|
a.viewCols = VC;
|
||||||
|
a.interactive = TRUE;
|
||||||
|
a.requestedGen = 0;
|
||||||
|
a.headerShow = TRUE;
|
||||||
|
a.alivec = ALIVEC;
|
||||||
|
a.deadc = DEADC;
|
||||||
|
a.cells = NULL;
|
||||||
|
uint8_t last;
|
||||||
|
for (uint8_t i = 0; i < argc; i++)
|
||||||
|
{
|
||||||
|
char *s = argv[i];
|
||||||
|
if (!strcmp(s, T_CAL))
|
||||||
|
{
|
||||||
|
last = L_CAL;
|
||||||
|
}
|
||||||
|
else if (!strcmp(s, T_VIE))
|
||||||
|
{
|
||||||
|
last = L_VIE;
|
||||||
|
}
|
||||||
|
else if (!strcmp(s, T_GEN))
|
||||||
|
{
|
||||||
|
last = L_GEN;
|
||||||
|
}
|
||||||
|
else if (!strcmp(s, T_NHG))
|
||||||
|
{
|
||||||
|
last = L_VAL;
|
||||||
|
a.headerShow = FALSE;
|
||||||
|
}
|
||||||
|
else if (!strcmp(s, T_DED))
|
||||||
|
{
|
||||||
|
last = L_DED;
|
||||||
|
}
|
||||||
|
else if (!strcmp(s, T_ALC))
|
||||||
|
{
|
||||||
|
last = L_ALC;
|
||||||
|
}
|
||||||
|
else if (!strcmp(s, T_CEL))
|
||||||
|
{
|
||||||
|
last = L_CEL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (last)
|
||||||
|
{
|
||||||
|
case L_CAL:
|
||||||
|
sscanf(s, "%" PRIu64 "x%" PRIu64 "", &a.calcRows, &a.calcCols);
|
||||||
|
break;
|
||||||
|
case L_VIE:
|
||||||
|
sscanf(s, "%" PRIu64 "x%" PRIu64 "", &a.viewRows, &a.viewCols);
|
||||||
|
break;
|
||||||
|
case L_GEN:
|
||||||
|
sscanf(s, "%" PRIu64 "", &a.requestedGen);
|
||||||
|
a.interactive = FALSE;
|
||||||
|
break;
|
||||||
|
case L_DED:
|
||||||
|
sscanf(s, "%c", &a.deadc);
|
||||||
|
break;
|
||||||
|
case L_ALC:
|
||||||
|
sscanf(s, "%c", &a.alivec);
|
||||||
|
break;
|
||||||
|
case L_CEL:
|
||||||
|
a.cells = s;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last = L_VAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
203
conway.c
Normal file
203
conway.c
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
/**
|
||||||
|
* @file conway.c
|
||||||
|
* @author MatMasIt
|
||||||
|
* @brief Conway game of life main game functions
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2022-03-12
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Game struct
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint64_t generation;
|
||||||
|
uint64_t rows;
|
||||||
|
uint64_t cols;
|
||||||
|
uint64_t viewRows;
|
||||||
|
uint64_t viewCols;
|
||||||
|
bool *data;
|
||||||
|
} Game;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief instantiate a new game
|
||||||
|
*
|
||||||
|
* @param calcRows rows of the calculation matrix
|
||||||
|
* @param calcCols cols of the calculation matrix
|
||||||
|
* @param viewRows rows of the viewport matrix
|
||||||
|
* @param viewCols cols of the viewport matrix
|
||||||
|
* @param error error pointer
|
||||||
|
* @return Game game struct
|
||||||
|
*/
|
||||||
|
Game newGame(uint64_t calcRows, uint64_t calcCols, uint64_t viewRows, uint64_t viewCols, bool *error)
|
||||||
|
{
|
||||||
|
Game g;
|
||||||
|
if (viewRows > calcRows || viewCols > calcCols)
|
||||||
|
{
|
||||||
|
*error = TRUE;
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
g.generation = 0;
|
||||||
|
g.rows = calcRows;
|
||||||
|
g.cols = calcCols;
|
||||||
|
g.viewRows = viewRows;
|
||||||
|
g.viewCols = viewCols;
|
||||||
|
g.data = calloc(1, g.rows * g.cols * sizeof(bool));
|
||||||
|
if (g.data == NULL)
|
||||||
|
{
|
||||||
|
*error = TRUE;
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
*error = FALSE;
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Check if coordinates are valid
|
||||||
|
*
|
||||||
|
* @param g Game
|
||||||
|
* @param x x-coord
|
||||||
|
* @param y y-cord
|
||||||
|
* @return true if valid
|
||||||
|
* @return false if not valid
|
||||||
|
*/
|
||||||
|
bool checkCoords(Game *g, uint64_t x, uint64_t y)
|
||||||
|
{
|
||||||
|
if (x > g->cols - 1 || y > g->rows - 1)
|
||||||
|
return FALSE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set a cell's value
|
||||||
|
*
|
||||||
|
* @param g Game
|
||||||
|
* @param x x-coord
|
||||||
|
* @param y y-coord
|
||||||
|
* @param isAlive aliveness status
|
||||||
|
* @return true: success, false: error
|
||||||
|
*/
|
||||||
|
bool setCell(Game *g, uint64_t x, uint64_t y, bool isAlive)
|
||||||
|
{
|
||||||
|
if (!checkCoords(g, x, y))
|
||||||
|
return FALSE;
|
||||||
|
g->data[x + y * g->cols] = isAlive;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Get a cell's valie
|
||||||
|
*
|
||||||
|
* @param g Game
|
||||||
|
* @param x x-coord
|
||||||
|
* @param y y-coord
|
||||||
|
* @param error error pointer
|
||||||
|
* @return true: alive, false: not-alive
|
||||||
|
*/
|
||||||
|
bool getCell(Game *g, uint64_t x, uint64_t y, bool *error)
|
||||||
|
{
|
||||||
|
if (!checkCoords(g, x, y))
|
||||||
|
{
|
||||||
|
*error = TRUE;
|
||||||
|
return ALIVE;
|
||||||
|
}
|
||||||
|
*error = FALSE;
|
||||||
|
return g->data[x + y * g->cols];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Count the number of alive neigbours for a cell
|
||||||
|
*
|
||||||
|
* @param g Game
|
||||||
|
* @param x x-coord
|
||||||
|
* @param y y-coord
|
||||||
|
* @return int number of alive neigbours
|
||||||
|
*/
|
||||||
|
int countLiveNeighbours(Game *g, uint64_t x, uint64_t y)
|
||||||
|
{
|
||||||
|
uint8_t alive = 0;
|
||||||
|
bool error = FALSE;
|
||||||
|
if (getCell(g, x - 1, y - 1, &error) == ALIVE && !error)
|
||||||
|
alive++;
|
||||||
|
if (getCell(g, x - 1, y, &error) == ALIVE && !error)
|
||||||
|
alive++;
|
||||||
|
if (getCell(g, x - 1, y + 1, &error) == ALIVE && !error)
|
||||||
|
alive++;
|
||||||
|
|
||||||
|
if (getCell(g, x, y - 1, &error) == ALIVE && !error)
|
||||||
|
alive++;
|
||||||
|
if (getCell(g, x, y + 1, &error) == ALIVE && !error)
|
||||||
|
alive++;
|
||||||
|
|
||||||
|
if (getCell(g, x + 1, y - 1, &error) == ALIVE && !error)
|
||||||
|
alive++;
|
||||||
|
if (getCell(g, x + 1, y, &error) == ALIVE && !error)
|
||||||
|
alive++;
|
||||||
|
if (getCell(g, x + 1, y + 1, &error) == ALIVE && !error)
|
||||||
|
alive++;
|
||||||
|
return alive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Progress game by calculating the new matrix and increasing generation
|
||||||
|
*
|
||||||
|
* @param g Game
|
||||||
|
*/
|
||||||
|
void progress(Game *g)
|
||||||
|
{
|
||||||
|
bool error;
|
||||||
|
Game c = newGame(g->rows, g->cols, g->viewRows, g->viewCols, &error); // new temp field to apply all rules instantly
|
||||||
|
uint8_t liveN;
|
||||||
|
bool val;
|
||||||
|
memcpy(c.data, g->data, g->rows * g->cols * sizeof(bool));
|
||||||
|
c.generation = g->generation + 1;
|
||||||
|
for (uint64_t y = 0; y < g->rows; y++)
|
||||||
|
{
|
||||||
|
for (uint64_t x = 0; x < g->cols; x++)
|
||||||
|
{
|
||||||
|
val = getCell(g, x, y, &error);
|
||||||
|
liveN = countLiveNeighbours(g, x, y);
|
||||||
|
if (val == DEAD && liveN == 3)
|
||||||
|
setCell(&c, x, y, ALIVE); // Any dead cell with three live neighbours becomes a live cell
|
||||||
|
else if (val == ALIVE && (liveN == 2 || liveN == 3))
|
||||||
|
setCell(&c, x, y, ALIVE); // Any live cell with two or three live neighbours survives
|
||||||
|
else
|
||||||
|
setCell(&c, x, y, DEAD); // All other cells either stay dead or die
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(g->data);
|
||||||
|
// copy struct and free previous field
|
||||||
|
*g = c;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Set random population
|
||||||
|
*
|
||||||
|
* @param g Game
|
||||||
|
*/
|
||||||
|
void randomPopulate(Game *g)
|
||||||
|
{
|
||||||
|
srand(time(NULL));
|
||||||
|
for (uint64_t y = 0; y < g->rows; y++)
|
||||||
|
{
|
||||||
|
for (uint64_t x = 0; x < g->cols; x++)
|
||||||
|
{
|
||||||
|
if (rand() % 2)
|
||||||
|
setCell(g, x, y, ALIVE);
|
||||||
|
else
|
||||||
|
setCell(g, x, y, DEAD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Build a game from args struct
|
||||||
|
*
|
||||||
|
* @param a the args struct
|
||||||
|
* @param error error pointer
|
||||||
|
* @return Game Game
|
||||||
|
*/
|
||||||
|
Game gameFromArgs(args a, bool *error)
|
||||||
|
{
|
||||||
|
Game c = newGame(a.calcRows, a.calcCols, a.viewRows, a.viewCols, error);
|
||||||
|
return c;
|
||||||
|
}
|
35
display.c
Normal file
35
display.c
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/**
|
||||||
|
* @file display.c
|
||||||
|
* @author MatMasIt
|
||||||
|
* @brief Handles displaying of the game
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2022-03-12
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @brief print the screen matrix
|
||||||
|
*
|
||||||
|
* @param g Game
|
||||||
|
* @param a Arguments
|
||||||
|
*/
|
||||||
|
void printScreen(Game *g, args a)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
bool error;
|
||||||
|
if (a.headerShow)
|
||||||
|
printf("Generation %" PRIu64 "\n", g->generation);
|
||||||
|
for (uint64_t y = 0; y < g->viewRows; y++)
|
||||||
|
{
|
||||||
|
for (uint64_t x = 0; x < g->viewCols; x++)
|
||||||
|
{
|
||||||
|
if (getCell(g, x, y, &error) == DEAD)
|
||||||
|
c = a.deadc;
|
||||||
|
else
|
||||||
|
c = a.alivec;
|
||||||
|
printf("%c", c);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
91
main.c
Normal file
91
main.c
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
/**
|
||||||
|
* @file main.c
|
||||||
|
* @author MatMasIt
|
||||||
|
* @brief The Conway game of life in ANSI C
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2022-03-12
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#define bool uint8_t
|
||||||
|
#define TRUE 1
|
||||||
|
#define FALSE 0
|
||||||
|
#define ALIVE TRUE
|
||||||
|
#define DEAD FALSE
|
||||||
|
#include "args.c"
|
||||||
|
#include "conway.c"
|
||||||
|
#include "display.c"
|
||||||
|
/**
|
||||||
|
* @brief The main function
|
||||||
|
*
|
||||||
|
* @param argc argument count
|
||||||
|
* @param argv arguments pointer
|
||||||
|
* @return int program result
|
||||||
|
*/
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
args ar = parseArgs(argc, argv);
|
||||||
|
char t;
|
||||||
|
bool error;
|
||||||
|
Game g = gameFromArgs(ar, &error);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
printf("Initialization error: check arguments\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
uint64_t i = 0;
|
||||||
|
if (ar.cells == NULL)
|
||||||
|
{
|
||||||
|
randomPopulate(&g);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const char *curLine = ar.cells;
|
||||||
|
while (curLine)
|
||||||
|
{
|
||||||
|
const char *nextLine = strchr(curLine, '.');
|
||||||
|
uint64_t x, y;
|
||||||
|
int curLineLen = nextLine ? (nextLine - curLine) : strlen(curLine);
|
||||||
|
char *tempStr = (char *)malloc(curLineLen + 1);
|
||||||
|
if (tempStr)
|
||||||
|
{
|
||||||
|
memcpy(tempStr, curLine, curLineLen);
|
||||||
|
tempStr[curLineLen] = '\0'; // NUL-terminate!
|
||||||
|
sscanf(tempStr, "%" PRIu64 ",%" PRIu64 "", &x, &y);
|
||||||
|
setCell(&g, x, y, ALIVE);
|
||||||
|
free(tempStr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
printf("Memory allocation error\n");
|
||||||
|
|
||||||
|
curLine = nextLine ? (nextLine + 1) : NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
if (ar.requestedGen != 0)
|
||||||
|
{
|
||||||
|
if (i == ar.requestedGen)
|
||||||
|
{
|
||||||
|
printScreen(&g, ar);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printScreen(&g, ar);
|
||||||
|
}
|
||||||
|
if (ar.interactive)
|
||||||
|
scanf("%c", &t);
|
||||||
|
progress(&g);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user