162 lines
4.7 KiB
C
162 lines
4.7 KiB
C
/**
|
|
* Yet another goddamn implementation of Conway's Game of Life.
|
|
* I'm under the impression that every programmer must do this at some point,
|
|
* and since I've been programming for a long time I guess I should get it out
|
|
* of the way...
|
|
*
|
|
* (c) 2023 A.M. Rowsell
|
|
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
|
* If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
// so many damn includes
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <wchar.h>
|
|
#include <locale.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
void printGrid(int gridX, int gridY, int **arr, int generation) {
|
|
char title[16];
|
|
snprintf(title, 16, "Generation %d", generation);
|
|
int spaces = ((float)gridX / 2.0F) - (strlen(title) / 2.0);
|
|
if (spaces <= 0) {
|
|
wprintf(L"%s\n", title);
|
|
} else {
|
|
for(int i = 0; i < spaces; i++) {
|
|
wprintf(L" ");
|
|
}
|
|
wprintf(L"%s\n", title);
|
|
}
|
|
wprintf(L"%lc", 0x2554UL); // prints ╔
|
|
for (int j = 0; j < gridX; j++) {
|
|
wprintf(L"%lc", 0x2550UL); // prints ═
|
|
}
|
|
wprintf(L"%lc", 0x2557UL); // prints ╗
|
|
wprintf(L"\n");
|
|
for (int j = 0; j < gridY; j++) {
|
|
wprintf(L"%lc", 0x2551UL); // prints ║
|
|
for (int i = 0; i < gridX; i++) {
|
|
wprintf(L"%lc", ((arr[i][j] == 1) ? 0x0023UL : 0x0020UL));
|
|
}
|
|
wprintf(L"%lc\n", 0x2551UL); // prints ║
|
|
}
|
|
wprintf(L"%lc", 0x255AUL); // prints ╚
|
|
for (int j = 0; j < gridX; j++) {
|
|
wprintf(L"%lc", 0x2550UL);
|
|
}
|
|
wprintf(L"%lc", 0x255DUL); // prints ╝
|
|
|
|
return;
|
|
}
|
|
|
|
void doGeneration(int gridX, int gridY, int **arr) {
|
|
// add up all live cells from [x-1][y-1] to [x+1][y+1]
|
|
// if total is 3, cell becomes alive
|
|
// if total is 4, cell retains state
|
|
// any other, cell dies
|
|
// also, all x/y are modulo gridX gridY so we get wraparound
|
|
|
|
// temporary array to hold processed generation
|
|
int *tempArr[gridX];
|
|
for(int i = 0; i < gridX; i++) {
|
|
tempArr[i] = (int *)malloc(sizeof(int)*gridY);
|
|
}
|
|
for(int i = 0; i < gridX; i++) {
|
|
for(int j = 0; j < gridY; j++) {
|
|
tempArr[i][j] = arr[i][j];
|
|
}
|
|
}
|
|
// total keeps track of live neighbours
|
|
int total = 0;
|
|
for(int i = 0; i < gridY; i++) {
|
|
// start of a line
|
|
for(int j = 0; j < gridX; j++) {
|
|
total = 0;
|
|
// start of 9-cell eval
|
|
for(int k = -1; k < 2; k++) {
|
|
for(int l = -1; l < 2; l++) {
|
|
total += (arr[(j+k)%gridX][(i+l)%gridY] == 1) ? 1 : 0;
|
|
}
|
|
}
|
|
if(total == 3) {
|
|
tempArr[j][i] = 1;
|
|
} else if (total == 4) {
|
|
tempArr[j][i] = arr[j][i];
|
|
} else {
|
|
tempArr[j][i] = 0;
|
|
}
|
|
}
|
|
}
|
|
for(int i = 0; i < gridX; i++) {
|
|
for(int j = 0; j < gridY; j++) {
|
|
arr[i][j] = tempArr[i][j];
|
|
}
|
|
}
|
|
// free all that memory
|
|
for(int i = 0; i < gridX; i++) {
|
|
free(tempArr[i]);
|
|
}
|
|
return;
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
if (argc < 3) {
|
|
printf("Usage: conway <xsize> <ysize> [seed]\n");
|
|
exit(255);
|
|
}
|
|
setlocale(LC_CTYPE, "");
|
|
int gridX = 0, gridY = 0, seed = 0, generation = 0;
|
|
for (int i = argc - 1; i > 0; i--) {
|
|
switch (i) {
|
|
case 1:
|
|
gridX = atoi(argv[i]);
|
|
break;
|
|
case 2:
|
|
gridY = atoi(argv[i]);
|
|
break;
|
|
case 3:
|
|
seed = atoi(argv[i]);
|
|
break;
|
|
}
|
|
}
|
|
if (seed == 0) {
|
|
time_t t;
|
|
srand((unsigned)time(&t));
|
|
} else {
|
|
srand(seed);
|
|
}
|
|
// dynamically allocate the 2D array, could be quite large!
|
|
int *arr[gridX];
|
|
for (int i = 0; i < gridX; i++) {
|
|
arr[i] = (int*)malloc(gridY * sizeof(int));
|
|
}
|
|
// seed the array
|
|
for (int i = 0; i < gridX; i++) {
|
|
for (int j = 0; j < gridY; j++) {
|
|
arr[i][j] = (rand() % 2 == 0) ? 1 : 0;
|
|
}
|
|
}
|
|
// display initial grid
|
|
printGrid(gridX, gridY, arr, generation);
|
|
// loop doing gens until user decides to quit
|
|
char choice[] = "y";
|
|
while(strcmp(choice, "y") == 0) {
|
|
wprintf(L"\n");
|
|
generation++;
|
|
doGeneration(gridX, gridY, arr);
|
|
printGrid(gridX, gridY, arr, generation);
|
|
wprintf(L"\nDo another generation? [y/n]: ");
|
|
sprintf(choice, "%c", tolower(getchar()));
|
|
getchar(); // consome the newline
|
|
}
|
|
// clean up allocated memory
|
|
for(int i = 0; i < gridX; i++) {
|
|
free(arr[i]);
|
|
}
|
|
return 0;
|
|
}
|