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()