Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

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;
}