In: Computer Science
Skills needed to complete this assignment: functions, dynamic arrays.
The mathematician John Horton Conway invented the "Game of Life". Though not a "game" in any traditional sense, it provides interesting behavior that is specified with only a few rules. This project asks you to write a program that allows you to specify an initial configuration. The program follows the rules of LIFE to show the continuing behavior of the configuration.
LIFE is an organism that lives in a discrete, two-dimensional world. This world is an array with each cell capable of holding one LIFE cell. Generations mark the passing of time. Each generation brings births and deaths to the LIFE community. The births and deaths follow the following set of rules.
1. We define each cell to have eight neighbor cells. The neighbors of a cell are the cells directly above, to the right, to the left, diagonally above to the right and left, and diagonally below to the right and left. Be careful when checking for neighbors on the edges.
2. If an occupied cell has zero or one neighbors, it dies of loneliness. If an occupied cell has more than three neighbors, it dies of overcrowding.
3. If an empty cell has exactly three occupied neighbor cells, there is a birth of a new cell to replace the empty cell.
4. Births and deaths are instantaneous and occur at the changes of generations. A cell dying for whatever reason may help cause birth, but a newborn cell cannot resurrect a cell that is dying, nor will a cell's death prevent the death of another, say, by reducing the local population.
Your job is to complete a program that stimulates this world. The program will first ask the user for the world's dimensions (rows and columns), the number of initial alive cells, and the initial alive cells' coordinates. After that, the program will display the initial world with space for dead cells, and asterisks for alive cells. The user can type in 'G' for the next generation, or type 'Q' to quit.
These function prototypes are provided in the template:
1. void initialization(bool **world, int nrows, int ncols)
This function takes a 2 dimensional Boolean array we call world, and the size of this array in rows and columns. It prompts the user input for the number of initial alive cells and their coordinates, and sets the initial world according to the inputs.
2. void generation(bool **world, bool **copy, int nrows, int ncols)
This function takes the world array, a copy of the world array (it can be used to help count neighbors while cells are turned on or off in the original vector), and the size of the world. The function scans the array and modifies the cells, marks the cells with births and deaths in accord with the rules listed earlier. This involves examining each cell in turn, either killing the cell, letting it live, or, if the cell is empty, deciding whether a cell should be born.
3. void display(bool **world, int nrows, int ncols)
This function acceps the array world and displays the array on the screen. For better visualization, we also display a border of the world.
You are free to add more functions to this program, BUT you must use these provided as well.
DO NOT:
1. modify the main function except at the places commented with /* your code here */ (for allocating/deallocating dynamic memory)
2. modify the prototypes of the above three functions
3. use C/C++ libraries other than iostream and cstdlib
TEMPLATE; (CODE MUST BE WRITTEN FROM THIS)
#include <iostream>
#include <cstdlib>
using namespace std;
const char ALIVE = '*';
const char DEAD = ' ';
void initialization(bool **world, int nrows, int ncols); //prompts and reads the alive cells to initialize the world
void generation(bool **world, bool **copy, int nrows, int ncols); //input parameters: original world, an array to make a copy, dimensions of the array and then updates the world
void display(bool **world, int nrows, int ncols); //prints the world to the console
//you are free to define more functions
int main() {
//Variable declaration. You can add more if necessary.
bool **world, **copy;
int nrows, ncols;
char next;
cout << "Enter world dimensions (rows and columns): ";
cin >> nrows >> ncols;
//allocate memory for dynamic 2d arrays 'world' and 'copy'
/* your code here */
//initialize the world and display
initialization(world, nrows, ncols);
display(world, nrows, ncols);
//prompt user input, Generation/Quit
while(true) {
cout << "next Generation or Quit (g/q) ";
cin >> next;
if(next == 'g' || next == 'G' || next == 'q' || next == 'Q')
break;
}
while (next == 'g' || next == 'G') {
//update the world and display
generation(world, copy, nrows, ncols);
display(world, nrows, ncols);
//prompt user input
while(true) {
cout << "next Generation or Quit (g/q): ";
cin >> next;
if(next=='g' || next=='G' || next=='q' || next=='Q') break;
}
}
//deallocate memory for dynamic 2d arrays 'world' and 'copy'
/* your code here */
return 0;
}
void generation(bool **world, bool **copy, int nrows, int ncols)
{
/* your code here */
}
void initialization(bool **world, int nrows, int ncols)
{
/* your code here */
}
void display(bool **world, int nrows, int ncols)
{
/* your code here */
}
//More function definitions
/* your code here */
// C++ program to to simulate the Game of life program for the given initial configuration of the world
#include <iostream>
#include <cstdlib>
using namespace std;
const char ALIVE = '*';
const char DEAD = ' ';
// function declaration
void initialization(bool **world, int nrows, int ncols); //prompts and reads the alive cells to initialize the world
void generation(bool **world, bool **copy, int nrows, int ncols); //input parameters: original world, an array to make a copy, dimensions of the array and then updates the world
void display(bool **world, int nrows, int ncols); //prints the world to the console
int evolve(bool **world ,int nrows, int ncols, int row, int col); //returns the number of alive neighbors for the given cell
int main() {
//Variable declaration. You can add more if necessary.
bool **world, **copy;
int nrows, ncols;
char next;
cout << "Enter world dimensions (rows and columns): ";
cin >> nrows >> ncols;
//allocate memory for dynamic 2d arrays 'world' and 'copy'
world = new bool*[nrows];
copy = new bool*[nrows];
for(int i=0;i<nrows;i++)
{
world[i] = new bool[ncols];
copy[i] = new bool[ncols];
}
//initialize the world and display
initialization(world, nrows, ncols);
display(world, nrows, ncols);
//prompt user input, Generation/Quit
while(true) {
cout << "next Generation or Quit (g/q) ";
cin >> next;
if(next == 'g' || next == 'G' || next == 'q' || next == 'Q')
break;
}
while (next == 'g' || next == 'G') {
//update the world and display
generation(world, copy, nrows, ncols);
display(world, nrows, ncols);
//prompt user input
while(true) {
cout << "next Generation or Quit (g/q): ";
cin >> next;
if(next=='g' || next=='G' || next=='q' || next=='Q') break;
}
}
//deallocate memory for dynamic 2d arrays 'world' and 'copy'
for(int i=0;i<nrows;i++) // Correction : instead of ncols this will be nrows
{
delete world[i];
delete copy[i];
}
delete world;
delete copy;
return 0;
}
// function to generate the next generation of the world based on the current world
void generation(bool **world, bool **copy, int nrows, int ncols)
{
// loop to copy the world
for(int i=0;i<nrows;i++)
{
for(int j=0;j<ncols;j++)
copy[i][j] = world[i][j];
}
int alive_neighbors;
// loop to get the alive neighbors for each cell and evolve them based on the rules
for(int i=0;i<nrows;i++)
{
for(int j=0;j<ncols;j++)
{
alive_neighbors = evolve(copy,nrows,ncols,i,j);
if(world[i][j]) // if cell is alive
{
if(alive_neighbors < 2 || alive_neighbors > 3)
world[i][j] = false;
}else // if cell is dead
{
if(alive_neighbors == 3)
world[i][j] = true;
}
}
}
}
// function to initialize the board
void initialization(bool **world, int nrows, int ncols)
{
int n_live_cells, row,col;
// loop to set all the cells dead
for(int i=0;i<nrows;i++)
{
for(int j=0;j<ncols;j++)
world[i][j] = false;
}
// input of number of alive cells
cout<<"Enter the number of initial alive cells : ";
cin>>n_live_cells;
cout<<"Enter the coordinates of the alive cells : "<<endl;
// loop to get the coordinates of the alive cells
for(int i=0;i<n_live_cells;)
{
cout<<"Enter row(0-"<<(nrows-1)<<") and column(0-"<<(ncols-1)<<") for the cell (separated by a space) : ";
cin>>row>>col;
// validate that the cell is valid and is not alive already
if( (row>=0) && (row < nrows) && (col >= 0) && (col < ncols) && (!world[row][col]))
{
world[row][col] = true;
i++;
}else
cout<<"Invalid row/column value or cell already occupied"<<endl;
}
}
// function to display the board
void display(bool **world, int nrows, int ncols)
{
for(int i=0;i<nrows;i++)
{
cout<<endl<<" | ";
for(int j=0;j<ncols;j++)
{
if(world[i][j])
cout<<ALIVE<<" | ";
else
cout<<DEAD<<" | ";
}
cout<<endl<<string(ncols*5,'-');
}
cout<<endl;
}
// function to count the number of alive neighbors for given cell (row,col)
// the cells at the edges have only 3 neighbors
int evolve(bool **world ,int nrows,int ncols, int row, int col)
{
int alive_neighbours = 0;
if(((row-1)>=0) && ((col-1)>=0) && world[row-1][col-1])
alive_neighbours++;
if(((row-1)>= 0) && world[row-1][col])
alive_neighbours++;
if(((row-1)>=0) && ((col+1)<ncols) && world[row-1][col+1])
alive_neighbours++;
if(((col-1)>=0) && world[row][col-1])
alive_neighbours++;
if(((col+1)<ncols) && world[row][col+1])
alive_neighbours++;
if(((row+1)<nrows) && ((col-1)>=0) && world[row+1][col-1])
alive_neighbours++;
if(((row+1)<nrows) && world[row+1][col])
alive_neighbours++;
if(((row+1)<nrows) && ((col+1)<ncols) && world[row+1][col+1])
alive_neighbours++;
return alive_neighbours;
}
//end of program
Output: