I am looking for a review on one of my homework assignments for this semester.
This homework has already been submitted and graded and my final has already been submitted so there is no cheating or conflict of interest in my review request!
I would love some advice on how to better manage my class interactions and how to better encapsulate data. The specific area I struggle with is when using parent classes and giving access to only protected assets from child classes. My professor has mentioned on several occasions that it would be much better to keep data private and give access through functions, but how would I initialize those member variables when instantiating an instance of a child class that has private members in the parent class?
I understand the idea of encapsulation is to protect data that shouldn't be manipulated by outside programmers or irrelevant classes. I was the sole developer on this project so I understand in this specific example encapsulation may not be paramount, but on a larger project with multiple engineers it would certainly be relevant.
Includes
#include "stdafx.h"
#include <iostream>
#include <ctime>
#include <vector>
using namespace std;
** Note the coordinates struct just contains an integer xCoordinate and an integer yCoordinate
main
int main()
{
//Create environment object containing
environment antDoodlebugSimulation;
antDoodlebugSimulation.InitializeSimulation();
return 0;
}
Environment
class environment
{
//friends of environment
friend class organism;
friend class doodlebug;
friend class ant;
private:
organism * environmentBoard[20][20];
void CreateStartPopulation();
int GenerateRandomStartingLocations(int min, int max);
void OutputCurrentEnvironment();
void DoodlebugsAct();
void AntsAct();
void ResetCritterTimeStep();
public:
//constructor
environment();
//deconstructor
~environment();
//public member functions
void InitializeSimulation();
};
environment::environment()
{
//Initialize environmentBoard array for entirely empty...all nullptr
for (int yCounter = 0; yCounter < 20; yCounter++)
for (int xCounter = 0; xCounter < 20; xCounter++)
this->environmentBoard[xCounter][yCounter] = nullptr;
//Add ants and doodlebugs into game environment
CreateStartPopulation();
}
void environment::OutputCurrentEnvironment()
{
//Outputs current environment to the screen
for (int yCounter = 0; yCounter < 20; yCounter++)
{
for (int xCounter = 0; xCounter < 20; xCounter++)
if (this->environmentBoard[xCounter][yCounter] == nullptr)
cout << '-';
else
cout << *environmentBoard[xCounter][yCounter];
cout << endl;
}
}
void environment::CreateStartPopulation()
{
//Populates game board for start of simulation
coordinates newLocation;
//Fill 5 doodlebugs
for (int doodleCounter = 0; doodleCounter < 5; doodleCounter++)
{
newLocation.xCoordinate = GenerateRandomStartingLocations(0, 19);
newLocation.yCoordinate = GenerateRandomStartingLocations(0, 19);
//Incase something already placed
while (this->environmentBoard[newLocation.xCoordinate][newLocation.yCoordinate] != nullptr)
{
newLocation.xCoordinate = GenerateRandomStartingLocations(0, 19);
newLocation.yCoordinate = GenerateRandomStartingLocations(0, 19);
}
this->environmentBoard[newLocation.xCoordinate][newLocation.yCoordinate] = new doodlebug(newLocation.xCoordinate, newLocation.yCoordinate, this);
}
for (int antCounter = 0; antCounter < 100; antCounter++)
{
newLocation.xCoordinate = GenerateRandomStartingLocations(0, 19);
newLocation.yCoordinate = GenerateRandomStartingLocations(0, 19);
//Incase something already placed
while (this->environmentBoard[newLocation.xCoordinate][newLocation.yCoordinate] != nullptr)
{
newLocation.xCoordinate = GenerateRandomStartingLocations(0, 19);
newLocation.yCoordinate = GenerateRandomStartingLocations(0, 19);
}
this->environmentBoard[newLocation.xCoordinate][newLocation.yCoordinate] = new ant(newLocation.xCoordinate, newLocation.yCoordinate, this);
}
}
int environment::GenerateRandomStartingLocations(int min, int max)
{
static bool firstIteration = true;
if (firstIteration)
{
//Seed once
srand(time(NULL));
firstIteration = false;
}
//Generate random number between range
return rand() % (max - min + 1) + min;
}
void environment::AntsAct()
{
//Iterate over environment
for(int yCounter = 0; yCounter < 20; yCounter++)
for (int xCounter = 0; xCounter < 20; xCounter++)
{
if (this->environmentBoard[xCounter][yCounter] != nullptr)
{
if (this->environmentBoard[xCounter][yCounter]->GetIdentifierTag() == 'o' && !(this->environmentBoard[xCounter][yCounter]->GetMoveAlternatorStatus()))
{
//Toggle moveAlternator
this->environmentBoard[xCounter][yCounter]->ToggleMoveAlternator();
//Move ant....Move function must return coordinate otherwise we attempt to increment/breed null pointer after movement
this->environmentBoard[xCounter][yCounter]->Move();
}
}
}
//Iterate over Ants again and breed
for(int yCounter = 0; yCounter < 20; yCounter++)
for (int xCounter = 0; xCounter < 20; xCounter++)
{
if (this->environmentBoard[xCounter][yCounter] != nullptr)
{
if (this->environmentBoard[xCounter][yCounter]->GetIdentifierTag() == 'o')
{
//Increment Ant Breeding cycle
this->environmentBoard[xCounter][yCounter]->IncrementBreedingCycle();
//Check if ready to breed
if (this->environmentBoard[xCounter][yCounter]->TimeToBreed())
{
this->environmentBoard[xCounter][yCounter]->Breed();
}
}
}
}
}
void environment::DoodlebugsAct()
{
//Move and eat if ant is found
for (int yCounter = 0; yCounter < 20; yCounter++)
{
for (int xCounter = 0; xCounter < 20; xCounter++)
{
//Not null pointer...a doodlebug....and has not already moved
if (this->environmentBoard[xCounter][yCounter] != nullptr && this->environmentBoard[xCounter][yCounter]->GetIdentifierTag() == 'X' && !this->environmentBoard[xCounter][yCounter]->GetMoveAlternatorStatus())
{
this->environmentBoard[xCounter][yCounter]->ToggleMoveAlternator();
this->environmentBoard[xCounter][yCounter]->Move();
}
}
}
//Breed and then check death cycle
for (int yCounter = 0; yCounter < 20; yCounter++)
{
for (int xCounter = 0; xCounter < 20; xCounter++)
{
if (this->environmentBoard[xCounter][yCounter] != nullptr && this->environmentBoard[xCounter][yCounter]->GetIdentifierTag() == 'X')
{
//Increment breeding step
this->environmentBoard[xCounter][yCounter]->IncrementBreedingCycle();
//Check if ready to breed
if (this->environmentBoard[xCounter][yCounter]->TimeToBreed())
this->environmentBoard[xCounter][yCounter]->Breed();
//Check if dying
if (this->environmentBoard[xCounter][yCounter]->Death())
this->environmentBoard[xCounter][yCounter]->Die();
}
}
}
}
void environment::ResetCritterTimeStep()
{
//Reset all critter time steps at the end of iteration
for (int yCounter = 0; yCounter < 20; yCounter++)
for (int xCounter = 0; xCounter < 20; xCounter++)
if (this->environmentBoard[xCounter][yCounter] != nullptr && (this->environmentBoard[xCounter][yCounter]->GetIdentifierTag() == 'o' || this->environmentBoard[xCounter][yCounter]->GetIdentifierTag() == 'X'))
this->environmentBoard[xCounter][yCounter]->ToggleMoveAlternator();
}
void environment::InitializeSimulation()
{
int numOfants, numOfDoodleBugs;
OutputCurrentEnvironment();
cout << "Simulation initialized starting with 5 doodle bugs and 100 ants. Please begin simulation by pressing the enter key\n";
while(cin.get() == '\n')
{
//Manage simulation
numOfants = 0;
numOfDoodleBugs = 0;
//Call doodlebugs to act
DoodlebugsAct();
//Call ants to act
AntsAct();
//Reset all critter time steps
ResetCritterTimeStep();
//output graphical environment status
OutputCurrentEnvironment();
//For easy visual of fluctuations between predator and prey populations
for (int yCounter = 0; yCounter < 20; yCounter++)
for (int xCounter = 0; xCounter < 20; xCounter++)
if (this->environmentBoard[xCounter][yCounter] != nullptr)
if (this->environmentBoard[xCounter][yCounter]->GetIdentifierTag() == 'o')
numOfants++;
else
numOfDoodleBugs++;
cout << "Ants: " << numOfants << endl;
cout << "Doodlebugs: " << numOfDoodleBugs << endl;
cout << "To continue simulation please press enter; otherwise enter -1: ";
}
}
environment::~environment()
{
//Clean up memory for object and repoint all dangling pointers
for(int yCounter = 0; yCounter < 20; yCounter++)
for (int xCounter = 0; xCounter < 20; xCounter++)
{
if (this->environmentBoard[xCounter][yCounter] != nullptr)
{
delete this->environmentBoard[xCounter][yCounter];
this->environmentBoard[xCounter][yCounter] = nullptr;
}
}
}
Organism
class organism
{
//Organism parent class
private:
bool moveAlternator = false;
protected:
environment * environmentPointer;
int breedingCycle = 0;
char identifierTag;
coordinates location;
public:
//Constructor
organism() {location.xCoordinate = 0; location.yCoordinate = 0;};
//deconstructor
virtual ~organism() {};
char GetIdentifierTag() const { return this->identifierTag; };
void IncrementBreedingCycle() { breedingCycle += 1; };
coordinates GetLocation() const { return this->location; };
virtual void Move() = 0;
void RandomDirectionalMovement(int direction);
virtual bool TimeToBreed() = 0;
void Die();
virtual bool Death() =0;
void Breed();
void ResetBreedingCycle() { this->breedingCycle = 0; };
void ToggleMoveAlternator();
bool GetMoveAlternatorStatus() const { return moveAlternator; };
void GoNorth() { this->location.yCoordinate -= 1; };
void GoEast() { this->location.xCoordinate += 1; };
void GoSouth() { this->location.yCoordinate += 1; };
void GoWest() { this->location.xCoordinate -= 1; };
friend ostream &operator<<(ostream &output, const organism ¤tOrg) { output << currentOrg.identifierTag; return output; };
};
void organism::ToggleMoveAlternator()
{
if (this->moveAlternator == false)
this->moveAlternator = true;
else
this->moveAlternator = false;
}
void organism::Breed()
{
//Breeds new
//Generate direction to breed in...if empty..breed
int newDirection = this->environmentPointer->GenerateRandomStartingLocations(1, 4);
bool breedSuccesful = false;
//North
if (newDirection == 1)
{
if (this->location.yCoordinate - 1 > -1 && this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate - 1] == nullptr)
{
if (this->GetIdentifierTag() == 'o')//Breed new ant
this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate - 1] = new ant(this->location.xCoordinate, this->location.yCoordinate - 1, this->environmentPointer);
else if (this->GetIdentifierTag() == 'X')//Breed new doodlebug
this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate - 1] = new doodlebug(this->location.xCoordinate, this->location.yCoordinate - 1, this->environmentPointer);
breedSuccesful = true;
}
}
//East
else if (newDirection == 2)
{
if (this->location.xCoordinate + 1 < 20 && this->environmentPointer->environmentBoard[this->location.xCoordinate + 1][this->location.yCoordinate] == nullptr)
{
if(this->GetIdentifierTag() == 'o')//Breed new ant
this->environmentPointer->environmentBoard[this->location.xCoordinate+1][this->location.yCoordinate] = new ant(this->location.xCoordinate+1, this->location.yCoordinate, this->environmentPointer);
else if (this->GetIdentifierTag() == 'X')//Breed new doodlebug
this->environmentPointer->environmentBoard[this->location.xCoordinate + 1][this->location.yCoordinate] = new doodlebug(this->location.xCoordinate + 1, this->location.yCoordinate, this->environmentPointer);
breedSuccesful = true;
}
}
//South
else if (newDirection == 3)
{
if (this->location.yCoordinate + 1 < 20 && this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate + 1] == nullptr)
{
if (this->GetIdentifierTag() == 'o')//Breed new ant
this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate+1] = new ant(this->location.xCoordinate, this->location.yCoordinate+1, this->environmentPointer);
else if (this->GetIdentifierTag() == 'X')//Breed new doodlebug
this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate+1] = new doodlebug(this->location.xCoordinate, this->location.yCoordinate+1, this->environmentPointer);
breedSuccesful = true;
}
}
//West
else if (newDirection == 4)
{
if (this->location.xCoordinate - 1 > -1 && this->environmentPointer->environmentBoard[this->location.xCoordinate - 1][this->location.yCoordinate] == nullptr)
{
if (this->GetIdentifierTag() == 'o')//Breed new ant
this->environmentPointer->environmentBoard[this->location.xCoordinate-1][this->location.yCoordinate] = new ant(this->location.xCoordinate-1, this->location.yCoordinate, this->environmentPointer);
else if (this->GetIdentifierTag() == 'X')//Breed new doodlebug
this->environmentPointer->environmentBoard[this->location.xCoordinate-1][this->location.yCoordinate] = new doodlebug(this->location.xCoordinate-1, this->location.yCoordinate, this->environmentPointer);
breedSuccesful = true;
}
}
if (breedSuccesful)
this->ResetBreedingCycle();
}
void organism::RandomDirectionalMovement(int direction)
{
//North
if (direction == 1)
{
if (this->location.yCoordinate - 1 > -1 && this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate - 1] == nullptr)
{
//Empty space found and valid location within stated environment
//Point new location to current organism object
this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate - 1] = this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate];
//repoint old location to null
this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate] = nullptr;
//update ant location
this->GoNorth();
}
}
//East
else if (direction == 2)
{
if (this->location.xCoordinate + 1 < 20 && this->environmentPointer->environmentBoard[this->location.xCoordinate + 1][this->location.yCoordinate] == nullptr)
{
//Empty space found and valid location with stated environment
//Point new location to current ant object
this->environmentPointer->environmentBoard[this->location.xCoordinate + 1][this->location.yCoordinate] = this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate];
//Repoint old location to null
this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate] = nullptr;
//update ant location
this->GoEast();
}
}
//South
else if (direction == 3)
{
if (this->location.yCoordinate + 1 < 20 && this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate + 1] == nullptr)
{
//Empty space found and valid location with stated environment
//Point new location to current ant object
this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate + 1] = this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate];
//Repoint old location to null
this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate] = nullptr;
//update organism location
this->GoSouth();
}
}
//West
else if (direction == 4)
{
if (this->location.xCoordinate - 1 > -1 && this->environmentPointer->environmentBoard[this->location.xCoordinate - 1][this->location.yCoordinate] == nullptr)
{
//Empty space found and valid location with stated environment
//Point new location to current organism object
this->environmentPointer->environmentBoard[this->location.xCoordinate - 1][this->location.yCoordinate] = this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate];
//Repoint old location to null
this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate] = nullptr;
//update organism location
this->GoWest();
}
}
}
void organism::Die()
{
//repoint location in environment to null
this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate] = nullptr;
//delete
delete this;
doodlebug
class doodlebug : public organism
{
//Doodlebug child class
private:
int starveCounter = 0;
public:
//Constructor
doodlebug(int xLocation, int yLocation, environment * worldPointer) { identifierTag = 'X'; location.xCoordinate = xLocation; location.yCoordinate = yLocation; environmentPointer = worldPointer; };
//Deconstructor
~doodlebug() {};
bool TimeToBreed();
void Move();
coordinates SearchForAnts();
void IncrementStarveCounter() { this->starveCounter += 1; };
void ResetStarveCounter() { this->starveCounter = 0; };
bool Death() { if (this->starveCounter == 3) return true; else return false; };
};
coordinates doodlebug::SearchForAnts()
{
coordinates antFound;
antFound.xCoordinate = -1;
antFound.yCoordinate = -1;
//store checked direction
int directionCheck;
vector<int> storeDirections;
directionCheck = this->environmentPointer->GenerateRandomStartingLocations(1, 4);
//randomize first search direction and store already searched directions
while (storeDirections.size() < 4 && antFound.xCoordinate == -1 && antFound.yCoordinate == -1)
{
//Search North for ant...verify not off the board...verify not null pointer...check if ant
if (directionCheck == 1 && this->location.yCoordinate - 1 > -1 && this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate - 1] != nullptr)
{
if (this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate - 1]->GetIdentifierTag() == 'o')
{
antFound.xCoordinate = this->location.xCoordinate;
antFound.yCoordinate = this->location.yCoordinate - 1;
}
}
//Search East for Ant....
else if (directionCheck == 2 && this->location.xCoordinate + 1 < 20 && this->environmentPointer->environmentBoard[this->location.xCoordinate + 1][this->location.yCoordinate] != nullptr)
{
if (this->environmentPointer->environmentBoard[this->location.xCoordinate + 1][this->location.yCoordinate]->GetIdentifierTag() == 'o')
{
antFound.xCoordinate = this->location.xCoordinate + 1;
antFound.yCoordinate = this->location.yCoordinate;
}
}
//Search South for Ant....
else if (directionCheck == 3 && this->location.yCoordinate + 1 < 20 && this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate + 1] != nullptr)
{
if (this->environmentPointer->environmentBoard[this->location.xCoordinate][this->location.yCoordinate + 1]->GetIdentifierTag() == 'o')
{
antFound.xCoordinate = this->location.xCoordinate;
antFound.yCoordinate = this->location.yCoordinate + 1;
}
}
//Search west for Ant...
else if (directionCheck == 4 && this->location.xCoordinate - 1 > -1 && this->environmentPointer->environmentBoard[this->location.xCoordinate - 1][this->location.yCoordinate] != nullptr)
{
if (this->environmentPointer->environmentBoard[this->location.xCoordinate - 1][this->location.yCoordinate]->GetIdentifierTag() == 'o')
{
antFound.xCoordinate = this->location.xCoordinate - 1;
antFound.yCoordinate = this->location.yCoordinate;
}
}
//Store direction check to increase size of stored directions....guarantees 4
storeDirections.push_back(directionCheck);
if (directionCheck < 4)
{
directionCheck += 1;
}
else
directionCheck = 1;
}
return antFound;
}
Ant
class ant : public organism
{
//ant child class
private:
public:
//Constructor
ant(int xLocation, int yLocation, environment * thisWorld) { identifierTag = 'o'; location.xCoordinate = xLocation; location.yCoordinate = yLocation; environmentPointer = thisWorld; };
//Deconstructor
~ant() {};
void Move();
bool TimeToBreed();
bool Death() { return false; };
};