This program uses multidimensional arrays to run through the algorithm for Conway’s Game of Life.
//Conway's Game of Life by Jack P. Oakley //This program gives various options to play Conway's Game of Life as referenced //from https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life #include <iostream> using namespace std; #include <fstream> #include <stdlib.h> #include <time.h> const int maxHeight = 25; const int maxWidth = 45; void title(void); void newBoard(char board[][maxWidth], int &rows, int &columns); void createBoard(char board[][maxWidth], int &numRows, int &numCols); void loadFile(int &numRows, int &numCols, char board[][maxWidth]); void useBoard(char board[][maxWidth], int &rows, int &columns); void border(char board[][maxWidth], int rows, int columns); void displayBoard(char board[][maxWidth], int numRows, int numCols); void liveCount(char board[][maxWidth], int numRows, int numCols); void holdScreen(void); int menu(void); int getTurns(void); void playGame(char board[][maxWidth], int numRows, int numCols, int numTurns); void restartGame(char board[][maxWidth], char savedBoard[][maxWidth], int numRows, int numCols); void nextGeneration(char board[][maxWidth], int numRows, int numCols); int neighbors(char board[][maxWidth], int rix, int cix); void copyArray(char destArray[][maxWidth], char sourceArray[][maxWidth], int numRows, int numCols); void animation(char board[][maxWidth], int numRows, int numCols, int numTurns); void randomBoard(char board[][maxWidth], int &rows, int &columns); /******************************************************************************* * main function: * * PURPOSE: Drives the program * * IN: none * * OUT: none * *******************************************************************************/ int main() { fstream infile; srand(time(NULL)); int option, numRows, numCols, numTurns; char board[maxHeight][maxWidth]; char savedBoard[maxHeight][maxWidth]; title(); newBoard(board, numRows, numCols); border(board, numRows, numCols); displayBoard(board, numRows, numCols); liveCount(board, numRows, numCols); holdScreen(); copyArray(savedBoard, board, numRows, numCols); do { option = menu(); if (option == 1) { numTurns = getTurns(); playGame(board, numRows, numCols, numTurns); } else if (option == 2) { restartGame(board, savedBoard, numRows, numCols); } else if (option == 3) { displayBoard(board, numRows, numCols); liveCount(board, numRows, numCols); holdScreen(); } else if (option == 4) { newBoard(board, numRows, numCols); border(board, numRows, numCols); displayBoard(board, numRows, numCols); liveCount(board, numRows, numCols); holdScreen(); copyArray(savedBoard, board, numRows, numCols); } else if (option == 5) { numTurns = 100; animation(board, numRows, numCols, numTurns); } } while (option != 6); } //End main() /******************************************************************************* * title function: * * PURPOSE: Display title & description by keeping main() a little cleaner * * IN: none * * OUT: none * *******************************************************************************/ void title(void) { cout << "Conway's Game of Life" << endl << endl; cout << "This program gives multiple options for Conway's Game of Life." << endl << endl; } //End title() /******************************************************************************* * newBoard function: * * PURPOSE: Give user a choice for how to start a new board and select the * * associated method * * IN: 2-D array to hold new board, 2 int containers to hold row size & col size* * OUT: Reference Params: 2-D array, 2 ints * *******************************************************************************/ void newBoard(char board[][maxWidth], int &rows, int &columns) { fstream infile; int choice; do { cout << "You have the following options:" << endl; cout << "[1] Enter New Board via Keyboard" << endl; cout << "[2] Load Board from Data File" << endl; cout << "[3] Use Predefined Board" << endl; cout << "[4] Generate Random Board" << endl; cin >> choice; if (choice < 1 || choice > 4) { cout << "Please enter an option from 1 to 4." << endl; } } while (choice < 1 || choice > 4); if (choice == 1) { createBoard(board, rows, columns); } else if (choice == 2) { loadFile(rows, columns, board); } else if (choice == 3) { useBoard(board, rows, columns); } else { randomBoard(board, rows, columns); } } //End newBoard() /******************************************************************************* * createBoard function: * * PURPOSE: Create a new board by way of keyboard entry * * IN: 2-D array to hold new board, 2 int containers to hold row size & col size* * OUT: Reference Params: 2-D array, 2 ints * *******************************************************************************/ void createBoard(char board[][maxWidth], int &numRows, int &numCols) { int rix, cix, liveR, liveC; char another; const int minRows = 5; const int minCols = 5; const int maxRows = 20; const int maxCols = 40; do { cout << "Enter the number of rows (" << minRows << "-" << maxRows << "): "; cin >> numRows; if (numRows < minRows || numRows > maxRows) { cout << "Please enter a value from " << minRows << " to " << maxRows << "." << endl; } } while (numRows < minRows || numRows > maxRows); do { cout << "Enter the number of columns (" << minCols << "-" << maxCols << "): "; cin >> numCols; if (numCols < minCols || numCols > maxCols) { cout << "Please enter a value from " << minCols << " to " << maxCols << "." << endl; } } while (numCols < minCols || numCols > maxCols); for (rix = 0; rix < numRows + 2; ++rix) { for (cix = 0; cix < numCols + 2; ++cix) { board[rix][cix] = ' '; } } do { do { cout << "Enter a row number for a live cell: "; cin >> liveR; if (liveR < 1 || liveR > numRows) { cout << "Please enter a row from 1 to " << numRows << "." << endl; } } while (liveR < 1 || liveR > numRows); do { cout << "Enter a column number for the cell: "; cin >> liveC; if (liveC < 1 || liveC > numCols) { cout << "Please enter a column from 1 to " << numCols << "." << endl; } } while (liveC < 1 || liveC > numCols); board[liveR][liveC] = '*'; do { cout << "Do you want to enter another live cell? (y/n) "; cin >> another; if (another != 'y' && another != 'Y' && another != 'n' && another != 'N') { cout << "Please enter either a y or an n." << endl; } } while (another != 'y' && another != 'Y' && another != 'n' && another != 'N'); } while (another == 'y' || another == 'Y'); cout << endl; } //End createBoard() /******************************************************************************* * loadFile function: * * PURPOSE: Create a new board by way of loading a specified file * * IN: 2-D array to hold new board, 2 int containers to hold row size & col size* * OUT: Reference Params: 2-D array, 2 ints * * ADTNL NOTE: 2 Examples are provided in .\ConwaysGameGrids\, 5x10Grid.txt & * * cat.txt * *******************************************************************************/ void loadFile(int &numRows, int &numCols, char board[][maxWidth]) { fstream infile; char filePath[101]; int rix, cix; cout << "Please enter the entire file path to the file including its " << "name and extension: "; cin >> filePath; infile.open(filePath, ios::in); infile >> numRows >> numCols; for (rix = 1; rix <= numRows; ++rix) { for (cix = 1; cix <= numCols; ++cix) { infile >> board[rix][cix]; if (board[rix][cix] == '-') { board[rix][cix] = ' '; } } } infile.close(); } //End loadFile() /******************************************************************************* * useBoard function: * * PURPOSE: Create a new board by way of precoded entry * * IN: 2-D array to hold new board, 2 int containers to hold row size & col size* * OUT: Reference Params: 2-D array, 2 ints * *******************************************************************************/ void useBoard(char board[][maxWidth], int &rows, int &columns) { int rix, cix; rows = 15; columns = 20; board[1][1] = '*'; board[1][2] = '*'; board[1][4] = '*'; board[1][10] = '*'; board[1][11] = '*'; board[1][12] = '*'; board[1][13] = '*'; board[1][14] = '*'; board[1][15] = '*'; board[1][18] = '*'; board[1][19] = '*'; board[1][20] = '*'; board[2][1] = '*'; board[2][4] = '*'; board[2][19] = '*'; board[3][4] = '*'; board[3][12] = '*'; board[3][13] = '*'; board[3][14] = '*'; board[3][15] = '*'; board[3][20] = '*'; board[4][20] = '*'; board[5][20] = '*'; board[6][4] = '*'; board[6][12] = '*'; board[6][13] = '*'; board[6][14] = '*'; board[6][15] = '*'; board[7][13] = '*'; board[7][14] = '*'; board[7][20] = '*'; board[9][1] = '*'; board[9][2] = '*'; board[9][3] = '*'; board[9][4] = '*'; board[10][1] = '*'; board[10][4] = '*'; board[11][1] = '*'; board[11][2] = '*'; board[11][3] = '*'; board[11][4] = '*'; board[11][7] = '*'; board[11][8] = '*'; board[11][9] = '*'; board[11][10] = '*'; board[12][7] = '*'; board[12][8] = '*'; board[12][9] = '*'; board[12][10] = '*'; board[13][7] = '*'; board[13][8] = '*'; board[13][9] = '*'; board[13][10] = '*'; board[12][15] = '*'; board[13][15] = '*'; board[12][16] = '*'; board[13][16] = '*'; board[12][19] = '*'; board[13][19] = '*'; board[12][20] = '*'; board[13][20] = '*'; board[10][17] = '*'; board[10][18] = '*'; board[11][17] = '*'; board[11][18] = '*'; board[14][17] = '*'; board[14][18] = '*'; board[15][17] = '*'; board[15][18] = '*'; board[14][1] = '*'; board[14][2] = '*'; board[15][2] = '*'; for (rix = 1; rix < rows + 1; ++rix) { for (cix = 1; cix < columns + 1; ++cix) { if (board[rix][cix] != '*') { board[rix][cix] = ' '; } } } } //End useBoard() /******************************************************************************* * border function: * * PURPOSE: Inserts a border around game board * * IN: 2-D array of game board, 2 ints: row size & col size * * OUT: Reference Param: 2-D array * *******************************************************************************/ void border(char board[][maxWidth], int rows, int columns) { int ix; const int borderTop = 0; const int borderLeft = 0; const int borderRight = columns + 1; const int borderBottom = rows + 1; for (ix = 0; ix < borderRight; ++ix) { board[borderTop][ix] = '|'; board[borderBottom][ix] = '|'; } for (ix = 0; ix < borderBottom + 1; ++ix) { board[ix][borderRight] = '|'; board[ix][borderLeft] = '|'; } } //End border() /******************************************************************************* * menu function: * * PURPOSE: Display user options and obtain user's choice * * IN: none * * OUT: Returns: int of user's chosen menu option * *******************************************************************************/ int menu(void) { int choice; do { cout << "Please select an option:" << endl; cout << "[1] Play Conway's Game of Life" << endl; cout << "[2] Restart the Game" << endl; cout << "[3] Display the Current Board" << endl; cout << "[4] Enter a New Board" << endl; cout << "[5] Animate Conway's Game of Life" << endl; cout << "[6] Stop the Program" << endl; cin >> choice; if (choice < 1 || choice > 6) { cout << "Please enter an option from 1 to 6." << endl; } } while (choice < 1 || choice > 6); return choice; } //End menu() /******************************************************************************* * displayBoard function: * * PURPOSE: Print board to screen in user friendly format * * IN: 2-D array of game board, 2 ints: row size & col size * * OUT: none * *******************************************************************************/ void displayBoard(char board[][maxWidth], int numRows, int numCols) { int row, column; for (row = 0; row < numRows + 2; ++row) { for (column = 0; column < numCols + 2; ++column) { cout << board[row][column]; } cout << endl; } cout << endl; } //End displayBoard() /******************************************************************************* * liveCount function: * * PURPOSE: Count number of cells that are alive & display total as well as % * * IN: 2-D array of game board, 2 ints: row size & col size * * OUT: none * *******************************************************************************/ void liveCount(char board[][maxWidth], int numRows, int numCols) { int rix, cix, totalSquares, numLive = 0; double percentLive; for (rix = 1; rix <= numRows; ++rix) { for (cix = 1; cix <= numCols; ++cix) { if (board[rix][cix] == '*') ++numLive; } } totalSquares = numRows * numCols; percentLive = numLive / (double)totalSquares; cout << "Rows: " << numRows << ",\tColumns: " << numCols << ",\tLive: " << numLive << ",\tPercent: " << percentLive << endl; } //End liveCount() /******************************************************************************* * holdScreen function: * * PURPOSE: Holds the screen from scrolling so user can see board * * IN: none * * OUT: none * *******************************************************************************/ void holdScreen(void) { char pause; cout << "Enter any letter then press enter to continue: "; cin >> pause; cout << endl; } //End holdScreen() /******************************************************************************* * getTurns function: * * PURPOSE: Obtain number of iterations user wants to go through * * IN: none * * OUT: Returns: int of number of iterations user chose * * ADTNL NOTE: Prompts user to confirm if 50 or more iterations chosen * *******************************************************************************/ int getTurns(void) { int numTurns; char confirm; do { cout << "How many turns do you want to play for? "; cin >> numTurns; if (numTurns <= 0) { cout << "Please enter a positive value." << endl; } else if (numTurns >= 50) { do { cout << "Are you sure? (y/n) It may take awhile to go through " << numTurns << " turns. "; cin >> confirm; if (confirm != 'y' && confirm != 'Y' && confirm != 'n' && confirm != 'N') { cout << "Please enter a y or n." << endl; } } while (confirm != 'y' && confirm != 'Y' && confirm != 'n' && confirm != 'N'); } } while (numTurns <= 0); return numTurns; } //End getTurns() /******************************************************************************* * playGame function: * * PURPOSE: Run through specified number of iterations, holding screen for each * * display * * IN: 2-D array of game board, 3 ints: row size, col size, & num iterations * * OUT: none * *******************************************************************************/ void playGame(char board[][maxWidth], int numRows, int numCols, int numTurns) { int ix; for (ix = 0; ix < numTurns; ++ix) { displayBoard(board, numRows, numCols); liveCount(board, numRows, numCols); holdScreen(); nextGeneration(board, numRows, numCols); } } //End playGame() /******************************************************************************* * nextGeneration function: * * PURPOSE: Determines which cells live, die, & birth, then updates board * * IN: 2-D array of game board, 2 ints row size & col size * * OUT: Reference Param: 2-D array * *******************************************************************************/ void nextGeneration(char board[][maxWidth], int numRows, int numCols) { int rix, cix, adjacent; char newGenBoard[maxHeight][maxWidth]; copyArray(newGenBoard, board, numRows, numCols); for (rix = 1; rix <= numRows; ++rix) { for (cix = 1; cix <= numCols; ++cix) { adjacent = neighbors(board, rix, cix); if (board[rix][cix] == '*') { if (adjacent < 2 || adjacent > 3) newGenBoard[rix][cix] = ' '; } else if (board[rix][cix] == ' ' && adjacent == 3) newGenBoard[rix][cix] = '*'; } } border(newGenBoard, numRows, numCols); copyArray(board, newGenBoard, numRows, numCols); } //End nextGeneration() /******************************************************************************* * restartGame function: * * PURPOSE: Reset to original chosen board * * IN: 2 2-D arrays: game board & original board, 2 ints: row size & col size * * OUT: Reference Param: 2-D array * *******************************************************************************/ void restartGame(char board[][maxWidth], char savedBoard[][maxWidth], int numRows, int numCols) { copyArray(board, savedBoard, numRows, numCols); } //End restartGame() /******************************************************************************* * neighbors function: * * PURPOSE: Count number of living neighbors to a given cell (iteratively) * * IN: 2-D array of game board, 2 ints: row & col of current cell * * OUT: Returns: int of neighbor count * *******************************************************************************/ int neighbors(char board[][maxWidth], int rix, int cix) { int numAdjacent = 0; if (board[rix - 1][cix - 1] == '*') ++numAdjacent; if (board[rix - 1][cix] == '*') ++numAdjacent; if (board[rix - 1][cix + 1] == '*') ++numAdjacent; if (board[rix][cix - 1] == '*') ++numAdjacent; if (board[rix][cix + 1] == '*') ++numAdjacent; if (board[rix + 1][cix - 1] == '*') ++numAdjacent; if (board[rix + 1][cix] == '*') ++numAdjacent; if (board[rix + 1][cix + 1] == '*') ++numAdjacent; return numAdjacent; } //End neighbors() /******************************************************************************* * copyArray function: * * PURPOSE: Make an exact copy of an array * * IN: 2 2-D arrays: source & destination, 2 ints: row size & col size * * OUT: Reference Param: 2-D array * *******************************************************************************/ void copyArray(char destArray[][maxWidth], char sourceArray[][maxWidth], int numRows, int numCols) { int rix, cix; for (rix = 0; rix < numRows + 2; ++rix) { for (cix = 0; cix < numCols + 2; ++cix) { destArray[rix][cix] = sourceArray[rix][cix]; } } } //End copyArray() /******************************************************************************* * animation function: * * PURPOSE: Simulate an animation * * IN: 2-D array of game board, 3 ints: row size, col size, & num iterations * * OUT: none * * ADTNL NOTE: Animation is simulated by doing an additional loop enough times * * to slow down the console window scrolling enough to see each generation* * of board go by without the need to hold screen. The faster the * * processor this is run on, the faster the animation. If animation is * * too fast to see, increase 'timerStart' to a larger value. * *******************************************************************************/ void animation(char board[][maxWidth], int numRows, int numCols, int numTurns) { int ix; double timer; const double timerStart = 50000000; const int timerEnd = 0; for (ix = 0; ix < numTurns; ++ix) { displayBoard(board, numRows, numCols); nextGeneration(board, numRows, numCols); cout << endl << endl << endl; timer = timerStart; do { --timer; } while (timer > timerEnd); } } //End animation() /******************************************************************************* * randomBoard function: * * PURPOSE: Create a new board by way of random num generation * * IN: 2-D array to hold new board, 2 int containers to hold row size & col size* * OUT: Reference Params: 2-D array, 2 ints * * ADTNL NOTE: Row size & col size are chosen randomly, then each cell has 50% * * chance of being alive/empty * *******************************************************************************/ void randomBoard(char board[][maxWidth], int &rows, int &columns) { int rix, cix, deadAlive; const int minHW = 5; rows = rand() % (maxHeight - minHW - 5) + minHW; columns = rand() % (maxWidth - minHW - 5) + minHW; for (rix = 1; rix <= rows; ++rix) { for (cix = 1; cix <= columns; ++cix) { deadAlive = rand() % 2; if (deadAlive == 0) board[rix][cix] = ' '; else if (deadAlive == 1) board[rix][cix] = '*'; } } } //End randomBoard()