This is my attempt on the Conway's "Game of Life" using C++. The code is functional but I am sure most aspects of the code might have been poorly constructed as I am fairly new at this. Please give any suggestions on how to improve my coding standards such as coding style, syntax, naming convention, error handling (although not much has been done) etc...
Points to note:
I have used pointers (
char**
grid) to aid in dynamic memory allocation, this way the code can be easily tweaked to dynamically expand the grid if needed (I hope so).the temp array (
char** cpy
) is used for temporary copy and is always deallocated after each iteration (Release()
).
Execute.h
#ifndef EXECUTE
#define EXECUTE
#include <iostream>
#include <iomanip>
#include "clear.h"
#define ALIVE '*'
#define DEAD '.'
class Execute
{
private:
/* 2D grid array */
char **grid;
/* copy */
char** cpy;
/* grid row and column sizes */
const int rows;
const int cols;
/* number of surrounding cells ALIVE*/
int numOfCellsAlive;
/* copy */
void Clone(char** grid);
/* release memory*/
void Release(char** mem);
/* compute cell status */
void AliveOrDead(char **grid);
/* run */
void Run();
protected:
public:
/* default C'Tor */
Execute();
/* C'Tor */
Execute(int x, int y);
/* copy constructor */
Execute(const Execute& copy);
/* default D'Tor */
~Execute();
/* render */
void RenderGrid(char **grid);
};
#endif // !EXECUTE
Execute.cpp
#include "Execute.h"
Execute::Execute(int x, int y) : rows(x), cols(y), numOfCellsAlive(0)
{
if (grid == NULL)
{
grid = new char* [rows];
for (int i(0); i < rows; i++)
{
grid[i] = new char[cols];
for (int j(0); j < cols; j++)
{
grid[i][j] = DEAD;
}
}
}
/* alives cells */
grid[20][20] = ALIVE;
grid[21][22] = ALIVE;
grid[22][19] = ALIVE;
grid[22][20] = ALIVE;
grid[22][23] = ALIVE;
grid[22][24] = ALIVE;
grid[22][25] = ALIVE;
Run();
}
Execute::~Execute()
{
Release(grid);
}
/* print grid */
void Execute::RenderGrid(char **grid)
{
std::cout << "\n";
for (int i(0); i < rows; i++)
{
std::cout << std::setw(5);
for (int j(0); j < cols; j++)
{
std::cout << grid[i][j];
}
std::cout << "\n";
}
}
/* compute next generation cycle */
void Execute::AliveOrDead(char **grid)
{
Clone(grid);
for (int i(0); i < rows; i++)
{
for (int j(0); j < cols; j++)
{
if ((j + 1) < cols && cpy[i][j + 1] == '*')
{
numOfCellsAlive++;
}
if ((j - 1) >= 0 && cpy[i][j - 1] == '*')
{
numOfCellsAlive++;
}
if ((j - 1) >= 0 && (i - 1) >= 0 && cpy[i - 1][j - 1] == '*')
{
numOfCellsAlive++;
}
if ((i - 1) >= 0 && cpy[i - 1][j] == '*')
{
numOfCellsAlive++;
}
if ((i - 1) >= 0 && (j + 1) < cols && cpy[i - 1][j + 1] == '*')
{
numOfCellsAlive++;
}
if ((i + 1) < rows && (j - 1) >= 0 && cpy[i + 1][j - 1] == '*')
{
numOfCellsAlive++;
}
if ((i + 1) < rows && cpy[i + 1][j] == '*')
{
numOfCellsAlive++;
}
if ((i + 1) < rows && (j + 1) < cols && cpy[i + 1][j + 1] == '*')
{
numOfCellsAlive++;
}
// case 1: the cell dies
if (numOfCellsAlive < 2 || numOfCellsAlive > 3)
{
grid[i][j] = DEAD;
}
// case 2: the cell stays same
else if (numOfCellsAlive == 2)
{
grid[i][j] = cpy[i][j];
}
// case 3: the cell stays alive or is "born"
else if (numOfCellsAlive == 3)
{
grid[i][j] = ALIVE;
}
numOfCellsAlive = 0;
}
}
Release(cpy);
}
/* create copy of grid for comparism */
void Execute::Clone(char **grid)
{
cpy = new char*[rows];
for (int i(0); i < rows; i++)
{
cpy[i] = new char[cols];
for (int j(0); j < cols; j++)
{
cpy[i][j] = grid[i][j];
}
}
}
/* deallocate memory from heap */
void Execute::Release(char** mem)
{
if (mem != NULL)
{
for (int i(0); i < rows; i++)
{
delete[] mem[i];
}
delete[] mem;
}
}
/* run the "Game of Life" */
void Execute::Run()
{
do
{
RenderGrid(grid);
AliveOrDead(grid);
cursorHome(0, 0);
} while (true);
}
clear.h
/* windows cursor positioning */
void cursorHome(int x, int y);
clear.cpp
#include "clear.h"
#ifdef _WIN32 || _WIN64
#include <windows.h>
void cursorHome(int x, int y)
{
COORD pos = { x, y };
HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(output, pos);
}
#else
#include <unistd.h>
void clearconsole()
{
write(1, "\E[H\E[2J", 7);
}
#endif
main.cpp
#include "Execute.h"
void main(void)
{
/*std::cout << "+-----------------------+" << std::endl;
std::cout << "| Conway's Game of Life |" << std::endl;
std::cout << "+-----------------------+" << std::endl;*/
try
{
const int rows = 50;
const int cols = 70;
Execute execute(rows, cols);
}
catch (std::exception &e)
{
std::cout << e.what() << std::endl;
}
catch (...)
{
std::cerr << "Fatal exception: " << "\n";
}
system("pause");
}