Project Overview Simulation of survival game. Character Tiger Hunter Rabbit Worl
ID: 3546413 • Letter: P
Question
Project Overview Simulation of survival game. Character Tiger Hunter Rabbit World 20x20 grid cells One critter only can occupy a cell at Critter can't get out of given world. Move At every time step, move randomly Up, down, left, right If the neighboring cell in selected direction is occupied or off the grid stay in the current cell Breed When a rabbit survives for three time steps, then it breed a child at the end of the time step (that is; after moving) Creates a new rabbit in an adjacent cell which is empty No empty cell, no breeding occurs Move If there is a rabbit in adjacent cell A tiger will move to that cell and at the rabbit Assume that tigers do not eat each other Other rules are same as rabbit's Starve If a tiger has not eaten a rabbit within the last three time steps, the tiger will die after moving. Breed If a tiger survives for eight time steps Spawn off a new tiger in the same manner as rabbits Move If there is a rabbit or a Tiger within two distance cell. Up, down, left, right(can't see diagonal direction) A hunter will move to that cell and hunt that critter. Assume that hunters do not hunt each other. Other rules are same as rabbit's. Starve If a hunter has not got a critter within the last three time steps, the hunter will die after moving At the beginning, take the initial number of rabbits, tigers and hunters from user input. Exception handling is not required. Of course, we assume that input never exceed 400. (20x20) Draw 2-dimensional world 'R' for rabbits T for tigers 'H' for hunters '-' for empty cell Use a 2-dimensional array (e.q., world[20][20]) This time, please follow exact output format asked. - see the execution example Print current time at the top of the screen. Print event message at the bottom of the screen how many critters born, starve, hunted at that step. After each time step, prompt the user to press 'Enter' to move to the next time step. Hint: getchar(); system("clear"); Movement priorities: Hunter > tiger > rabbit. ex) Only survived rabbit after tigers' movement can move. Use Classes for each characters(Rabbit, Tiger, Hunter). 3 member variables: indicate x & y coordinates and lifetime each 2 member functions: move(): breed() (except for hunters) For breeding or starving, you must use new, delete keyword. Allocating 400 objects for each critter at the beginning is not allowed. You can create additional classes, member variables, member functions if you need You can use 'rand' function for moving(Lecture slide 05-17p) Use reasonable class feature (private/public, static, const, constructor) Reasonable comments in English(lmportant!) Reasonable lndentation(lmportant!)Explanation / Answer
Go to http://pastebin.com/tVFH4egE for proper indentation. There are 11 files total: main.cpp, World.h, World.cpp, Critter.h, Critter.cpp, Rabbit.h, Rabbit.cpp, Tiger.h, Tiger.cpp, Hunter.h, and Hunter.cpp
kinda long... ~700 lines of code total. That's why I asked for 7500 pts -.-
// main.cpp
#include <iostream>
#include <ctime>
#include "World.h"
int main()
{
srand(time(NULL));
World world(20, 20);
int rabbitCount = 0;
std::cout << "Enter initial number of rabbits: ";
std::cin >> rabbitCount;
world.addRabbits(rabbitCount);
int tigerCount = 0;
std::cout << "Enter initial number of tigers: ";
std::cin >> tigerCount;
world.addTigers(tigerCount);
int hunterCount = 0;
std::cout << "Enter initial number of hunters: ";
std::cin >> hunterCount;
world.addHunters(hunterCount);
while (true)
{
system("clear");
world.display();
std::cout << "Press Enter to proceed";
char c = std::cin.get();
if (c == 'x') break;
world.update();
}
}
// World.h
#ifndef WORLD_H
#define WORLD_H
#include "Critter.h"
class World
{
public:
enum GridStatus { EMPTY='-', CRITTER='X', RABBIT='R', TIGER='T', HUNTER='H' };
public:
World(int r=20, int c=20);
~World();
bool isValid(int x, int y)const;
bool isEmpty(int x, int y)const;
void moveCritter(int x, int y, int nx, int ny);
void addCritter(Critter* c);
bool hasRabbit(int x, int y)const;
void killRabbit(int x, int y);
bool hasTiger(int x, int y)const;
void killTiger(int x, int y);
void addRabbits(int count);
void addTigers(int count);
void addHunters(int count);
void update();
void display()const;
private:
void updateRabbits();
void updateTigers();
void updateHunters();
void updateGrid();
void getEmptyCell(int& x, int& y)const;
private:
int rows, cols;
Critter*** grid;
Critter*** nextGrid; // to record next moves
int timestep;
int rabbitCount, rabbitBorn, rabbitHunted;
int tigerCount, tigerBorn, tigerStarve, tigerHunted;
int hunterCount, hunterBorn, hunterStarve;
};
#endif // WORLD_H
// World.cpp
#include "World.h"
#include <iostream>
#include "Rabbit.h"
#include "Tiger.h"
#include "Hunter.h"
World::World(int r, int c)
: rows(r), cols(c), grid(new Critter**[rows]),
nextGrid(new Critter**[rows]), timestep(0),
rabbitCount(0), rabbitBorn(0), rabbitHunted(0),
tigerCount(0), tigerBorn(0), tigerStarve(0), tigerHunted(0),
hunterCount(0), hunterBorn(0), hunterStarve(0)
{
for (int i = 0; i < rows; ++i)
{
grid[i] = new Critter*[cols];
nextGrid[i] = new Critter*[cols];
for (int j = 0; j < cols; ++j)
grid[i][j] = nextGrid[i][j] = NULL;
}
}
World::~World()
{
for (int i = 0; i < rows; ++i)
{
for (int j = 0; j < cols; ++j)
delete grid[i][j]; //never delete nextGrid[i][j];
delete [] grid[i];
delete [] nextGrid[i];
}
delete [] nextGrid;
delete [] grid;
}
bool World::isValid(int x, int y)const
{
return x >= 0 && x < cols && y >= 0 && y < rows;
}
bool World::isEmpty(int x, int y)const
{
return !grid[y][x] && !nextGrid[y][x];
}
bool World::hasRabbit(int x, int y)const
{
if (!grid[y][x]) return false;
return dynamic_cast<Rabbit*>(grid[y][x]) != NULL;
}
void World::killRabbit(int x, int y)
{
if (grid[y][x] && dynamic_cast<Rabbit*>(grid[y][x]))
{
// if we have copied a rabbit to nextGrid, undo it
if (nextGrid[y][x] == grid[y][x]) nextGrid[y][x] = NULL;
// now delete the real rabbit on grid
delete grid[y][x];
grid[y][x] = NULL;
++rabbitHunted;
--rabbitCount;
}
}
bool World::hasTiger(int x, int y)const
{
if (!grid[y][x]) return false;
return dynamic_cast<Tiger*>(grid[y][x]) != NULL;
}
void World::killTiger(int x, int y)
{
if (grid[y][x] && dynamic_cast<Tiger*>(grid[y][x]))
{
// if we have copied a tiger to nextGrid, undo it
if (nextGrid[y][x] == grid[y][x]) nextGrid[y][x] = NULL;
// now delete the real tiger on grid
delete grid[y][x];
grid[y][x] = NULL;
++tigerHunted;
--tigerCount;
}
}
void World::moveCritter(int x, int y, int nx, int ny)
{
nextGrid[ny][nx] = grid[y][x];
}
void World::addCritter(Critter* c)
{
if (grid[c->posY()][c->posX()]) return; //can't add to occupied cell
grid[c->posY()][c->posX()] = c;
}
void World::display()const
{
std::cout << "Time step: " << timestep << " ";
char dispChr;
for (int i = 0; i < rows; ++i)
{
std::cout.width(2);
std::cout << i << ' ';
for (int j = 0; j < cols; ++j)
{
if (!grid[i][j]) dispChr = EMPTY;
else if (dynamic_cast<Rabbit*>(grid[i][j])) dispChr = RABBIT;
else if (dynamic_cast<Tiger*>(grid[i][j])) dispChr = TIGER;
else if (dynamic_cast<Hunter*>(grid[i][j])) dispChr = HUNTER;
else dispChr = CRITTER;
std::cout << dispChr << ' ';
}
std::cout << ' ';
}
std::cout << ' ';
std::cout << "number of rabbits: ";
std::cout.width(5);
std::cout << rabbitCount << " (born:" << rabbitBorn
<< ", hunted:" << rabbitHunted << ") ";
std::cout << "number of tigers: ";
std::cout.width(5);
std::cout<< tigerCount << " (born:" << tigerBorn
<< ", starve:" << tigerStarve
<< ", hunted:" << tigerHunted << ") ";
std::cout << "number of hunters: ";
std::cout.width(5);
std::cout << hunterCount << " (born:" << hunterBorn
<< ", starve:" << hunterStarve << ") ";
}
void World::getEmptyCell(int& x, int& y)const
{
while (true)
{
x = rand() % cols;
y = rand() % rows;
if (isEmpty(x, y)) break;
}
}
void World::addRabbits(int count)
{
int x, y;
for (int i = 0; i < count; ++i)
{
getEmptyCell(x, y);
addCritter(new Rabbit(*this, x, y));
++rabbitBorn;
++rabbitCount;
}
}
void World::addTigers(int count)
{
int x, y;
for (int i = 0; i < count; ++i)
{
getEmptyCell(x, y);
addCritter(new Tiger(*this, x, y));
++tigerBorn;
++tigerCount;
}
}
void World::addHunters(int count)
{
int x, y;
for (int i = 0; i < count; ++i)
{
getEmptyCell(x, y);
addCritter(new Hunter(*this, x, y));
++hunterBorn;
++hunterCount;
}
}
void World::updateRabbits()
{
// moving
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
{
Rabbit* pRabbit = dynamic_cast<Rabbit*>(grid[i][j]);
if (pRabbit) pRabbit->move();
else if (grid[i][j]) nextGrid[i][j] = grid[i][j];
}
//
updateGrid();
// breeding
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
{
Rabbit* pRabbit = dynamic_cast<Rabbit*>(grid[i][j]);
if (pRabbit && pRabbit->breed()) ++rabbitBorn, ++rabbitCount;
}
}
void World::updateTigers()
{
// moving
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
{
Tiger* pTiger = dynamic_cast<Tiger*>(grid[i][j]);
if (pTiger) pTiger->move();
else if (grid[i][j]) nextGrid[i][j] = grid[i][j];
}
//
updateGrid();
// delete starving tigers
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
{
Tiger* pTiger = dynamic_cast<Tiger*>(grid[i][j]);
if (pTiger && pTiger->starving())
{
delete grid[i][j];
grid[i][j] = NULL;
++tigerStarve;
--tigerCount;
}
}
// breeding
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
{
Tiger* pTiger = dynamic_cast<Tiger*>(grid[i][j]);
if (pTiger && pTiger->breed()) ++tigerBorn, ++tigerCount;
}
}
void World::updateHunters()
{
// moving
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
{
Hunter* pHunter = dynamic_cast<Hunter*>(grid[i][j]);
if (pHunter) pHunter->move();
else if (grid[i][j]) nextGrid[i][j] = grid[i][j];
}
//
updateGrid();
// delete starving hunters
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
{
Hunter* pHunter = dynamic_cast<Hunter*>(grid[i][j]);
if (pHunter && pHunter->starving())
{
delete grid[i][j];
grid[i][j] = NULL;
++hunterStarve;
--hunterCount;
}
}
}
void World::update()
{
// reset counters
rabbitBorn = rabbitHunted = 0;
tigerBorn = tigerStarve = tigerHunted = 0;
hunterBorn = hunterStarve = 0;
updateHunters();
updateTigers();
updateRabbits();
++timestep;
}
void World::updateGrid()
{
for (int i = 0; i < rows; ++i)
{
for (int j = 0; j < cols; ++j)
{
grid[i][j] = nextGrid[i][j];
nextGrid[i][j] = NULL;
}
}
}
// Critter.h
#ifndef CRITTER_H
#define CRITTER_H
#include <cstdlib>
class World;
class Critter
{
public:
enum Direction { TOP, LEFT, BOTTOM, RIGHT,
TOP2, LEFT2, BOTTOM2, RIGHT2 };
public:
Critter(World& w, int x, int y) : x(x), y(y), lifetime(0), w(w) { }
virtual ~Critter() { }
virtual void move();
int posX()const { return x; }
int posY()const { return y; }
protected:
int x, y;
int lifetime;
World& w;
};
#endif // CRITTER_H
// Critter.cpp
#include "Critter.h"
#include "World.h"
void Critter::move()
{
++lifetime;
int nx = x; // new x position
int ny = y; // new y position
int direction = rand() % 4; // get move direction
if (direction == TOP) --ny;
else if (direction == BOTTOM) ++ny;
else if (direction == LEFT) --nx;
else if (direction == RIGHT) ++nx;
if (!w.isValid(nx, ny) || !w.isEmpty(nx, ny))
{
nx = x;
ny = y;
}
w.moveCritter(x, y, nx, ny);
x = nx;
y = ny;
}
// Rabbit.h
#ifndef RABBIT_H
#define RABBIT_H
#include "Critter.h"
class Rabbit : public Critter
{
public:
Rabbit(World& w, int x, int y) : Critter(w, x, y) { }
bool breed();
};
#endif // RABBIT_H
// Rabbit.cpp
#include "Rabbit.h"
#include "World.h"
bool Rabbit::breed()
{
// if lifetime is not a multiple of three, return
if (!lifetime || lifetime % 3) return false;
// get status of 4 adjacent cells
bool adj[4] = {w.isValid(x, y-1) && w.isEmpty(x, y-1), //top
w.isValid(x-1, y) && w.isEmpty(x-1, y), //left
w.isValid(x, y+1) && w.isEmpty(x, y+1), //bottom
w.isValid(x+1, y) && w.isEmpty(x+1, y)};//right
// count empty cells
int emptyCount = 0;
for (int i = 0; i < 4; ++i) if (adj[i]) ++emptyCount;
// if there is no empty cell, return
if (!emptyCount) return false;
int id = rand() % emptyCount + 1; // random 'index' of an empty cell
// decide which cell is it, top, left, bottom, or right?
int c = 0;
while (id) if (adj[c++]) --id;
--c;
// add new born to world
Rabbit* newBorn = NULL;
if (c == TOP) newBorn = new Rabbit(w, x, y-1);
else if (c == LEFT) newBorn = new Rabbit(w, x-1, y);
else if (c == BOTTOM) newBorn = new Rabbit(w, x, y+1);
else if (c == RIGHT) newBorn = new Rabbit(w, x+1, y);
w.addCritter(newBorn);
return true;
}
// Tiger.h
#ifndef TIGER_H
#define TIGER_H
#include "Critter.h"
class Tiger : public Critter
{
public:
Tiger(World& w, int x, int y) : Critter(w, x, y), food(3) { }
void move();
bool breed();
bool starving()const { return !food; }
private:
bool isFood(int x, int y)const;
private:
int food;
};
#endif // TIGER_H
// Tiger.cpp
#include "Tiger.h"
#include "World.h"
bool Tiger::isFood(int x, int y)const
{
return w.isValid(x, y) && w.hasRabbit(x, y);
}
void Tiger::move()
{
// hunt
// get rabbit status of 4 adjacent cells
bool adj[4] = {isFood(x, y-1), //top
isFood(x-1, y), //left
isFood(x, y+1), //bottom
isFood(x+1, y)};//right
// count adj rabbits
int rabbitCount = 0;
for (int i = 0; i < 4; ++i) if (adj[i]) ++rabbitCount;
// if there is no empty cell, move casually
if (!rabbitCount)
{
Critter::move();
--food;
return;
}
++lifetime;
int id = rand() % rabbitCount + 1; // random 'index' of an empty cell
// decide which cell is it, top, left, bottom, or right?
int c = 0;
while (id) if (adj[c++]) --id;
--c;
int nx = x;
int ny = y;
// hunt that rabbit!
if (c == TOP) w.killRabbit(x, --ny);
else if (c == LEFT) w.killRabbit(--nx, y);
else if (c == BOTTOM) w.killRabbit(x, ++ny);
else if (c == RIGHT) w.killRabbit(++nx, y);
food = 3; // replenish food
// now move
w.moveCritter(x, y, nx, ny);
x = nx;
y = ny;
}
bool Tiger::breed()
{
// if lifetime is not a multiple of 8, return
if (!lifetime || lifetime % 8) return false;
// get status of 4 adjacent cells
bool adj[4] = {w.isValid(x, y-1) && w.isEmpty(x, y-1), //top
w.isValid(x-1, y) && w.isEmpty(x-1, y), //left
w.isValid(x, y+1) && w.isEmpty(x, y+1), //bottom
w.isValid(x+1, y) && w.isEmpty(x+1, y)};//right
// count empty cells
int emptyCount = 0;
for (int i = 0; i < 4; ++i) if (adj[i]) ++emptyCount;
// if there is no empty cell, return
if (!emptyCount) return false;
int id = rand() % emptyCount + 1; // random 'index' of an empty cell
// decide which cell is it, top, left, bottom, or right?
int c = 0;
while (id) if (adj[c++]) --id;
--c;
// add new born to world
Tiger* newBorn = NULL;
if (c == TOP) newBorn = new Tiger(w, x, y-1);
else if (c == LEFT) newBorn = new Tiger(w, x-1, y);
else if (c == BOTTOM) newBorn = new Tiger(w, x, y+1);
else if (c == RIGHT) newBorn = new Tiger(w, x+1, y);
w.addCritter(newBorn);
return true;
}
// Hunter.h
#ifndef HUNTER_H
#define HUNTER_H
#include "Critter.h"
class Hunter : public Critter
{
public:
Hunter(World& w, int x, int y) : Critter(w, x, y), food(3) { }
void move();
bool starving()const { return !food; }
private:
bool isFood(int x, int y)const;
private:
int food;
};
#endif // HUNTER_H
// Hunter.cpp
#include "Hunter.h"
#include "World.h"
bool Hunter::isFood(int x, int y)const
{
return w.isValid(x, y) && (w.hasRabbit(x, y) || w.hasTiger(x, y));
}
void Hunter::move()
{
// hunt
// get food status of 8 adjacent cells
bool adj[8] = {isFood(x, y-1), //top
isFood(x-1, y), //left
isFood(x, y+1), //bottom
isFood(x+1, y), //right
isFood(x, y-2), //top2
isFood(x-2, y), //left2
isFood(x, y+2), //bottom2
isFood(x+2, y)};//right2
// count adj 'foods'
int foodCount = 0;
for (int i = 0; i < 8; ++i) if (adj[i]) ++foodCount;
// if there is no food cell, move casually
if (!foodCount)
{
Critter::move();
--food;
return;
}
++lifetime;
int id = rand() % foodCount + 1; // random 'index' of an empty cell
// decide which cell is it, top, left, bottom, or right?
int c = 0;
while (id) if (adj[c++]) --id;
--c;
int nx = x;
int ny = y;
// hunt that 'food'!
if (c == TOP)
{
if (w.hasRabbit(x, --ny)) w.killRabbit(x, ny);
else w.killTiger(x, ny);
}
else if (c == LEFT)
{
if (w.hasRabbit(--nx, y)) w.killRabbit(nx, y);
else w.killTiger(nx, y);
}
else if (c == BOTTOM)
{
if (w.hasRabbit(x, ++ny)) w.killRabbit(x, ny);
else w.killTiger(x, ny);
}
else if (c == RIGHT)
{
if (w.hasRabbit(++nx, y)) w.killRabbit(nx, y);
else w.killTiger(nx, y);
}
else if (c == TOP2)
{
ny -= 2;
if (w.hasRabbit(x, ny)) w.killRabbit(x, ny);
else w.killTiger(x, ny);
}
else if (c == LEFT2)
{
nx -= 2;
if (w.hasRabbit(nx, y)) w.killRabbit(nx, y);
else w.killTiger(nx, y);
}
else if (c == BOTTOM2)
{
ny += 2;
if (w.hasRabbit(x, ny)) w.killRabbit(x, ny);
else w.killTiger(x, ny);
}
else if (c == RIGHT2)
{
nx += 2;
if (w.hasRabbit(nx, y)) w.killRabbit(nx, y);
else w.killTiger(nx, y);
}
food = 3; // replenish food
// now move
w.moveCritter(x, y, nx, ny);
x = nx;
y = ny;
}
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.