reate a simple two-dimensional predator-prey simulation. In this simulation the
ID: 3915866 • Letter: R
Question
reate a simple two-dimensional predator-prey simulation. In this simulation the prey are ants and the predators are doodlebugs. These critters live in a world composed of a 20 ×20 grid of pointers to critters. Only one critter may occupy a cell at a time. The grid is enclosed, so a critter is not allowed to move off the edges of the world. Time is simulated in time steps. Each critter performs some action every time step. Doodlebugs eat Ants.
The ants behave according to the following model:
· Move. Every time step, randomly try to move up, down, left, or right. (hints: you can use a random number generator to generate integer from 1 to 4, 1 = right, 2 = down, 3 = left, and 4 = up). If the neighboring cell in the selected direction is occupied or would move the ant off the grid, then the ant stays in the current cell.
· Breed. If an ant survives for three time steps, then at the end of the time step (that is; after moving) the ant will breed. This is simulated by creating a new ant in an adjacent (up, down, left, or right) cell that is empty. If there is no empty cell available, then no breeding occurs. Once an offspring is produced, an ant cannot produce an offspring until three more time steps have elapsed.
The doodlebugs behave according to the following model:
Move. Every time step, if there is an adjacent ant (up, down, left, or right), then the doodlebug will move to that cell and eat the ant. Otherwise, the doodlebug moves according to the same rules as the ant. Note that a doodlebug cannot eat other doodlebugs.
· Breed. If a doodlebug survives for eight time steps, then at the end of the time step it will spawn off a new doodlebug in the same manner as the ant.
· Starve. If a doodlebug has not eaten an ant within the last three time steps, then at the end of the third time step it will starve and die. The doodlebug should then be removed from the grid of cells. During one turn, all the doodlebugs should move before the ants do.
Write a program to implement this simulation and draw the world using ASCII characters of “A” for an ant, “D” for a doodlebug and “.” A dot represent an empty location. This is an example for 10 x 10 world (we want 20 x 20).
....D....A
...A......
A.DA....A.
.....A...A
.D...D..AD
This class should have a virtual function named move that is defined in the derived classes of Ant and Doodlebug.
Create a class named Organism that encapsulates basic data common to both ants and doodlebugs.
Each round shall print 3 grids; 1st for doodlebug movement, 2nd for ant movement, 3rd for what the grid looks like after breeding/starvation.
Initialize the world with 5 doodlebugs and 100 ants. After each time step, prompt the user to press Enter to move to the next time step. You should see a cyclical pattern between the population of predators and prey, although random perturbations may lead to the elimination of one or both species.
Explanation / Answer
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <time.h>
// in question asked to create class name as Organism...
class Organism{
private:
int p;
int q;
int id;
int antsSurvived;
bool antsMoved;
bool antsEaten;
public:
Organism(int p, int q, int id){
this->p = p;
this->q = q;
this->id = id;
this->antsSurvived = 0;
this->antsMoved = false;
this->antsEaten = false;
}
virtual ~Organism() {}
virtual void move(Organism* grid[20][20]) = 0;
virtual char getType()const = 0;
virtual void breed(Organism* grid[20][20], int&) = 0;
virtual void starve(Organism* grid[20][20]){
if (getRoundsSurvived() == 3){
if (getIfAte() == false){
delete grid[getP()][getQ()];
grid[getP()][getQ()] = NULL;
}
}
}
// Getters
int getP()const{ return p; }
int getQ()const{ return q; }
int getID()const{ return id; }
int getRoundsSurvived()const{ return antsSurvived; }
bool getIfMoved()const{ return antsMoved; }
bool getIfAte()const{ return antsEaten; }
// Setters
void setP(int p){ this->p = p; }
void setQ(int q){ this->q = q; }
void setID(int id){ this->id = id; }
void setRoundsSurvived(int antsSurvived){ this->antsSurvived = antsSurvived; }
void setIfMoved(bool condition){ this->antsMoved = condition; }
void setIfAte(bool condition){ this->antsEaten = condition; }
};
class Doodlebug: public Organism{
private:
char type;
public:
Doodlebug(int p, int q, int id): Organism(p, q, id), type('P') {}
virtual ~Doodlebug(){}
char getType()const{ return type; }
void move(Organism* grid[20][20]);
void breed(Organism* grid[20][20], int& doodlebugID);
void starve(Organism* grid[20][20]);
};
void Doodlebug::move(Organism* grid[20][20]){
/*
1. Randomize a direction
(.) Let's define the directions by the following integers
(a) Up: 1
(b) Down: 2
(c) Left: 3
(d) Right: 4
2. Depending on which direction you're going make sure it's a valid direction
(a) A direction is valid if the doodlebug doesn't fall off the grid
3. Swap p, q with that point in the grid by creating a new object and marking
that object as one that moved
//*/
int direction = rand() % 4 + 1;
if (direction == 1 && getP()-1 >= 0 && getIfMoved() == false){
if (grid[getP()-1][getQ()] == NULL){
int newP = getP()-1;
int newQ = getQ();
int newID = getID();
int newRoundsSurvived = getRoundsSurvived()+1;
delete grid[getP()][getQ()];
grid[getP()][getQ()] = NULL;
grid[newP][newQ] = new Doodlebug(newP, newQ, newID);
grid[newP][newQ]->setRoundsSurvived(newRoundsSurvived);
grid[newP][newQ]->setIfMoved(true);
return;
}
else if (grid[getP()-1][getQ()]->getType() == 'o'){
int newP = getP()-1;
int newQ = getQ();
int newID = getID();
int newRoundsSurvived = getRoundsSurvived()+1;
delete grid[getP()][getQ()];
delete grid[newP][newQ];
grid[getP()][getQ()] = NULL;
grid[newP][newQ] = new Doodlebug(newP, newQ, newID);
grid[newP][newQ]->setRoundsSurvived(newRoundsSurvived);
grid[newP][newQ]->setIfMoved(true);
grid[newP][newQ]->setIfAte(true);
return;
}
}
if (direction == 2 && getP()+1 <= 19 && getIfMoved() == false){
if (grid[getP()+1][getQ()] == NULL){
int newP = getP()+1;
int newQ = getQ();
int newID = getID();
int newRoundsSurvived = getRoundsSurvived()+1;
delete grid[getP()][getQ()];
grid[getP()][getQ()] = NULL;
grid[newP][newQ] = new Doodlebug(newP, newQ, newID);
grid[newP][newQ]->setRoundsSurvived(newRoundsSurvived);
grid[newP][newQ]->setIfMoved(true);
return;
}
else if (grid[getP()+1][getQ()]->getType() == 'o'){
int newP = getP()+1;
int newQ = getQ();
int newID = getID();
int newRoundsSurvived = getRoundsSurvived()+1;
delete grid[getP()][getQ()];
delete grid[newP][newQ];
grid[getP()][getQ()] = NULL;
grid[newP][newQ] = new Doodlebug(newP, newQ, newID);
grid[newP][newQ]->setRoundsSurvived(newRoundsSurvived);
grid[newP][newQ]->setIfMoved(true);
grid[newP][newQ]->setIfAte(true);
return;
}
}
if (direction == 3 && getQ()-1 >= 0 && getIfMoved() == false){
if (grid[getP()][getQ()-1] == NULL){
int newP = getP();
int newQ = getQ()-1;
int newID = getID();
int newRoundsSurvived = getRoundsSurvived()+1;
delete grid[getP()][getQ()];
delete grid[newP][newQ];
grid[getP()][getQ()] = NULL;
grid[newP][newQ] = new Doodlebug(newP, newQ, newID);
grid[newP][newQ]->setRoundsSurvived(newRoundsSurvived);
grid[newP][newQ]->setIfMoved(true);
return;
}
else if (grid[getP()][getQ()-1]->getType() == 'o'){
int newP = getP();
int newQ = getQ()-1;
int newID = getID();
int newRoundsSurvived = getRoundsSurvived()+1;
delete grid[getP()][getQ()];
delete grid[newP][newQ];
grid[getP()][getQ()] = NULL;
grid[newP][newQ] = new Doodlebug(newP, newQ, newID);
grid[newP][newQ]->setRoundsSurvived(newRoundsSurvived);
grid[newP][newQ]->setIfMoved(true);
grid[newP][newQ]->setIfAte(true);
return;
}
}
if (direction == 4 && getQ()+1 <= 19 && getIfMoved() == false){
if (grid[getP()][getQ()+1] == NULL){
int newP = getP();
int newQ = getQ()+1;
int newID = getID();
int newRoundsSurvived = getRoundsSurvived()+1;
delete grid[getP()][getQ()];
grid[getP()][getQ()] = NULL;
grid[newP][newQ] = new Doodlebug(newP, newQ, newID);
grid[newP][newQ]->setRoundsSurvived(newRoundsSurvived);
grid[newP][newQ]->setIfMoved(true);
return;
}
else if (grid[getP()][getQ()+1]->getType() == 'o'){
int newP = getP();
int newQ = getQ()+1;
int newID = getID();
int newRoundsSurvived = getRoundsSurvived()+1;
delete grid[getP()][getQ()];
delete grid[newP][newQ];
grid[getP()][getQ()] = NULL;
grid[newP][newQ] = new Doodlebug(newP, newQ, newID);
grid[newP][newQ]->setRoundsSurvived(newRoundsSurvived);
grid[newP][newQ]->setIfMoved(true);
grid[newP][newQ]->setIfAte(true);
return;
}
}
setRoundsSurvived(getRoundsSurvived()+1);
}
void Doodlebug::breed(Organism* grid[20][20], int& doodlebugID){
setRoundsSurvived(0);
if (grid[getP()-1][getQ()] == NULL){
++doodlebugID;
grid[getP()-1][getQ()] = new Doodlebug(getP()-1, getQ(), doodlebugID);
}
else if (grid[getP()+1][getQ()] == NULL){
++doodlebugID;
grid[getP()+1][getQ()] = new Doodlebug(getP()+1, getQ(), doodlebugID);
}
else if (grid[getP()][getQ()-1] == NULL){
++doodlebugID;
grid[getP()][getQ()-1] = new Doodlebug(getP(), getQ()-1, doodlebugID);
}
else if (grid[getP()][getQ()+1] == NULL){
++doodlebugID;
grid[getP()][getQ()+1] = new Doodlebug(getP(), getQ()+1, doodlebugID);
}
}
void Doodlebug::starve(Organism* grid[20][20]){
/*
Implement this after implementing the ant class
//*/
if (getRoundsSurvived() == 3){
if (getIfAte() == false){
delete grid[getP()][getQ()];
grid[getP()][getQ()] = NULL;
}
}
}
class Ant: public Organism{
private:
char type;
public:
Ant(int p, int q, int id): Organism(p, q, id), type('o'){}
virtual ~Ant(){}
char getType()const{ return type; }
void move(Organism* grid[20][20]);
void breed(Organism* grid[20][20], int&);
};
void Ant::move(Organism* grid[20][20]){
int direction = rand() % 4 + 1;
if (direction == 1 && getP()-1 >= 0 && getIfMoved() == false){
if (grid[getP()-1][getQ()] == NULL){
int newP = getP()-1;
int newQ = getQ();
int newID = getID();
int newRoundsSurvived = getRoundsSurvived()+1;
delete grid[getP()][getQ()];
grid[getP()][getQ()] = NULL;
grid[newP][newQ] = new Ant(newP, newQ, newID);
grid[newP][newQ]->setRoundsSurvived(newRoundsSurvived);
grid[newP][newQ]->setIfMoved(true);
return;
}
}
if (direction == 2 && getP()+1 <= 19 && getIfMoved() == false){
if (grid[getP()+1][getQ()] == NULL){
int newP = getP()+1;
int newQ = getQ();
int newID = getID();
int newRoundsSurvived = getRoundsSurvived()+1;
delete grid[getP()][getQ()];
grid[getP()][getQ()] = NULL;
grid[newP][newQ] = new Ant(newP, newQ, newID);
grid[newP][newQ]->setRoundsSurvived(newRoundsSurvived);
grid[newP][newQ]->setIfMoved(true);
return;
}
}
if (direction == 3 && getQ()-1 >= 0 && getIfMoved() == false){
if (grid[getP()][getQ()-1] == NULL){
int newP = getP();
int newQ = getQ()-1;
int newID = getID();
int newRoundsSurvived = getRoundsSurvived()+1;
delete grid[getP()][getQ()];
grid[getP()][getQ()] = NULL;
grid[newP][newQ] = new Ant(newP, newQ, newID);
grid[newP][newQ]->setRoundsSurvived(newRoundsSurvived);
grid[newP][newQ]->setIfMoved(true);
return;
}
}
if (direction == 4 && getQ()+1 <= 19 && getIfMoved() == false){
if (grid[getP()][getQ()+1] == NULL){
int newP = getP();
int newQ = getQ()+1;
int newID = getID();
int newRoundsSurvived = getRoundsSurvived()+1;
delete grid[getP()][getQ()];
grid[getP()][getQ()] = NULL;
grid[newP][newQ] = new Ant(newP, newQ, newID);
grid[newP][newQ]->setRoundsSurvived(newRoundsSurvived);
grid[newP][newQ]->setIfMoved(true);
return;
}
}
setRoundsSurvived(getRoundsSurvived()+1);
}
void Ant::breed(Organism* grid[20][20], int& antID){
setRoundsSurvived(0);
if (grid[getP()-1][getQ()] == NULL){
++antID;
grid[getP()-1][getQ()] = new Ant(getP()-1, getQ(), antID);
}
else if (grid[getP()+1][getQ()] == NULL){
++antID;
grid[getP()+1][getQ()] = new Ant(getP()+1, getQ(), antID);
}
else if (grid[getP()][getQ()-1] == NULL){
++antID;
grid[getP()][getQ()-1] = new Ant(getP(), getQ()-1, antID);
}
else if (grid[getP()][getQ()+1] == NULL){
++antID;
grid[getP()][getQ()+1] = new Ant(getP(), getQ()+1, antID);
}
}
void initialize(Organism* grid[20][20]){
for (int i = 0; i < 20; i++){
for (int j = 0; j < 20; j++){
grid[i][j] = NULL;
}
}
}
void render(Organism* grid[20][20]){
for (int i = 0; i < 20; i++){
for (int j = 0; j < 20; j++){
if (grid[i][j] == NULL){
std::cout << "-" << " ";
}
else if (grid[i][j]->getType() == 'P'){
std::cout << "P" << " ";
}
else if (grid[i][j]->getType() == 'o'){
std::cout << "o" << " ";
}
}
std::cout << std::endl;
}
std::cout << std::endl;
}
int countTheDoodles(Organism* grid[20][20]){
int count = 0;
for (int i = 0; i < 20; i++){
for (int j = 0; j < 20; j++){
if (grid[i][j] != NULL){
if (grid[i][j]->getType() == 'D'){
count++;
}
}
}
}
return count;
}
int countTheAnts(Organism* grid[20][20]){
int count = 0;
for (int i = 0; i < 20; i++){
for (int j = 0; j < 20; j++){
if (grid[i][j] != NULL){
if (grid[i][j]->getType() == 'o'){
count++;
}
}
}
}
return count;
}
int main(){
Organism* grid[20][20];
initialize(grid);
std::srand(time(NULL));
// Create 5 doodlebugs on the heap
int doodlebugCount = 0;
int doodlebugID = 0;
while (doodlebugCount < 5){
// Get a random p and q coordinate for the grid
int randomP = rand() % 20;
int randomQ = rand() % 20;
if (grid[randomP][randomQ] == NULL){
grid[randomP][randomQ] = new Doodlebug(randomP, randomQ, doodlebugID);
doodlebugCount++;
doodlebugID++;
}
}
// Create 100 ants on the heap
int antCount = 0;
int antID = 100;
while (antCount < 100){
int randomP = rand() % 20;
int randomQ = rand() % 20;
if (grid[randomP][randomQ] == NULL){
grid[randomP][randomQ] = new Ant(randomP, randomQ, antID);
antCount++;
antID++;
}
}
std::cout << "Intial Grid" << std::endl;
render(grid);
bool flag = true;
int step = 0;
while (flag){
std::cout << "Press Enter to continue..." << std::endl;
std::cin.ignore();
++step;
std::cout << "******Time Step: " << step << "******" << std::endl;
for (int i = 0; i < 20; i++){
for (int j = 0; j < 20; j++){
if (grid[i][j] != NULL){
if (grid[i][j]->getType() == 'D' && !grid[i][j]->getIfMoved()){
grid[i][j]->move(grid);
}
}
}
}
for (int i = 0; i < 20; i++){
for (int j = 0; j < 20; j++){
if (grid[i][j] != NULL){
if (grid[i][j]->getType() == 'o' && !grid[i][j]->getIfMoved()){
grid[i][j]->move(grid);
}
}
}
}
for (int i = 0; i < 20; i++){
for (int j = 0; j < 20; j++){
if (grid[i][j] != NULL){
if (grid[i][j]->getType() == 'D' || grid[i][j]->getType() == 'o'){
grid[i][j]->setIfMoved(false);
}
}
}
}
for (int i = 0; i < 20; i++){
for (int j = 0; j < 20; j++){
if (grid[i][j] != NULL){
if (grid[i][j]->getType() == 'D'){
grid[i][j]->starve(grid);
}
}
}
}
for (int i = 0; i < 20; i++){
for (int j = 0; j < 20; j++){
if (grid[i][j] != NULL){
if (grid[i][j]->getType() == 'D' && grid[i][j]->getRoundsSurvived() == 8){
grid[i][j]->breed(grid, doodlebugID);
}
}
}
}
for (int i = 0; i < 20; i++){
for (int j = 0; j < 20; j++){
if (grid[i][j] != NULL){
if (grid[i][j]->getType() == 'o' && grid[i][j]->getRoundsSurvived() == 3){
grid[i][j]->breed(grid, antID);
}
}
}
}
render(grid);
if (countTheAnts(grid) == 400 || countTheDoodles(grid) == 400){
flag = false;
}
}
for (int i = 0; i < 20; i++){
for (int j = 0; j < 20; j++){
delete grid[i][j];
grid[i][j] = NULL;
}
}
return 0;
}
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.