Hi:

I wasn't able to find the exact solution to my problem on Daniweb, although there are several posts regarding the game of life. This situation came the closest: http://www.daniweb.com/software-development/cpp/threads/242338
My situation is a bit different because I HAVE to use a combination of functions and a class in the client program; it's 3 files total: client, specification(header), and the file that holds all the defitions for the secification file. So I'm not sure what I'm doing wrong to end up with blank cells. I think that the problem is with my tally function in the client file/program.

I will first post my assignment, then my specification file, then my class member definitions, and lastly my client file. The .txt file, that the client uses, is attached. My erroneous output is at the very bottom. The expected output is at this link: http://www.santarosa.edu/~dharden/1011/proj5fullout.shtml

...thanks in advance for any help.

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 . . .

Run time errors are always the hardest to find. Learning how to view variable values as the program is running is one of the most useful techniques I can think of to be successful in this task. As I look at your code and the output you have presented it looks to me like the value of liveNeighbors is the key. From what I can tell it looks like the value of liveNeighbors will always be less than or equal to zero. Which means that there won't be a next generation since the fate functions always set the current cell in generations to false if liveNeighbors is less than or equal to zero. Which means, the print out of the second generation will always appear empty.

Why liveNeighbors is always less than or equal to zero I will leave you to figure out. That's half the fun!

HINT: focus on tallyLiveNeighbors() and checkOutOfBounds()

Run time errors are always the hardest to find. Learning how to view variable values as the program is running is one of the most useful techniques I can think of to be successful in this task. As I look at your code and the output you have presented it looks to me like the value of liveNeighbors is the key. From what I can tell it looks like the value of liveNeighbors will always be less than or equal to zero. Which means that there won't be a next generation since the fate functions always set the current cell in generations to false if liveNeighbors is less than or equal to zero. Which means, the print out of the second generation will always appear empty.

Why liveNeighbors is always less than or equal to zero I will leave you to figure out. That's half the fun!

HINT: focus on tallyLiveNeighbors() and checkOutOfBounds()

Thank you for your reply. I will take a closer look at tallyLiveNeighbors() and checkOutOfBounds().

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.