This is a small console game that simulates life forms as they reproduce on a grid. The code works well enough, but I'm interested in suggestions to make it more optimal/efficient. It just seems a bit too "messy" at the moment.
/* ---------LIFE---------
Programmer : Me
Version : 1.0
Date : 14 February 2014
----------------------
*/
#include <iostream>
#include <string>
#include <ctime>
usingnamespace std;
constint LIFESPAN = 12; // turns until death
constint REPRODUCE_CHANCE = 80; // % chance to successfully reproduce
struct GameBoard
{
int age;
bool active;
};
GameBoard gboard[10][10];
//'age' != 0 then life is in this grid; otherwise 0 == no life in this grid.
//'active' is to prevent single turn from overpopulating - explained more below
inlinevoid Randomize() { srand(time(0)); }
int Random(int minVal, int maxVal)
{
int r;
r= rand();
r = (r % (maxVal-minVal+1)) + minVal;
return r;
}
void DisplayScreen()
{
/*
Draw the Game Board on the console screen
# = lifeform in grid
blank [space] = empty grid
* = grid border
*/
system("cls");
string thisLine;
cout << "* ********** *\n";
for (int i=0; i<10; ++i)
{
thisLine = "* ";
for (int j=0; j<10; ++j) {
thisLine += (gboard[i][j].age != 0) ? "#" : " "; }
thisLine += " *\n";
cout << thisLine;
}
cout << "* ********** *\n";
}
void ExecuteTurn()
{
//Loop through each game board grid
for (int i=0; i<10; ++i) {
for (int j=0; j<10; ++j)
{
//LIFE FORM CHECK * *
//If a game board grid contains a lifeform and is active...
if (gboard[i][j].age != 0 && gboard[i][j].active == true)
{
//Increase age by 1
gboard[i][j].age += 1;
//REPRODUCTION CHECK * * *
//Determine if this lifeform will reproduce this turn
int chanceForLife = Random(1,100);
if (chanceForLife <= REPRODUCE_CHANCE)
{
//Life will reproduce - choose random direction to make new lifeform
bool goodDirection = false;
while (goodDirection == false)
{
int nDir = Random(0,3);
int nColumn = i;
int nRow = j;
switch (nDir)
{
case 0:
//above this grid
nColumn -= 1;
if (nColumn >= 0) goodDirection = true;
break;
case 1:
//right of this grid
nRow += 1;
if (nRow <= 9) goodDirection = true;
break;
case 2:
//below this grid
nColumn += 1;
if (nColumn <= 9) goodDirection = true;
break;
default:
//left of this grid
nRow -= 1;
if (nRow >= 0) goodDirection = true;
break;
}
//Good direction has been choosen
//make this a new lifeform - age 1
gboard[nColumn][nRow].age = 1;
/* ACTIVE =
Necessary to keep loop from immediately actioning on NEW lifeforms
Otherwise you will end up with 1/2 the grid full on a single 'turn'
*/
gboard[nColumn][nRow].active = false;
}
} //END OF REPRODUCTION CHECK * * *
//Kill old lifeforms
if (gboard[i][j].age >= LIFESPAN) gboard[i][j].age = 0;
} //END OF LIFE FORM CHECK * *
}} //Game board grid for loops (x2)
//This turn is complete - make all lifeforms active
for (int i=0; i<10; ++i)
for (int j=0; j<10; ++j)
gboard[i][j].active = true;
}
void CreateRandomLife(int Count)
{
for (int i=0; i<Count; ++i)
{
int iCol = Random(0,9);
int iRow = Random(0,9);
gboard[iCol][iRow].age = 1;
gboard[iCol][iRow].active = true;
}
}
void ResetGame()
{
//Kill all life
for (int i=0; i<10; ++i)
for (int j=0; j<10; ++j)
{ gboard[i][j].age = 0; gboard[i][j].active = false; }
//Create 3 random lifeforms to begin
CreateRandomLife(3);
}
int main()
{
Randomize();
ResetGame();
DisplayScreen();
bool gameIsRunning = true;
while (gameIsRunning)
{
cout << "\n\nHow many times would you like to run the simulation? ";
int simCount;
cin >> simCount;
if (simCount < 0) simCount = 0;
if (simCount > 50) simCount = 50;
//Run sim
for (int i=0; i<simCount; ++i)
{
ExecuteTurn();
}
DisplayScreen();
if (simCount == 0)
{
cout << "\nWould you like to play again (y/n)? ";
char answer;
cin >> answer;
gameIsRunning = (answer == 'y') ? true : false;
if (gameIsRunning == true) { ResetGame(); DisplayScreen(); }
}
}
return 0;
}
Thanks for the feedback. I was never really sure how often to call it. That clears up quite a bit - for this and a few other programs I've created. Thanks again.