/** * 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 #include #include #include #include #include #include #include #include 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 [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; }