You will use cellular automata to create a simple 2D predator–prey simulation in
ID: 3664664 • Letter: Y
Question
You will use cellular automata to create a simple 2D predator–prey simulation in your program. The prey are ants and the predators are doodlebugs. These critters live in a 20 * 20 grid of cells. Only one critter may occupy a cell at a time. The grid is enclosed, so no critter may move off the grid. Time is simulated in steps. Each critter performs some action every time step. The ants behave according to the following model: Move- For every time step, the ants randomly try to move up, down, left, or right. 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, at the end of the time step (i.e., 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, no breeding occurs. Once an offspring is produced, an ant cannot produce an offspring again until it has survived three more time steps. The doodlebugs behave according to the following model: Move- For every time step, the doodlebug will move to an adjacent cell containing an ant and eat the ant. If there are no ants in adjoining cells, 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, 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 three time steps, at the end of the third time step it will starve and die. The doodlebug should then be removed from the grid of cells. You will prompt the user to enter the number of time steps to run. For each time step do the following in your program. After all moves, breeding, eating, and starving is resolved display the resulting grid. The doodlebugs will move before the ants in each time step. Draw the world using ASCII characters of “O” for an ant and “X” for a doodlebug. When you reach the time step entered by the user ask them to enter another number or to exit the program. Create a class named organism that contains data and functions common to ants and doodlebugs. This class should have a virtual function named move that is defined in the derived classes of Ant and Doodlebug. You must maintain the state of the current grid while creating the next display. You will use a dynamic array to represent the grid. Each array element will be a pointer to Critter. Initialize the world with 5 doodlebugs and 100 ants. You will randomly place them. 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
#ifndef ORGANSIM_H
#define ORGANSIM_H
#pragma once
#include "location.h"
#include <iostream>
namespace DoodleBugGameOrtell
{
class Organism
{
public:
Organism( );
Organism(Location postion, char species);
Organism(const Organism& other);
Organism& operator=(const Organism& other);
void set_location(Location new_location);
virtual Location& get_location( );
virtual char get_species( );
private:
Location m_points;
char m_species;
};
}//DoodleBugGameOrtell
#endif // ORGANSIM_H
#include "stdafx.h"
#include "Organism.h"
namespace DoodleBugGameOrtell
{
Organism::Organism( )
{ }
Organism::Organism( Location points,
char species):
m_points(points),
m_species(species)
{ }
Organism::Organism(const Organism& other)
{
this->m_points = other.m_points;
this->m_species = other.m_species;
}
Organism& Organism::operator=(const Organism& other)
{
this->m_points = other.m_points;
this->m_species = other.m_species;
return *this;
}
char Organism::get_species( )
{
return m_species;
}
Location& Organism::get_location( )
{
return m_points;
}
void Organism::set_location(Location new_location) //validate x and y are >= 0 && <= 20
{
((new_location.get_xpoint( ) - 1) >= 0 && (new_location.get_xpoint( ) + 1) <= 19) ?
m_points.set_xpoint(new_location.get_xpoint( )) : m_points.set_xpoint(m_points.get_xpoint( ));
((new_location.get_ypoint( ) - 1) >= 0 && (new_location.get_ypoint( ) + 1) <= 19) ?
m_points.set_ypoint(new_location.get_ypoint( )) : m_points.set_ypoint(m_points.get_ypoint( ));
}
}//DoodleBugsGameOrtell
#ifndef ANT_H
#define ANT_H
#pragma once
#include "Organism.h"
namespace DoodleBugGameOrtell
{
class Ant : public Organism
{
public:
Ant( );
Ant(Location postion, char species, int steps_till_breed);
char get_species( );
Location& get_location( );
void set_steps_till_breed(const int count);
int get_steps_till_breed( ) const;
private:
int m_steps_till_breed;
};
} // DoodleBugGameOrtell
#endif //ANT_H
#include "stdafx.h"
#include "Ant.h"
#include <cstdlib>
namespace DoodleBugGameOrtell
{
Ant::Ant( )
{ }
Ant::Ant( Location points,
char species,
int steps_till_breed):
Organism(points, species),
m_steps_till_breed(steps_till_breed)
{ }
char Ant::get_species( )
{
return 'A';
}
Location& Ant::get_location( )
{
return Organism::get_location( );
}
void Ant::set_steps_till_breed(const int count)
{
m_steps_till_breed = count;
}
int Ant::get_steps_till_breed( ) const
{
return m_steps_till_breed;
}
}//DoodleBugGameOrtell
#ifndef DOODLEBUG_H
#define DOODLEBUG_H
#pragma once
#include "Organism.h"
namespace DoodleBugGameOrtell
{
class DoodleBug : public Organism
{
public:
DoodleBug( );
DoodleBug(Location postion, char species, int steps_till_breed, int steps_till_death);
char get_species( );
Location& get_location( );
void set_steps_till_breed(const int count);
void set_steps_till_death(const int count);
int get_steps_till_breed( ) const;
int get_steps_till_death( ) const;
private:
int m_steps_till_breed;
int m_steps_till_death;
};
} // DoodleBugGameOrtell
#endif //DOODLEBUG_H
#include "stdafx.h"
#include "Doodlebug.h"
namespace DoodleBugGameOrtell
{
DoodleBug::DoodleBug( )
{ }
DoodleBug::DoodleBug( Location postion,
char species,
int till_breed,
int till_death):
Organism(postion, species),
m_steps_till_breed(till_breed),
m_steps_till_death(till_death)
{ }
char DoodleBug::get_species( )
{
return 'D';
}
Location& DoodleBug::get_location( )
{
return Organism::get_location( );
}
void DoodleBug::set_steps_till_breed(const int count)
{
m_steps_till_breed = count;
}
void DoodleBug::set_steps_till_death(const int count)
{
m_steps_till_death = count;
}
int DoodleBug::get_steps_till_breed( ) const
{
return m_steps_till_breed;
}
int DoodleBug::get_steps_till_death( ) const
{
return m_steps_till_death;
}
}//DoodlebugGameOrtell
#ifndef GAMEBOARD_H
#define GAMEBOARD_H
#pragma once
#include <iostream>
#include "Location.h"
#include "Constants.h"
#include "Ant.h"
#include "DoodleBug.h"
namespace DoodleBugGameOrtell
{
class GameBoard
{
public:
GameBoard( );
Location check_for_empty_cell(Location& current_cell);
Location check_for_ant_cell(Location& current_cell);
Location pick_random_surrounding_cell(Location& current_cell);
char get_contents_of_chosen_cell(Location& chosen_cell);
void remove_organism_from_gameBoard(Location& cell);
void add_ant_to_gameBoard(Ant& ant);
void add_doodleBug_to_gameBoard(DoodleBug& player);
private:
Organism m_gameBoard[ROWS][COLUMNS];
};
}//DoodleBugGameOrtell
#endif //GAMEBOARD_H
#include "stdafx.h"
#include "GameBoard.h"
namespace DoodleBugGameOrtell
{
GameBoard::GameBoard( ) // populates gameBoard with empty organisms
{
for(int i =0; i < ROWS; i++)
for(int j =0; j < COLUMNS; j++)
m_gameBoard[i][j] = Organism(Location(i, j),'*');
}
void GameBoard::remove_organism_from_gameBoard(Location& cell)
{
m_gameBoard[cell.get_xpoint( )][cell.get_ypoint( )] = Organism(cell, '*');
}
void GameBoard::add_ant_to_gameBoard(Ant& ant)
{
m_gameBoard[ant.get_location( ).get_xpoint( )][ant.get_location( ).get_ypoint( )] = ant;
}
void GameBoard::add_doodleBug_to_gameBoard(DoodleBug& doodleBug)
{
m_gameBoard[doodleBug.get_location( ).get_xpoint( )][doodleBug.get_location( ).get_ypoint( )] = doodleBug;
}
Location GameBoard::pick_random_surrounding_cell(Location& current_cell)
{
switch(rand( ) % 4)
{
case 0: //<--- UP
if(current_cell.get_xpoint( ) -1 >= GAMEBOARD_EDGE_BOTTOM_SIDE )
return Location((current_cell.get_xpoint()-1), current_cell.get_ypoint());
case 1: //<--- DOWN
if (current_cell.get_xpoint( ) +1 <= GAMEBOARD_EDGE_HIGH_SIDE)
return Location((current_cell.get_xpoint( )+1), current_cell.get_ypoint( ));
case 2: //<--- LEFT
if (current_cell.get_ypoint( ) -1 >= GAMEBOARD_EDGE_BOTTOM_SIDE)
return Location((current_cell.get_xpoint( )), current_cell.get_ypoint( )-1);
case 3: //<--- RIGHT
if(current_cell.get_xpoint( ) +1 <= GAMEBOARD_EDGE_HIGH_SIDE)
return Location((current_cell.get_xpoint( )), current_cell.get_ypoint( )+1);
}
return current_cell;
}
char GameBoard::get_contents_of_chosen_cell(Location& chosen_cell)
{
return m_gameBoard[chosen_cell.get_xpoint( )][chosen_cell.get_ypoint( )].get_species( );
}
Location GameBoard::check_for_empty_cell(Location& current_cell)
{
if(current_cell.get_xpoint( ) -1 >= GAMEBOARD_EDGE_BOTTOM_SIDE) //<--- Up
if(m_gameBoard[current_cell.get_xpoint( )-1][current_cell.get_ypoint( )].get_species( ) == '*')
return Location((current_cell.get_xpoint( )-1), current_cell.get_ypoint( ));
if(current_cell.get_xpoint( ) +1 <= GAMEBOARD_EDGE_HIGH_SIDE) //<--- Down
if(m_gameBoard[current_cell.get_xpoint( )+1][current_cell.get_ypoint( )].get_species( ) == '*')
return Location((current_cell.get_xpoint( )+1), current_cell.get_ypoint( ));
if(current_cell.get_ypoint( ) -1 >= GAMEBOARD_EDGE_BOTTOM_SIDE) //<--- Left
if(m_gameBoard[current_cell.get_xpoint( )][current_cell.get_ypoint( )-1].get_species( ) == '*')
return Location((current_cell.get_xpoint( )), current_cell.get_ypoint( )-1);
if(current_cell.get_ypoint( ) +1 <= GAMEBOARD_EDGE_HIGH_SIDE) //<--- Right
if(m_gameBoard[current_cell.get_xpoint( )][current_cell.get_ypoint( )+1].get_species( ) == '*')
return Location((current_cell.get_xpoint( )), current_cell.get_ypoint( )+1);
return current_cell; // All are Occupied
}
Location GameBoard::check_for_ant_cell(Location& current_cell)
{
if(current_cell.get_xpoint( ) -1 >= GAMEBOARD_EDGE_BOTTOM_SIDE) //<--- Up
if(m_gameBoard[current_cell.get_xpoint( )-1][current_cell.get_ypoint( )].get_species( ) == 'A')
return Location((current_cell.get_xpoint( )-1), current_cell.get_ypoint( ));
if(current_cell.get_xpoint( ) +1 <= GAMEBOARD_EDGE_HIGH_SIDE) //<--- Down
if(m_gameBoard[current_cell.get_xpoint( )+1][current_cell.get_ypoint( )].get_species( ) == 'A')
return Location((current_cell.get_xpoint( )+1), current_cell.get_ypoint( ));
if(current_cell.get_ypoint( ) -1 >= GAMEBOARD_EDGE_BOTTOM_SIDE) //<--- Left
if(m_gameBoard[current_cell.get_xpoint( )][current_cell.get_ypoint( )-1].get_species( ) == 'A')
return Location((current_cell.get_xpoint( )), current_cell.get_ypoint( )-1);
if(current_cell.get_ypoint( ) +1 <= GAMEBOARD_EDGE_HIGH_SIDE) //<--- Right
if(m_gameBoard[current_cell.get_xpoint( )][current_cell.get_ypoint( )+1].get_species( ) == 'A')
return Location((current_cell.get_xpoint( )), current_cell.get_ypoint( )+1);
return current_cell; // All are Occupied
}
}//DoodleBugGameOrtell
#ifndef GAMEENGINE_H
#define GAMEENGINE_H
#pragma once
#include <vector>
#include "Ant.h"
#include "DoodleBug.h"
#include "GameBoard.h"
#include "Constants.h"
namespace DoodleBugGameOrtell
{
class GameEngine
{
public:
GameEngine( );
Ant& get_ant_from_ants(int index);
DoodleBug& get_doodleBug_from_doodlebugs(int index);
void move_ant(Ant& ant_2_move);
void breed_ant(Ant& ant_2_move);
void move_doodleBug(DoodleBug& doodleBug_2_move);
void eat_ant(Location& location_of_ant_2_eat);
void breed_doodleBug(DoodleBug& doodleBug_2_breed);
void kill_doodlebug(DoodleBug& doodleBug_2_kill);
void populate_gameBoard( );
void draw_gameBoard_2_console( );
int get_number_of_ants( ) const;
int get_number_of_doodleBugs( ) const;
void set_number_of_ants(const int number_of_ants);
void set_number_of_doodleBugs(const int number_of_doodleBugs);
private:
int m_number_of_ants;
int m_number_of_doodleBugs;
GameBoard m_gameBoard;
Ant m_ants[SIZE_OF_ANTS];
DoodleBug m_doodleBugs[SIZE_OF_DOODLEBUGS];
};
}//DoodlebugGameOrtell
#endif //GAMEENGINE_H
#include "stdafx.h"
#include "GameEngine.h"
namespace DoodleBugGameOrtell
{
GameEngine::GameEngine( )
{
m_number_of_ants =0;
m_number_of_doodleBugs =0;
populate_gameBoard( );
}
int GameEngine::get_number_of_ants( ) const
{
return m_number_of_ants;
}
int GameEngine::get_number_of_doodleBugs( ) const
{
return m_number_of_doodleBugs;
}
void GameEngine::set_number_of_ants(const int number_of_ants)
{
m_number_of_ants = number_of_ants;
}
void GameEngine::set_number_of_doodleBugs(const int number_of_doodleBugs)
{
m_number_of_doodleBugs = number_of_doodleBugs;
}
Ant& GameEngine::get_ant_from_ants(int index)
{
return m_ants[index];
}
DoodleBug& GameEngine::get_doodleBug_from_doodlebugs(int index)
{
return m_doodleBugs[index];
}
void GameEngine::populate_gameBoard( )
{
int count =0;
while(m_number_of_ants < 100)
{
int x = rand( ) % 20;
int y = rand( ) % 20;
if (m_gameBoard.get_contents_of_chosen_cell(Location(x, y)) == '*')
{
m_ants[count] = (Ant(Location(x, y), 'A', 0));
m_gameBoard.add_ant_to_gameBoard(Ant(Location(x, y), 'A', 0));
m_number_of_ants++;
count++;
}
}
count =0;
while (m_number_of_doodleBugs < 5)
{
int x = rand( ) % 20;
int y = rand( ) % 20;
if (m_gameBoard.get_contents_of_chosen_cell(Location(x, y)) == '*')
{
m_doodleBugs[count] = (DoodleBug(Location(x, y), 'D', 0, 0));
m_gameBoard.add_doodleBug_to_gameBoard(DoodleBug(Location(x, y), 'D', 0, 0));
m_number_of_doodleBugs++;
count++;
}
}
}
void GameEngine::move_ant(Ant& ant_2_move)
{
Location desired_cell = m_gameBoard.pick_random_surrounding_cell(ant_2_move.get_location( ));
if (m_gameBoard.get_contents_of_chosen_cell(desired_cell) == '*')
{
m_gameBoard.remove_organism_from_gameBoard(ant_2_move.get_location( ));
ant_2_move.set_location(desired_cell);
m_gameBoard.add_ant_to_gameBoard(ant_2_move);
(ant_2_move.get_steps_till_breed( ) == 3) ? breed_ant(ant_2_move) :
ant_2_move.set_steps_till_breed(ant_2_move.get_steps_till_breed( )+1);
}
}
void GameEngine::breed_ant(Ant& ant_2_move)
{
Location spawns_cell = m_gameBoard.check_for_empty_cell(ant_2_move.get_location( ));
if (spawns_cell != ant_2_move.get_location( ))
{
m_ants[m_number_of_ants] = (Ant(spawns_cell, 'A', 0));
m_gameBoard.add_ant_to_gameBoard(Ant(spawns_cell, 'A', 0));
ant_2_move.set_steps_till_breed(0);
m_number_of_ants++;
}
}
void GameEngine::move_doodleBug(DoodleBug& doodleBug_2_move)
{
Location desired_cell = m_gameBoard.check_for_ant_cell(doodleBug_2_move.get_location( ));
if (m_gameBoard.get_contents_of_chosen_cell(desired_cell) == 'A')
{
m_gameBoard.remove_organism_from_gameBoard(desired_cell);
m_gameBoard.remove_organism_from_gameBoard(doodleBug_2_move.get_location());
doodleBug_2_move.set_location(desired_cell);
m_gameBoard.add_doodleBug_to_gameBoard(doodleBug_2_move);
m_number_of_ants--;
doodleBug_2_move.set_steps_till_death(0);
(doodleBug_2_move.get_steps_till_breed( ) == 8) ? breed_doodleBug(doodleBug_2_move) :
doodleBug_2_move.set_steps_till_breed(doodleBug_2_move.get_steps_till_breed( )+1);
}
else
{
desired_cell = m_gameBoard.check_for_empty_cell(doodleBug_2_move.get_location( ));
if (desired_cell != doodleBug_2_move.get_location( ))
{
m_gameBoard.remove_organism_from_gameBoard(doodleBug_2_move.get_location( ));
doodleBug_2_move.set_location(desired_cell);
m_gameBoard.add_doodleBug_to_gameBoard(doodleBug_2_move);
(doodleBug_2_move.get_steps_till_death( ) == 3) ? kill_doodlebug(doodleBug_2_move) :
doodleBug_2_move.set_steps_till_death(doodleBug_2_move.get_steps_till_death( )+1);
(doodleBug_2_move.get_steps_till_breed( ) == 8) ? breed_doodleBug(doodleBug_2_move) :
doodleBug_2_move.set_steps_till_breed(doodleBug_2_move.get_steps_till_breed( )+1);
}
}
}
void GameEngine::breed_doodleBug(DoodleBug& doodleBug_2_breed)
{
Location spawns_cell = m_gameBoard.check_for_empty_cell(doodleBug_2_breed.get_location( ));
if (spawns_cell != doodleBug_2_breed.get_location( ))
{
m_doodleBugs[m_number_of_doodleBugs] = (DoodleBug(spawns_cell, 'D', 0, 0));
m_gameBoard.add_doodleBug_to_gameBoard(DoodleBug(spawns_cell, 'D', 0, 0));
doodleBug_2_breed.set_steps_till_breed(0);
doodleBug_2_breed.set_steps_till_death(0);
m_number_of_doodleBugs++;
}
}
void GameEngine::kill_doodlebug(DoodleBug& doodleBug_2_kill)
{
m_gameBoard.remove_organism_from_gameBoard(doodleBug_2_kill.get_location());
}
void GameEngine::draw_gameBoard_2_console( )
{
for(int i =0; i < 20; i++)
{
for(int j =0; j < 20; j++)
{
std::cout << m_gameBoard.get_contents_of_chosen_cell(Location(i, j)) << " ";
}
std::cout << std::endl;
}
}
}//DoodlebugGameOrtell
#ifndef CONSTANTS_H
#define CONSTANTS_H
namespace DoodleBugGameOrtell
{
const int ROWS = 20;
const int COLUMNS = 20;
const int SIZE_OF_ANTS =400;
const int SIZE_OF_DOODLEBUGS =200;
const int GAMEBOARD_EDGE_HIGH_SIDE = 19;
const int GAMEBOARD_EDGE_BOTTOM_SIDE =0;
}//DoodleBugGameOrtell
#endif //CONSTANTS_H
#include "stdafx.h"
#include <Windows.h>
#include "GameEngine.h"
using namespace DoodleBugGameOrtell;
int _tmain(int argc, _TCHAR* argv[])
{
GameEngine test_engine;
test_engine.draw_gameBoard_2_console( );
int count =0;
while (true)
{
for (int i =0; i < test_engine.get_number_of_ants( ); i++)
{
test_engine.move_ant(test_engine.get_ant_from_ants(i));
}
for (int i =0; i < test_engine.get_number_of_doodleBugs( ); i++)
{
test_engine.move_doodleBug(test_engine.get_doodleBug_from_doodlebugs(i));
std::cout << "DoodleBugs Loop ran " << i << std::endl;
}
std::cout << std::endl;
std::cout << "Outer Loop " << count << std::endl;
std::cout << "Ants: "<< test_engine.get_number_of_ants( ) << " DoodleBugs: "
<< test_engine.get_number_of_doodleBugs( ) << std::endl;
std::cout << std::endl;
test_engine.draw_gameBoard_2_console( );
Sleep(1000);
count++;
}
system("PAUSE");
return 0;
}
/* The goal for this programming project is to create a simple 2D predator–prey
simulation. In this simulation, the prey are ants and the predators are doodlebugs.
These critters live in a 20 * 20 grid of cells. 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 steps. Each critter performs some action every
time step.
The ants behave according to the following model:
? Move . For every time step, the ants randomly try to move up, down, left, or
right. 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, at the end of the time step (i.e., 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,
no breeding occurs. Once an offspring is produced, an ant cannot produce an
offspring again until it has survived three more time steps.
The doodlebugs behave according to the following model:
? Move . For every time step, the doodlebug will move to an adjacent cell containing
an ant and eat the ant. If there are no ants in adjoining cells, 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, 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 three time steps, 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.
Write a program to implement this simulation and draw the world using ASCII
characters of “O” for an ant and “X” for a doodlebug. Create a class named
Organism that encapsulates basic data common to ants and doodlebugs. This
class should have a virtual function named move that is defined in the derived
classes of Ant and Doodlebug . You may need additional data structures to keep
track of which critters have moved.
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 perturba-
tions may lead to the elimination of one or both species.*/
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.