I'm trying to write the code for the Game of Life program, using arrays and for loops. I based most of my code on what my teacher did in class and modified it to fit the requirements of my assignment. I've hit a wall, though. When I execute the program, I'm able to input what how many cells and what cells I want occupied. The program displays my input correctly for the first Generation, but every Generation after that has all the cells filled with astericks.

#include <iostream>

using namespace std;

#include <memory.h>
#include <stdlib.h>
#include <time.h>

void main ()
	{
	const	long	NumCols	(60);
	const	long	NumRows	(60);
			bool	Board	[NumRows + 2] [NumCols + 2];
			bool	NextBoard	[NumRows + 2] [NumCols + 2];
			long	Col;
			time_t	CurrTime;
			long	Generation;
			long	i;
			long	NumNeighbors;
			long	NumOccupied;
			long	Row;
			time_t	StartTime;
	const	time_t	WaitTime (3);

	memset (Board, false, (NumRows + 2) * (NumCols + 2) * sizeof (bool));

	cout << "How many cells do you want occupied? ";
	cin >> NumOccupied;
	for (i = 0; i < NumOccupied; i++)
		{
		cout << "Which row and column position is to be occupied: (1 to 60) ";
		cin >> Row >> Col;
		 if(Row > NumRows, Col > NumCols)
					{
					cout << "Not a valid position, reenter" << endl;
					i--;
					}
				else
					Board [Row] [Col] = true;
		}

	for (Generation = 0; ; Generation++)
		{
		system ("cls");		// "cls" needs to be changed if you are on UNIX
		cout << "Generation " << Generation << endl;
		for (Row = 1; Row <= NumRows; Row++)
			{
			for (Col = 1; Col <= NumCols; Col++)
				cout << (Board [Row] [Col] ? '*' : ' ');
				if (Board [Row] [Col])
						cout << '*';
					else
						cout << ' ';
			cout << endl;
			}

		for (Row = 1; Row <= NumRows; Row++)
			for (Col = 1; Col <= NumCols; Col++)
				{
				// count the number of occupied neighbors
				NumNeighbors = 0;
				if (Board [Row - 1] [Col - 1])
						NumNeighbors++;
					else;
				if (Board [Row - 1] [Col])
						NumNeighbors++;
					else;
				if (Board [Row + 1] [Col - 1])
						NumNeighbors++;
					else;
				if (Board [Row + 1] [Col])
						NumNeighbors++;
					else;
				if (Board [Row + 1] [Col + 1])
						NumNeighbors++;
					else;
				if (Board [Row + 1] [Col])
						NumNeighbors++;
					else;
				if (Board [Row - 1] [Col + 1])
						NumNeighbors++;
					else;
					
				// do the same for the other cells around this one
				// now apply the rules
				if (NumNeighbors >= 4)
						NextBoard [Row] [Col] = ' ';
				if (NumNeighbors <= 1)
						NextBoard [Row] [Col] = ' ';
				if (NumNeighbors = 3)
						NextBoard [Row] [Col] = '*';
				else;
				}
		
		memcpy (Board, NextBoard,  (NumRows + 2) * (NumCols + 2) * sizeof (bool));

		StartTime = time (0);	// gets current time in seconds since Jan 1, 1970
		do	{
			CurrTime = time (0);
			} while ((CurrTime - StartTime) < WaitTime);
		}
	}

Any help would would be appreciated.

Dani AI

Generated

Brief expert summary: several small, independent problems combine to produce the symptoms you describe. was right to flag the type/char vs bool mismatch; was right about the missing neighbor checks. The most important concrete causes to fix (in order) are: accidental assignments in conditions, wrong use of comma/bitwise operators, not setting every cell of NextBoard each generation, and missing braces around the inner print loop.

Concrete fixes and why they matter

  • Input validation: the comma operator evaluates only the last expression. Use a logical OR and check both upper and lower bounds.
  • Printing: the inner for needs braces. Right now a stray if after the loop uses Col after it has incremented past the last printed column and (worse) assigns to the board. That single assignment will set a trailing column true on every row.
  • Neighbor counting: do not chain eight neighbors with &. That yields true only if all eight are true. Check each neighbor separately and increment NumNeighbors for each true neighbor.
  • Update rules and initialization: use comparison, not assignment, when testing NumNeighbors. Also set NextBoard[row][col] for every case—if you leave some entries untouched they contain garbage and memcpy will copy that into Board.

Minimal code patterns to apply

/* clear next-board at the start of each generation */
memset(NextBoard, 0, sizeof NextBoard);  // or std::fill

/* correct update rule for each cell */
if (neighbors == 3)
    next[r][c] = true;
else if (neighbors == 2)
    next[r][c] = board[r][c];  // survive only if already alive
else
    next[r][c] = false;

Quick debugging tips

  • Compile with warnings enabled (g++ -Wall -Wextra) and fix everything the compiler flags.
  • Use a tiny board (e.g. 8x8) and print neighbor counts while debugging.
  • Instrument the code to print the index values when you see unexpected writes; that will quickly reveal assignments that happen after a loop ends.

Fixing the four items above will eliminate the “all filled” and column-fill symptoms and get the standard Game of Life rules working.

Recommended Answers

All 3 Replies

Lines 50 vs 87-92. Make up your mind on bool vs char contents of Board[][].

You aren't testing Board[Row][Col-1] nor Board[Row][Col+1] .
Wouldn't two nested loops be better than all those IF statements?.

So I added Board[Row][Col-1] and Board[Row][Col+1] to my list of rules, and also condensed them all into one IF statement. I also modified the IF statements below that. I have a different problem now: whenever I execute the program all the cells in column 60 are filled. I'm incredibly new to programming, so the issue completely eludes me.

#include <iostream>

using namespace std;

#include <memory.h>
#include <stdlib.h>
#include <time.h>

void main ()
	{
	const	long	NumCols	(60);
	const	long	NumRows	(60);
			bool	Board	[NumRows + 2] [NumCols + 2];
			bool	NextBoard	[NumRows + 2] [NumCols + 2];
			long	Col;
			time_t	CurrTime;
			long	Generation;
			long	i;
			long	NumNeighbors;
			long	NumOccupied;
			long	Row;
			time_t	StartTime;
	const	time_t	WaitTime (3);

	memset (Board, false, (NumRows + 2) * (NumCols + 2) * sizeof (bool));

	cout << "How many cells do you want occupied? ";
	cin >> NumOccupied;
	for (i = 0; i < NumOccupied; i++)
		{
		cout << "Which row and column position is to be occupied: (1 to 60) ";
		cin >> Row >> Col;
		 if(Row > NumRows, Col > NumCols)
					{
					cout << "Not a valid position, reenter" << endl;
					i--;
					}
				else
					Board [Row] [Col] = true;
		}

	for (Generation = 0; ; Generation++)
		{
		system ("cls");		// "cls" needs to be changed if you are on UNIX
		cout << "Generation " << Generation << endl;
		for (Row = 1; Row <= NumRows; Row++)
			{
			for (Col = 1; Col <= NumCols; Col++)
				cout << (Board [Row] [Col] ? '*' : ' ');
				if (Board [Row] [Col] = true)
						cout << '*';
					else
						cout << ' ';
			cout << endl;
			}

		for (Row = 1; Row <= NumRows; Row++)
			for (Col = 1; Col <= NumCols; Col++)
				{
				// count the number of occupied neighbors
				NumNeighbors = 0;
				if (Board [Row] [Col - 1] & Board [Row] [Col + 1] & Board [Row - 1] [Col - 1]
				& Board [Row - 1] [Col] & Board [Row + 1] [Col - 1] & Board [Row + 1] [Col]
				& Board [Row + 1] [Col + 1] & Board [Row - 1] [Col + 1])
						NumNeighbors++;
					else;
					
				// do the same for the other cells around this one
				// now apply the rules
				if (NumNeighbors >= 4)
						NextBoard [Row] [Col] = false;
				if (NumNeighbors <= 1)
						NextBoard [Row] [Col] = false;
				if (NumNeighbors == 3)
						NextBoard [Row] [Col] = true;
				else;
				}
		
		memcpy (Board, NextBoard,  (NumRows + 2) * (NumCols + 2) * sizeof (bool));

		StartTime = time (0);	// gets current time in seconds since Jan 1, 1970
		do	{
			CurrTime = time (0);
			} while ((CurrTime - StartTime) < WaitTime);
		}
	}
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.