NEED HELP WITH THIS PROJECT!!!!!! Objective: Learn how to use pointers and be ab
ID: 3671655 • Letter: N
Question
NEED HELP WITH THIS PROJECT!!!!!!
Objective:
Learn how to use pointers and be able to compile and run programs in Linux.
Specifications:
For this assignment you will be implementing the classic cellular automata of Conway's Game of Life.
Rules
A new cell is born on an empty square if is surrounded by exactly three neighboring cells
A cell dies of overcrowding if it has four or more neighbors
A cell dies of loneliness if it has zero or one neighbor
Any live cell with two or three live neighbors lives, unchanged, to the next generation.
Implementation details:
The initial state of the game is held in a text file named the driver code and attached to this assignment (you must use this driver program). The format will be sequences of ones and zeros. A one means a live cell and zero a dead cell. You can determine the width of the grid by reading first line character by character until the end of the line terminator is encountered. You can determine the height of the grid by counting the lines of data.
Example:
00000000100000001010
00000000010000001001
11100000010100000010
10100100101010101010
00101010010010101000
The grader will use a file with arbitrary grade size (there is no limitation in terms of how large the grid would be) to grade the project. You algorithm should be able to handle this.
Example: Jeremy Allen's Glider Gun fight grid (set the iterations to 500).
Note: When printing out the status of the grid, print one character per cell in the grid to console. Use 0 to represent dead cell and one to represent live cell. The driver program will clear the screen between generations.
In this project you will have three files: 1) "life.h" stores the prototypes for all functions that are employed in the implementation of Game of Life 2) "life.cpp" stores the definitions of the functions that declared in "life.h" 3) "life_driver.cpp" – the driver file that tests the functionality of your game of life.
Conway's Game of Life c++ program
Explanation / Answer
life.cpp
#include <iostream>
#include <fstream>
#include <cctype>
#include "life.h"
using namespace std;
//GLOBAL VARIABLES
int ROWS; //stores the number of rows in the grid
int COLUMNS; //stores the number of columns in the grid
//These are pointer variables that point to char pointers, this is how the
//dynamic 2-d array is made, it is essentially an array of pointers.
char **grid, **tempgrid;
//Another pointer variable but this one points to pointers that point to
//integers. Global variables first_row, last_row, first_column, and
//last_column are declared here
int **ngrid,
first_row = 0,
last_row = 0,
first_column = 0,
last_column = 0;
/****************************************************************************
* populateWorld():
* This function creates a const char pointer called file that points to
* FILE_NAME in life_driver.cpp. A 1-d dynamic array is created to store the
* first row of the input file while counting how many entries there are at
* the same time. A 2-d dynamic array is then created and begins allocating
* and deallocating memory using a **tempgrid and **grid until the end of
* file is reached. The data read is the initial population of cells.
*/
void populateWorld (const char * file)
{
//The dynamic array starts with a size of 1
int start_size = 1, count = 0;
//ROWS and COLUMNS are initialized to 0
ROWS = 0;
COLUMNS = 0;
//These are pointers used to create a 1d dynamic array
char *col_count, *temp;
//Open input file
fstream fin(file, ios::in);
//Allocate memory of size "start_size"
col_count = new char [start_size];
//This while loop will continue loop until the function peek()
//detects something thats next in line to be read that is not
//a number or alphabetical letter, in this case the end of line
//character
while(isalnum(fin.peek()))
{
//Reads in data and then increments count
fin >> col_count[count];
++count;
//Allocate memory that is size count + 1
temp = new char [count + 1];
//Assign what has already been read into newly allocated
//memory
for( int i = 0; i < count; ++i )
{
temp[i] = col_count[i];
}
//Deallocate memory that is of lesser size
delete [] col_count;
//Assign pointer to newly allocated memory
col_count = temp;
}
COLUMNS = count;
//A pointer array of size "start_size" is create
grid = new char *[start_size];
//A pointer is assigned in each element of the pointer array
//now a 2-d dynamic array is created. This is accomplished
//by making an array of pointers that each point to an array.
for( int i = 0; i < start_size; ++i )
{
grid[i] = new char[COLUMNS];
}
//Since the first line of the file has already been read it is
//stored into the first row of the 2-d array
for( int i = 0; i < start_size; ++i)
{
for( int j = 0; j < COLUMNS; ++j)
{
grid[i][j] = col_count[j];
}
}
//This while loop will continue looping until the end of the file
//is reached. Each loop will increment ROWS and add 1 row to the
//2-d array by allocating memory that can hold the new size,
//deallocating the lesser sized memory, and assigning the grid
//pointer to the newly allocated memory.
while(!fin.eof())
{
if( fin.eof() )
{
break;
}
++ROWS;
tempgrid = new char *[ROWS+1];
for( int i = 0; i < (ROWS + 1); ++i )
{
tempgrid[i] = new char[COLUMNS];
}
for( int i = 0; i < ROWS; ++i )
{
for( int j = 0; j < COLUMNS; ++j )
{
tempgrid[i][j] = grid[i][j];
}
}
for( int i = ROWS; i < (ROWS + 1); ++i )
{
for( int j = 0; j < COLUMNS; ++j )
{
fin >> tempgrid[i][j];
}
}
for( int i = 0; i < ROWS; ++i )
{
delete [] grid[i];
}
delete [] grid;
grid = tempgrid;
}
//close input file after reading has ended
fin.close();
}
//This function calls the function changeGrid() to make sure grid
//is correct size before outputting the grid for current generation
void showWorld ()
{
changeGrid();
for( int i = 0; i < ROWS; ++i )
{
for( int j = 0; j < COLUMNS; ++j )
{
cout << grid[i][j];
}
cout << endl;
}
cout << endl;
}
//This function creates new generation grid from the old generation grid
//before changing grid it calls functions getNeighborCount() and changeGrid()
void iterateGeneration ()
{
getNeighborCount();
changeGrid();
//Once the neighbor count grid is created (ngrid) it changes each cell
//in the grid by comparing each cell with its neighbor count in conditional
//statements that implement the rules of the game
for( int i = 0; i < ROWS; ++i)
{
for( int j = 0; j < COLUMNS; ++j )
{
//A cell dies of loneliness if it has zero or one neighbor
if (grid[i][j] == '1' && ngrid[i][j] < 2)
grid[i][j] = '0';
//A cell dies of overcrowding if it has four or more neighbors
else if (grid[i][j] == '1' && ngrid[i][j] > 3)
grid[i][j] = '0';
//Any live cell with two or three live neighbors lives, unchanged, to the next generation.
else if (grid[i][j] == '1' && (ngrid[i][j] == 2 || ngrid[i][j] == 3))
grid[i][j] = '1';
//A new cell is born on an empty square if is surrounded by exactly three neighboring cells
else if (grid[i][j] == '0' && ngrid[i][j] == 3)
grid[i][j] = '1';
}
}
//delete memory allocated for ngrid as it is no longer needed
for( int i = 0; i < ROWS; ++i )
{
delete [] ngrid[i];
}
delete [] ngrid;
}
/****************************************************************************
* changeGrid():
* This function calls findParameters() to get data from the grid that is used
* change the grid to the correct size. findParameters() will assign values to
* the global variables first_row, last_row, first_column, and last_column. Since
* there should only be one surrounding boundry of dead cells this function
* calculates the size that the grid should be with two algorithms. Once the size
* is determined, memory of that size is allocated and the part of the original
* grid that is in size of the newly allocated memory is stored and then the old
* allocated memory is deleted.
*/
void changeGrid()
{
int temp_row = 0,
temp_column = 0;
//Finds first_row, last_row, first_column, and last_column
findParameters();
//stores the desired row size of the grid into variable temp_row
//using the algorithm (last_row - first_row + 1);
temp_row = (last_row - first_row + 1);
//stores the desired column size of the grid into variable temp_column
//using the algorithm (last_column - first_column + 1);
temp_column = (last_column - first_column + 1);
//create new 2-d dynamic array of row size "temp_row" and column size
//"temp_column"
tempgrid = new char *[temp_row];
for( int i = 0; i < temp_row; ++i )
{
tempgrid[i] = new char [temp_column];
}
//initialize all elements of 2-d array to 0
for( int i = 0; i < temp_row; ++i )
{
for( int j = 0; j < temp_column; ++j )
{
tempgrid[i][j] = '0';
}
}
//This for loop stores the part of the grid that is not changing into
//the new tempgrid that is appropriate size
for( int i = 0; i < temp_row; ++i )
{
for( int j = 0; j < temp_column; ++j )
{
//first_row and first_columns are used again to store the correct
//elements into the new grid
tempgrid[i][j] = grid[(first_row - 1) + i][(first_column - 1) + j];
}
}
//delete memory allocated for old grid
for( int i = 0; i < ROWS; ++i )
{
delete [] grid[i];
}
delete [] grid;
//assign grid pointer to newly allocated memory
grid = tempgrid;
//Now that the new grid is created we set gobals ROWS and COLUMNS to the
//size of the new grid
ROWS = temp_row;
COLUMNS = temp_column;
//Since we want a boundary of dead cells around the grid the function addLayer()
//is called to do just that
addLayer();
}
/****************************************************************************
* addLayer():
* This function simply increments both ROWS and COLUMNS by 2, allocates new
* memory of appropriate size, initializes all elements of new 2-d array to 0
* , then stores contents of the grid into the center of the new 2-d array.
* The memory allocated for the old grid is then deleted and the grid pointer
* is assigned to the newly allocated memory. This function ensures that the
* outermost boundry of the grid is a boundary of dead cells.
*/
void addLayer()
{
//increments ROWS and COLUMNS
ROWS += 2;
COLUMNS += 2;
//creates new 2-d array of desired size
tempgrid = new char *[ROWS];
for( int i = 0; i < ROWS; ++i )
{
tempgrid[i] = new char [COLUMNS];
}
//initializes all elements to 0
for( int i = 0; i < ROWS; ++i )
{
for( int j = 0; j < COLUMNS; ++j )
{
tempgrid[i][j] = '0';
}
}
//stores contents of grid into the center of tempgrid
for( int i = 0; i < (ROWS - 2); ++i )
{
for( int j = 0; j < (COLUMNS - 2); ++j )
{
tempgrid[i+1][j+1] = grid[i][j];
}
}
//deletes memory allocated for grid
for( int i = 0; i < (ROWS - 2); ++i )
{
delete [] grid[i];
}
delete [] grid;
//assigned grid to newly allocated memory
grid = tempgrid;
}
/****************************************************************************
* findParameters():
* This function sets global variables first_row, last_row, first_column, and
* last_column to 0. The function then goes through 4 for loops that each
* traverse the grid and assigned appropriate values to the global variables.
*/
void findParameters()
{
first_row = 0;
last_row = 0;
first_column = 0;
last_column = 0;
//checks for a 1 and then assigns the row index found + 1 to first_row and
//then breaks out of the loop
for( int i = 0; i < ROWS; ++i )
{
for( int j = 0; j < COLUMNS; ++j )
{
if( grid[i][j] == '1' )
{
first_row = i + 1;
break;
}
}
if( first_row != 0 )
{
break;
}
}
//checks for a 1 and then assigns the row index found + 1 to last_row but
//will check all rows to make sure that last_row has correct value
for( int i = 0; i < ROWS; ++i )
{
for( int j = 0; j < COLUMNS; ++j )
{
if( grid[i][j] == '1' )
{
last_row = i + 1;
break;
}
}
}
//checks for a 1 and then assigns the column index found + 1 to first_column
//and then breaks out of the loop
for( int j = 0; j < COLUMNS; ++j )
{
for( int i = 0; i < ROWS; ++i )
{
if( grid[i][j] == '1' )
{
first_column = j + 1;
break;
}
}
if( first_column != 0 )
{
break;
}
}
//checks for a 1 and then assigns the column index found + 1 to last_column
//but will check all columns to make sure that last_column has correct value
for( int j = 0; j < COLUMNS; ++j )
{
for( int i = 0; i < ROWS; ++i )
{
if( grid[i][j] == '1' )
{
last_column = j + 1;
break;
}
}
}
}
/****************************************************************************
* findParameters():
* This function creates a new 2-d integer array that is the same size has the array
* containing the grid. addLayer() is then called in order to add a boundary of dead
* cells around the grid so that the program doesn't travel outside the boundaries
* of the array when checking for neighbors.
*/
void getNeighborCount()
{
//declare a neighbor count and set temp_rows = ROWS and temp_col = COLUMNS
//so that the original size is not lost after addLayer() is called
int ncount = 0,
temp_row = ROWS,
temp_col = COLUMNS;
//create 2-d array of the same size as the grid
ngrid = new int *[ROWS];
for( int i = 0; i < ROWS; ++i )
{
ngrid[i] = new int [COLUMNS];
}
//initialize all elements of the newly created array to 0
for( int i = 0; i < ROWS; ++i )
{
for( int j = 0; j < COLUMNS; ++j )
{
ngrid[i][j] = 0;
}
}
//call addLayer() to add a boundary of dead cells around the ground
addLayer();
//this for loop checks all 8 possible cells around each cell to see if
//that cell has any neighbor cells that are alive. If an alive cell is found
//ncount is incremented and then stored into the neighbor grid 2-d array
//after each conditional statement is checked. ncount is then set to 0 to
//start count all over for next cell in line.
for( int i = 1; i < temp_row; ++i )
{
for( int j = 1; j < temp_col; ++j )
{
if( grid[i-1][j-1] == '1' )
ncount++;
if( grid[i-1][j] == '1' )
ncount++;
if( grid[i-1][j+1] == '1' )
ncount++;
if( grid[i][j-1] == '1' )
ncount++;
if( grid[i][j+1] == '1' )
ncount++;
if( grid[i+1][j-1] == '1' )
ncount++;
if( grid[i+1][j] == '1' )
ncount++;
if( grid[i+1][j+1] == '1' )
ncount++;
ngrid[(i-1)][(j-1)] = ncount;
ncount = 0;
}
}
}
life.h
//This header file provides the prototypes of the function definitions
//for the project.
#ifndef life_h
#define life_h
#include <iostream>
#include <fstream>
#include <stdlib.h>
using namespace std;
void populateWorld(const char * file);
void showWorld();
void iterateGeneration();
void changeGrid();
void addLayer();
void findParameters();
void getNeighborCount();
#endif
life_driver.cpp
// This is driver's code
#ifdef linux
#define LINUX true
#define WINDOWS false
#endif
#ifdef __WIN32__
#define LINUX false
#define WINDOWS true
#endif
#include <iostream>
#include <fstream>
#include "life.h"
const char FILE_NAME[] = "glider_gun_fight.txt";
using namespace std;
const int NUM_GENERATIONS = 10; //set to a smaller number for debugging
int main()
{
populateWorld(FILE_NAME);
showWorld();
for (int iteration = 0; iteration < NUM_GENERATIONS; iteration++)
{
if (WINDOWS)
system("cls"); //Windows only
else
system("clear"); //Linux only
iterateGeneration();
showWorld();
}
if (WINDOWS)
system("PAUSE");
return 0;
}
glider_gun_fight.txt
0000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000010000000000000000000000000000000000000000000
0000000000000000000000000000001010000000000000000000000000000000000000000000
0000000000000000000011000000110000000000001100000000000000000000000000000000
0000000000000000000100010000110000000000001100000000000000000000000110000000
0000000011000000001000001000110000000000000000000000000000000000000110000000
0000000011000000001000101100001010000000000000000000000000000000000000000000
0000000000000000001000001000000010000000000000000000000000000000000000000000
0000000000000000000100010000000000000000000000000000000000000000000000000000
0000000000000000000011000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.