Problem

Your task is to write a program that plays the game of life. This game is a computer simulation of the life and death events in a population of single-cell organisms. Each position in a two-dimensional grid (Petri dish) can support one cell. The program determines whether each position will be able to support life in the next generation.

Specifications

The grid of cells is represented by a two-dimensional array. The starting grid is generation 0 and is read from a supplied input file. Most positions in the grid have 8 neighbors like the center square in a tic-tac-toe game. The four corner positions have only 3 neighbors each. The remaining positions around the edge of the grid have 5 neighbors each. The rules for the state of each position in the next generation of the grid are as follows:

If the cell is currently empty:
If the cell has exactly three living neighbors, it will come to life in the next generation.
If the cell has any other number of living neighbors, it will remain empty.
If the cell is currently living:
If the cell has one or zero living neighbors, it will die of loneliness in the next generation.
If the cell has four or more living neighbors, it will die of overcrowding in the next generation.
If the cell has two or three neighbors, it will remain living.
All births and deaths occur simultaneously. This point is critical to the correct result.
The following three webpages are also available: the data file, the correct output, and the output including intermediate generations. The last webpage is available to help you debug your code.

The data file supplies the data for generation 0. Each line of data gives a pair of coordinates (row# column#) for a living cell in the original grid. Assume that every number in the text file is between 0 and 19. All other grid positions are empty.

After your program has created the two-dimensional array that represents generation 0, your program must allow life to proceed for the number of generations specified by the user. Start with five generations. Your program should then display a grid on the screen to show the final results. Use a star (*) to represent a live cell and a space to represent a dead cell. After the grid, display the following statistical information:

The number of living cells in the entire board.
The number of living cells in row 10.
The number of living cells in column 10.
Please make sure that your output matches the correct output exactly.

Create a class named boolMatrix for storing and processing a two-dimensional array of bool values. The class should be saved in a specification file and an implementation file. Your client program must use this class rather than declaring its own arrays. You must not use any arrays in your client program.

The size of each dimension of the matrix must be specified near the top of the specification file by two global named constants. You must use a 20 by 20 array to start. These named constants will also be used to limit the loops that process the array in both the member functions and the client code. When processing the array, do not access any memory outside of the array bounds.

Keep in mind as you write the class that it is to be completely unrelated to the game of Life. The class should not mention anything about life, cells, neighbors, etc. The class will have exactly one private data member that is an array of bool. The class will have seven member functions:

default constructor: initialize all of the array elements to false
get: return the current contents of a single array element. Use arguments to indicate the row and column of the array element that should be returned.
set: set the contents of a single array element. Use arguments to indicate the row and column of the array element that should be set, and the value to which it should be set.
rowcount: return the number of true values that exist in any given row
colcount: return the number of true values that exist in any given column
totalcount: return the number of true values that exist in the entire array
print: display the contents of the array, including the row and column indices (see the posted correct output). For each element of the array, a true value must be displayed as an asterisk ("*") and a false value must be displayed as a space. This member function is the only one that displays output.
Use const to indicate const functions and unchangeable reference parameters whenever possible.

In the client code, a minimum of three functions is required in addition to the main function. Remember our discussions about functional cohesion, value-returning vs. void functions, and value parameters vs. reference parameters.

The only documentation required is the initial file documentation for each of the three files. Note that this means you must provide pre/post conditions in your header file.

Hints

Use iterative development.

Keep straight that the array is a data member within the class object and must be accessed accordingly.

I think the most difficult part is counting the neighbors. Try to keep this code as simple as possible.

Turn in

The program code from each of the three files.
Output showing generation 5 for a 20 by 20 grid.
Output showing generation 8 for a grid of 21 rows and 22 columns. The change in the grid size should be accomplished by changing only the two named constants in the specification file.

//////////////////////Header//////////////////////
#include <iostream>
#ifndef BOOLMATRIX_H
#define BOOLMATRIX_H
const int NUM_ROWS = 20;
const int NUM_COLS = 20;

class boolMatrix
{
    public: // Available for clients use.
            boolMatrix();
            bool get(int row, int col) const;
            void set(int row, int col, bool value);
            int rowCount(int row) const;
            int colCount(int col) const;
            int totalCount() const;
            void print()const;

    private: // Can only be used within the class, Client cannot call it.
            bool matrix[NUM_ROWS][NUM_COLS];
};
#endif // BOOLMATRIX_H



/////////Class Member Functions////////////
#include <iostream>
#include <iomanip>
#include "boolmatrix.h" // class's header file
using namespace std;
// class constructor
boolMatrix::boolMatrix()
{
    for (int row = 0; row < NUM_ROWS; row++){
        for (int col = 0; col < NUM_COLS; col++){    
             matrix[row][col] = false;
         }
    }

}
bool boolMatrix::get(int row, int col) const
{
    return matrix[row][col];
}
void boolMatrix::set(int row, int col, bool value)
{
     matrix[row][col] = value;
}
int boolMatrix::rowCount(int row) const
{
    int rowtotal = 0;

    for (int col = 0; col < NUM_COLS; col++){
        if ( matrix[row][col] == true ){
           rowtotal++;
        }
    }
    return rowtotal;           
}
int boolMatrix::colCount(int col) const
{
    int colTotal = 0;

    for (int row = 0; row < NUM_ROWS; row++){
        if ( matrix[row][col] == true ){
           colTotal++;
        }
    }
    return colTotal;                    
}
int boolMatrix::totalCount() const
{
     int total = 0;
     for (int row = 0; row < NUM_ROWS; row++){
         for (int col = 0; col < NUM_COLS; col++){ 
             if ( matrix[row][col] == true ){
                total++;
             }
         }     
     }
     return total;

}
void boolMatrix::print() const
{
    cout << "  ";

    for (int col = 0; col < NUM_COLS; col++)
    {
        cout << col % 10;
    }
    cout << endl;

    for (int row = 0; row < NUM_ROWS; row++)
    {
        cout << setw(2) << row % 100;    
        for (int col = 0; col < NUM_COLS; col++){    
            if ( matrix[row][col] == true ){
               cout << "*";
            } else if ( matrix[row][col] == false ){
               cout << " ";
            }
        }
        cout << endl;
    }      
}



///////////////Client File\\\\\\\\\\\\\\\\\\\\\\\\
#include <iostream>
#include <fstream>
#include <cassert>
#include "boolmatrix.h"
using namespace std;
void firstgen(boolMatrix& generation);
void getNextGen(boolMatrix& generation,int liveNeighbors,int row,int col);
void fateDeadCell(boolMatrix& generation,int liveNeighbors,int row,int col);
void fateLiveCell(boolMatrix& generation,int liveNeighbors,int row,int col);
void checkOutBounds(int row, int col, int& liveNeighbors);
void printResults(boolMatrix& generation);
int tallyLiveNeighbors(const boolMatrix& generation, int& liveNeighbors,int row,int col);
int main()
{
    boolMatrix generation;
    int numGen, liveNeighbors, row, col;
    cout << "How many generations in total?: " << endl;
    cin >> numGen;
    firstgen(generation);
    generation.print();    //prints first generations.
    cout << "Total alive in row 10 = " << generation.rowCount(10) << endl;
    cout << "Total alive in col 10 = " << generation.colCount(10) << endl;  
    cout << "Total alive = " << generation.totalCount() << endl << endl;  

    for(int count = 1; count < numGen; count++)
    {
        getNextGen(generation,liveNeighbors,row,col);
        printResults(generation);    
    }

    system("pause");
    return 0;
}
void firstgen(boolMatrix& generation)    //stores data file info into array.
{
     ifstream infile("lifedata.txt");
     assert(infile);
     int row, col;

     infile >> row >> col;
     while (infile) {
           generation.set(row, col, true);
           infile >> row >> col;
     }
     infile.close();
}
void getNextGen(boolMatrix& generation,int liveNeighbors,int row,int col)    //gets all subsequent generations.
{
    liveNeighbors = 0;
    for(int row = 0; row < NUM_ROWS; row++)
    {
        for(int col = 0; col < NUM_COLS; col++)
        {
            if(generation.get(row,col) == false){
                fateDeadCell(generation,liveNeighbors,row,col);
            }else if(generation.get(row,col) == true){
                fateLiveCell(generation,liveNeighbors,row,col);
            }
        }
    }
}

int tallyLiveNeighbors(boolMatrix& generation,int& liveNeighbors,int row,int col)
{
    if(generation.get(row-1,col-1) == true){
        liveNeighbors++;
        checkOutBounds(row, col, liveNeighbors);
    }else if(generation.get(row-1,col) == true){
        liveNeighbors++;
        checkOutBounds(row, col, liveNeighbors);
    }else if(generation.get(row-1,col+1) == true){
        liveNeighbors++;
        checkOutBounds(row, col, liveNeighbors);
    }else if(generation.get(row,col-1) == true){
        liveNeighbors++;
        checkOutBounds(row, col, liveNeighbors); 
    }else if(generation.get(row,col+1) == true){ 
        liveNeighbors++;
        checkOutBounds(row, col, liveNeighbors);
    }else if(generation.get(row+1,col-1) == true){
        liveNeighbors++;
        checkOutBounds(row, col, liveNeighbors);
    }else if(generation.get(row+1,col)== true){ 
        liveNeighbors++;
        checkOutBounds(row, col, liveNeighbors);
    }else if(generation.get(row+1,col+1) == true){
        liveNeighbors++;
        checkOutBounds(row, col, liveNeighbors);
    }    
}
void fateDeadCell(boolMatrix& generation,int liveNeighbors,int row,int col)
{
    tallyLiveNeighbors(generation,liveNeighbors,row,col);
    if(liveNeighbors == 3){
        generation.set(row,col,true);
    }else if ((liveNeighbors < 3) || (liveNeighbors > 3)){
        generation.set(row,col,false);
    }
}
void fateLiveCell(boolMatrix& generation,int liveNeighbors,int row,int col)
{
    tallyLiveNeighbors(generation,liveNeighbors,row,col);

    if((liveNeighbors <= 1) || (liveNeighbors >= 4)){
        generation.set(row,col,false);
    }else if((liveNeighbors == 2) || (liveNeighbors == 3)){
        generation.set(row,col,true);
    }
}
void checkOutBounds(int row, int col, int& liveNeighbors)
{
    if(((row-1) < 0) || ((row+1) > NUM_ROWS) || ((col-1)< 0) || ((col+1) < NUM_COLS))
    {
        liveNeighbors--;
    }
}
void printResults(boolMatrix& generation)
{
    generation.print();    //prints subsequent generations
    cout << "Total alive in row 10 = " << generation.rowCount(10) << endl;
    cout << "Total alive in col 10 = " << generation.colCount(10) << endl;  
    cout << "Total alive = " << generation.totalCount() << endl << endl;    
}
How many generations in total?:
2
  01234567890123456789
 0*    *   *         *
 1      *       * *
 2    *  *   *  *** *
 3  *  *   **      * *
 4*  * *   *
 5  ** *         ***
 6     **   ** **  **
 7      * *     * *
 8 *   *  * *      *
 9   ** **
10*        *         *
11 *** * **     *  * *
12    *** *
13**     *  **  *****
14  *        * * * * *
15           * *    *
16 **  *  *        *
17     **
18      *         * *
19*  **  *
Total alive in row 10 = 3
Total alive in col 10 = 4
Total alive = 100
  01234567890123456789
 0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
Total alive in row 10 = 0
Total alive in col 10 = 0
Total alive = 0
Press any key to continue . . .

Recommended Answers

All 3 Replies

getting a runtime error points suggest that you are going out of the bounds of the array. What I wold suggest is that in your get and set methods you put in an if statement that checks to see if you are out of bounds and if you are then print a message. Then you should be able to find out where that is coming from.

I couldn't reproduce the error, but I did notice a few things:

  • void getNextGen(boolMatrix& generation, int liveNeighbors, int row, int col) accepts 3 arguments(int liveNeighbors, int row, int col) that are never used but are re-declared inside the function

  • tallyLiveNeighbors doesn't return any values instead it modifies an argument passed by reference. This should be declared as void

  • You might want to consider using an if block to check if infile is good instead of using assert. This way you have a less destructive method of trapping the error and you have more control over the error message istelf.

I think that you should move:boolMatrix& generation,
int tallyLiveNeighbors(boolMatrix& generation,int& liveNeighbors,int row,int col)
because in the error it says that the function take only 3 arguments and you you put it 4 or you will move 1 parametere and redeclare it in the body of the function tallyLiveNeighbors.
Try this and request me

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.