Hi, I am having a problem with an assignment for a C++ course. I have to make a Game of Life simulator (predator and prey). There are two organisms, lion and ant, and the lions eat the ants.
My problem is that for some reason I can't fathom, the lions are disappearing when they aren't supposed to.
I won't post the whole thing for readability sake, just the parts I think are relevant. Let me know if I should include other files.
World.h
#ifndef _WORLD_H
#define _WORLD_H
#include <iostream>
using namespace std;
class Organism;
const int GRID_WIDTH = 20;
const int GRID_HEIGHT = 20;
class World
{
protected:
Organism *grid[GRID_WIDTH][GRID_HEIGHT];
public:
World();
virtual ~World();
Organism *getOrganism( int x, int y );
void setOrganism( Organism *organism, int x, int y );
void move();
friend ostream& operator<<( ostream &output, World &world );
};
#endif
World.cpp
#include <iostream>
#include "World.h"
#include "Organism.h"
#include "Ant.h"
#include "Lion.h"
using namespace std;
World::World()
{
for( int i=0; i<GRID_WIDTH; i++ )
{
for( int j=0; j<GRID_HEIGHT; j++ )
{
grid[i][j] = NULL;
}
}
}
World::~World()
{
//free up allocated memory
for( int i=0; i<GRID_WIDTH; i++ )
{
for( int j=0; j<GRID_HEIGHT; j++ )
{
if( grid[i][j] != NULL )
{
delete grid[i][j];
}
}
}
}
Organism *World::getOrganism( int x, int y )
{
return grid[x][y];
}
void World::setOrganism( Organism *organism, int x, int y )
{
grid[x][y] = organism;
}
void World::move()
{
// object method call priority:
// 1 - Move all lions
for( int i=0; i<GRID_WIDTH; i++ )
{
for( int j=0; j<GRID_HEIGHT; j++ )
{
// verify organism is a lion and that the lion
// has not already moved once, before moving
if( (dynamic_cast<lion *>(grid[i][j]) != NULL) &&
(grid[i][j]->isTurn()) )
{
grid[i][j]->move();
}
}
}
// 2 - Move all ants
for( int i=0; i<GRID_WIDTH; i++ )
{
for( int j=0; j<GRID_HEIGHT; j++ )
{
// verify organism is an ant and that the ant
// has not already moved once, before moving
if( (dynamic_cast<ant *>(grid[i][j]) != NULL) &&
(grid[i][j]->isTurn()) )
{
grid[i][j]->move();
}
}
}
// 3 - Breed all eligible lions
for( int i=0; i<GRID_WIDTH; i++ )
{
for( int j=0; j<GRID_HEIGHT; j++ )
{
// verify organism is a lion and that it's the lion's
// turn before attempting to breed
if( (dynamic_cast<lion *>(grid[i][j]) != NULL) &&
(grid[i][j]->isTurn()) )
{
grid[i][j]->breed();
}
}
}
// 4 - Breed all eligible ants
for( int i=0; i<GRID_WIDTH; i++ )
{
for( int j=0; j<GRID_HEIGHT; j++ )
{
// verify organism is an ant and that it's the ant's
// turn before attempting to breed
if( (dynamic_cast<ant *>(grid[i][j]) != NULL) &&
(grid[i][j]->isTurn()) )
{
grid[i][j]->breed();
}
}
}
// 6 - Starve all eligible lions
for( int i=0; i<GRID_WIDTH; i++ )
{
for( int j=0; j<GRID_HEIGHT; j++ )
{
// verify organism is a lion and that it's the lion's
// turn before attempting to starve
if( (dynamic_cast<lion *>(grid[i][j]) != NULL) &&
(grid[i][j]->isTurn()) )
{
(dynamic_cast<lion *>(grid[i][j])->starve());
}
}
}
// 7 - End all the organism's turns
for( int i=0; i<GRID_WIDTH; i++ )
{
for( int j=0; j<GRID_HEIGHT; j++ )
{
// verify presence of organism
if( grid[i][j] != NULL )
{
grid[i][j]->endTurn();
}
}
}
// 8 - All remaining organisms have "survived" this step. Increment each organism's counter by one.
for( int i=0; i<GRID_WIDTH; i++ )
{
for( int j=0; j<GRID_HEIGHT; j++ )
{
// verify presence of organism
if( grid[i][j] != NULL )
{
grid[i][j]->incCounter();
}
}
}
}
ostream& operator<<( ostream &output, World &world )
{
// display grid
for( int i=0; i<GRID_WIDTH; i++ )
{
for( int j=0; j<GRID_HEIGHT; j++ )
{
output << world.grid[i][j];
}
output << endl;
}
return output;
}
Lion.h
#ifndef _Lion_H
#define _Lion_H
#include "Organism.h"
class lion : public Organism
{
protected:
int newX,
newY;
bool eaten;
public:
lion();
lion( World *world, int width, int height);
virtual ~lion();
void eat(int coordX, int coordY);
void move();
void breed();
void starve();
void spawn(int coordX, int coordY);
};
#endif
Lion.cpp
#include <cstdlib>
#include <ctime>
#include "World.h"
#include "Ant.h"
#include "Lion.h"
using namespace std;
lion::lion()
{
}
lion::lion( World *world, int width, int height)
:Organism( world, width, height )
{
srand( (unsigned int)time(NULL) );
eaten = false;
}
lion::~lion()
{
}
void lion::eat(int coordX, int coordY)
{
if(dynamic_cast<ant *>(world->getOrganism(coordX, coordY)) != NULL) // if the space is occupied by an ant
{
// move to the ant's space and replace with the lion
newX = coordX;
newY = coordY;
world->setOrganism( this, newX, newY );
world->setOrganism( NULL, x, y );
x = newX;
y = newY;
}
}
void lion::move()
{
int direction;
// eat the first ant that the lion comes across, and move into its space
if( // the space is occupied,
(world->getOrganism(x, y-1) != NULL) &&
// the space isn't over the edge of the grid,
(x >= 0) && (y-1 >=0) && (x < GRID_WIDTH) && (y-1 < GRID_HEIGHT) &&
// and the space is occupied by an ant,
(dynamic_cast<ant *>(world->getOrganism(x, y-1)) != NULL) )
{
// replace the ant with the lion
eat(x, y-1);
eaten = true;
}
else if((world->getOrganism(x, y+1) != NULL) && (x >= 0) && (y+1 >=0) &&
(x < GRID_WIDTH) && (y+1 < GRID_HEIGHT) && (dynamic_cast<ant *>(world->getOrganism(x, y+1)) != NULL)) // SOUTH
{
eat(x, y+1);
eaten = true;
}
else if((world->getOrganism(x+1, y) != NULL) && (x+1 >= 0) && (y >=0) &&
(x+1 < GRID_WIDTH) && (y < GRID_HEIGHT) && (dynamic_cast<ant *>(world->getOrganism(x+1, y)) != NULL)) // EAST
{
eat(x+1, y);
eaten = true;
}
else if((world->getOrganism(x-1, y) != NULL) && (x-1 >= 0) && (y >=0) &&
(x-1 < GRID_WIDTH) && (y < GRID_HEIGHT) && (dynamic_cast<ant *>(world->getOrganism(x-1, y)) != NULL)) // WEST
{
eat(x-1, y);
eaten = true;
}
else if((world->getOrganism(x+1, y-1) != NULL) && (x+1 >= 0) && (y-1 >=0) &&
(x+1 < GRID_WIDTH) && (y-1 < GRID_HEIGHT) && (dynamic_cast<ant *>(world->getOrganism(x+1, y-1)) != NULL)) // NORTHEAST
{
eat(x+1, y-1);
eaten = true;
}
else if((world->getOrganism(x-1, y-1) != NULL) && (x-1 >= 0) && (y-1 >=0) &&
(x-1 < GRID_WIDTH) && (y-1 < GRID_HEIGHT) && (dynamic_cast<ant *>(world->getOrganism(x-1, y-1)) != NULL)) // NORTHWEST
{
eat(x-1, y-1);
eaten = true;
}
else if((world->getOrganism(x+1, y+1) != NULL) && (x+1 >= 0) && (y+1 >=0) &&
(x+1 < GRID_WIDTH) && (y+1 < GRID_HEIGHT) && (dynamic_cast<ant *>(world->getOrganism(x+1, y+1)) != NULL)) // SOUTHEAST
{
eat(x+1, y+1);
eaten = true;
}
else if((world->getOrganism(x-1, y+1) != NULL) && (x-1 >= 0) && (y+1 >=0) &&
(x-1 < GRID_WIDTH) && (y+1 < GRID_HEIGHT) && (dynamic_cast<ant *>(world->getOrganism(x-1, y+1)) != NULL)) // SOUTHWEST
{
eat(x-1, y+1);
eaten = true;
}
else // move normally
{
direction = rand() % NUM_DIRECTIONS;
switch( direction )
{
case NORTH:
newX = x;
newY = y - 1;
break;
case SOUTH:
newX = x;
newY = y + 1;
break;
case EAST:
newX = x + 1;
newY = y;
break;
case WEST:
newX = x - 1;
newY = y;
break;
default:
break;
}
// check limits of the grid
if( newX < 0 ) newX = 0;
if( newY < 0 ) newY = 0;
if( newX >= GRID_WIDTH ) newX = GRID_WIDTH - 1;
if( newY >= GRID_HEIGHT ) newY = GRID_HEIGHT - 1;
// move lion to new location
if( world->getOrganism( newX, newY ) == NULL )
{
world->setOrganism( this, newX, newY );
world->setOrganism( NULL, x, y );
x = newX;
y = newY;
}
}
}
void lion::breed()
{
// if 8 turns are up, attempt to breed
if(counter % 8 == 0 && counter != 0)
{
// check availability of surrounding spaces for breeding
if((world->getOrganism(x, y-1) == NULL) && (x >= 0) && (y-1 >=0) &&
(x < GRID_WIDTH) && (y-1 < GRID_HEIGHT) ) // NORTH
{
// if the space is available, place new lion
spawn(x, y-1);
}
else if((world->getOrganism(x, y+1) == NULL) && (x >= 0) && (y+1 >=0) &&
(x < GRID_WIDTH) && (y+1 < GRID_HEIGHT) ) // SOUTH
{
spawn(x, y+1);
}
else if((world->getOrganism(x+1, y) != NULL) && (x+1 >= 0) && (y >=0) &&
(x+1 < GRID_WIDTH) && (y < GRID_HEIGHT)) // EAST
{
spawn(x+1, y);
}
else if((world->getOrganism(x-1, y) != NULL) && (x-1 >= 0) && (y >=0) &&
(x-1 < GRID_WIDTH) && (y < GRID_HEIGHT) ) // WEST
{
spawn(x-1, y);
}
// if no available spaces, do not breed
}
}
void lion::starve()
{
// if three turns have gone by
if(counter % 3 == 0 && counter != 0)
{
// the lion will starve if it hasn't eaten
if(eaten == false)
{
world->setOrganism(NULL, x, y);
}
else
{
eaten = false;
}
}
// last action for lion of its turn
done = true;
}
void lion::spawn(int coordX, int coordY)
{
// method to be called from breed() to instantiate new lion
lion *offspring = new lion( world, GRID_WIDTH, GRID_HEIGHT );
offspring->setPosition( coordX, coordY );
world->setOrganism(offspring, coordX, coordY );
}
Ant.h
#ifndef _Ant_H
#define _Ant_H
#include "Organism.h"
class ant : public Organism
{
public:
ant();
ant( World *world, int width, int height );
virtual ~ant();
void move();
void breed();
void spawn(int coordX, int coordY);
};
#endif
Ant.cpp
#include <cstdlib>
#include <ctime>
#include "World.h"
#include "Ant.h"
using namespace std;
ant::ant()
{
}
ant::ant( World *world, int x, int y )
: Organism( world, x, y )
{
srand( (unsigned int)time(NULL) );
}
ant::~ant()
{
}
void ant::move()
{
int direction;
direction = rand() % 4;
int newX, newY;
switch( direction )
{
case NORTH:
newX = x;
newY = y - 1;
break;
case SOUTH:
newX = x;
newY = y + 1;
break;
case EAST:
newX = x + 1;
newY = y;
break;
case WEST:
newX = x - 1;
newY = y;
break;
default:
break;
}
// check limits of the grid
if( newX < 0 ) newX = 0;
if( newY < 0 ) newY = 0;
if( newX >= GRID_WIDTH ) newX = GRID_WIDTH - 1;
if( newY >= GRID_HEIGHT ) newY = GRID_HEIGHT - 1;
// move ant to new location
if( world->getOrganism( newX, newY ) == NULL )
{
world->setOrganism( this, newX, newY );
world->setOrganism( NULL, x, y );
x = newX;
y = newY;
}
}
void ant::breed()
{
// if 3 turns are up, attempt to breed
if(counter % 3 && counter != 0)
{
// check availability of surrounding spaces for breeding
if((world->getOrganism(x, y-1) == NULL) && (x >= 0) && (y-1 >=0) &&
(x < GRID_WIDTH) && (y-1 < GRID_HEIGHT) ) // NORTH
{
// if the space is available, place new ant
spawn(x, y-1);
}
else if((world->getOrganism(x, y+1) == NULL) && (x >= 0) && (y+1 >=0) &&
(x < GRID_WIDTH) && (y+1 < GRID_HEIGHT) ) // SOUTH
{
spawn(x, y+1);
}
else if((world->getOrganism(x+1, y) != NULL) && (x+1 >= 0) && (y >=0) &&
(x+1 < GRID_WIDTH) && (y < GRID_HEIGHT)) // EAST
{
spawn(x+1, y);
}
else if((world->getOrganism(x-1, y) != NULL) && (x-1 >= 0) && (y >=0) &&
(x-1 < GRID_WIDTH) && (y < GRID_HEIGHT) ) // WEST
{
spawn(x-1, y);
}
// if no available spaces, do not breed
// last action for ant of its turn
done = true;
}
}
void ant::spawn(int coordX, int coordY)
{
ant *offspring = new ant( world, GRID_WIDTH, GRID_HEIGHT );
offspring->setPosition( coordX, coordY );
world->setOrganism(offspring, coordX, coordY );
}
Organism.h (base class)
#ifndef _Organism_H
#define _Organism_H
#include <iostream>
using namespace std;
class World;
class Organism
{
protected:
int x;
int y;
int width;
int height;
int counter;
bool done;
World *world;
enum { WEST, NORTH, EAST, SOUTH, NUM_DIRECTIONS };
public:
Organism();
Organism( World *world, int width, int height );
virtual ~Organism();
virtual void move();
virtual void breed();
virtual void spawn();
void incCounter();
void setPosition( int x, int y );
void endTurn();
bool isTurn();
friend ostream& operator<<( ostream &output, Organism *organism );
};
#endif
Organism.cpp
#include <iostream>
#include "World.h"
#include "Organism.h"
#include "Ant.h"
#include "Lion.h"
using namespace std;
Organism::Organism() : done(false)
{
}
Organism::Organism( World *world, int width, int height ) : done(false)
{
this->world = world;
this->width = width;
this->height = height;
counter = 0;
}
Organism::~Organism()
{
}
void Organism::incCounter()
{
counter++;
}
void Organism::setPosition( int x, int y )
{
this->x = x;
this->y = y;
}
void Organism::endTurn()
{
done = false;
}
bool Organism::isTurn()
{
return !done;
}
ostream& operator<<( ostream &output, Organism *organism )
{
if( dynamic_cast<ant *>(organism) != NULL )
{
output << "O ";
}
else if( dynamic_cast<lion *>(organism) != NULL )
{
output << "X ";
}
else
{
output << "- ";
}
return output;
}
void Organism::spawn(){}
void Organism::move(){}
void Organism::breed(){}
Hopefully someone can see what I've missed.
thanks