//------------------------------------------------------------------------- // // rabbit3.cpp // // Written by: Simon Parsons // Last modified: 4th November 2007 // A third version of the simple ecosystem. The world contains carrots, // a rabbit and a fox. The rabbit moves around randomly until it finds // a carrot and eats it, the fox moves around randomly until it finds // the rabbit and eats it. The fox moves faster than the rabbit. // Include the necessary header files #include #include #include using namespace std; //------------------------------------------------------------------------- // enum direction {north, east, south, west}; const int SIZE = 5; const int CARROTS = 3; //------------------------------------------------------------------------- // // point // // Our old favorite // class point{ private: // The only attributes of the point are x and y coordinates. int x, y; public: // The interface methods get the x and y coordinates of the point, // set the coordinates, and print their values. int getX() const; int getY() const; void set(int x, int y); void print() const; }; int point::getX() const{ return x; } int point::getY() const{ return y; } void point::set(int x, int y){ this->x = x; this->y = y; } void point::print() const{ cout << "(" << x << ", " << y << ")" << endl; } // // End of point //------------------------------------------------------------------------- // // carrot // // A carrot has a location, and reacts when it is eaten. class carrot { private: // Private data members are location, a point, and a bool to record // whether the carrot was eaten. point location; bool eaten; public: // Most of the interface methods for the carrot are just the same as for a // point, and just call the ones for point. int getX() const; int getY() const; void set(int x, int y); void print() const; // We also have a constructor that ensures carrots are not created // already eaten and a method that responds to being eaten. carrot(){eaten = false;}; void beEaten(); }; int carrot::getX() const{ return location.getX(); } int carrot::getY() const{ return location.getY(); } void carrot::set(int x, int y){ location.set(x, y); } void carrot::print() const{ location.print(); } void carrot::beEaten(){ cout << "Oh no, not again!" << endl; eaten = true; } // // End of carrot //------------------------------------------------------------------------- // // animal // // An animal makes random moves. class animal { protected: // The only private data member is a location, a point, and an count // of how many things the animal has eaten. point location; int consumed; public: // Most of the interface methods for the carrot are just the same as for a // point, and just call the ones for point. int getX() const; int getY() const; void set(int x, int y); void print() const; // We also have a constructor that sets "consumed" to 0, a pair // of methods that move the rabbit, a method for eating, and a method // that reports if the rabbit hasn't eaten. animal(){consumed = 0;}; void move(); void move(direction d); void eat(); bool hungry(); }; int animal::getX() const{ return location.getX(); } int animal::getY() const{ return location.getY(); } void animal::set(int x, int y){ location.set(x, y); } void animal::print() const{ location.print(); } // Pick a random direction to move in, and then move one unit in that direction void animal::move(){ direction d; d = static_cast(rand() % 4); move(d); } // When the animal moves, the world "wraps around", so, for example, // if the animal is at the east end of the world and moves east, it // appears at the far west end. // // The overloaded function move provides this abilty. void animal::move(direction d){ int x = location.getX(); int y = location.getY(); // Find a new x and y coordinate if (d == north){ y = (y + 1) % SIZE; } if (d == south){ y = (y - 1); if (y < 0){ y = SIZE; } } if (d == east){ x = (x + 1) % SIZE; } if (d == west) { x = (x - 1) % SIZE; if (x < 0){ x = SIZE; } } // Set the location of the animal to those coordinates location.set(x, y); }; void animal::eat(){ cout << "Yum!" << endl; consumed++; } // A animal is hungry unless it has eaten something bool animal::hungry(){ if (consumed == 0){ return true; } else { return false; } } // // End of animal //------------------------------------------------------------------------- // // rabbit // // A rabbit is a kind of animal // We add eaten and beEaten to the rabbit, to allow it to be eaten by the // fox class rabbit : public animal { private: bool eaten; public: rabbit(){eaten = false;}; void beEaten(); }; void rabbit::beEaten(){ cout << "Drat that fox!" << endl; eaten = true; } // // End of rabbit //------------------------------------------------------------------------- // // fox // // A fox is a kind of animal class fox : public animal { public: void move(); void move(direction d); }; void fox::move(){ direction d; d = static_cast(rand() % 4); move(d); } void fox::move(direction d){ int x = location.getX(); int y = location.getY(); // Find a new x and y coordinate if (d == north){ y = (y + 2) % SIZE; } if (d == south){ y = (y - 2); if (y < 0){ y = SIZE; } } if (d == east){ x = (x + 2) % SIZE; } if (d == west) { x = (x - 2) % SIZE; if (x < 0){ x = SIZE; } } location.set(x, y); } // // End of fox //------------------------------------------------------------------------- // // world // // Class world represents the little ecosystem we are building // class world { private: // The world contains a rabbit and some carrots. rabbit peter; fox mrTodd; carrot carrots[CARROTS]; public: // There are methods to get the positions of the rabbit and the // carrots. There are also methods to determine if a carrot is at a // particular location, to make the rabbit move around, and to print // the position of all objects in the world. void setRabbit(int x, int y); void setFox(int x, int y); void setCarrot(int x, int y, int index); bool isCarrotAt(int x, int y) const; int whichCarrotAt(int x, int y) const; void rabbitRoam(); void print() const; }; // Setting the locations of rabbit, fox, and carrots is easy since // they have methods to do this. void world::setRabbit(int x, int y){ peter.set(x, y); } void world::setFox(int x, int y){ mrTodd.set(x, y); } void world::setCarrot(int x, int y, int index){ carrots[index].set(x, y); } // Identify if there is a carrot at a specific location. Step through // the carrots array checking if x and y coordinates line up. bool world::isCarrotAt(int x, int y) const{ bool match = false; int index = 0; while(!match && index < CARROTS){ if((x == carrots[index].getX()) && (y == carrots[index].getY())){ match = true; } index++; } } // If we there is a carrot at a specific location, which one is it? // Assumes that there is a match, so only call it under those circumstances. // Not very elegant, but it works. int world::whichCarrotAt(int x, int y) const{ for(int i = 0; i< CARROTS; i++){ if((x == carrots[i].getX()) && (y == carrots[i].getY())){ return i; } } } // Make the rabbit roam around, make the rabbit eat if it is able to // (when it is at the same location as a carrot) and if it does, make // the carrot respond. // // At the same time, make the fox roam, and if it is in the same location // as the rabbit, eat the rabbit. // // Roaming stops as soon as either the rabbit or the fox eats. void world::rabbitRoam(){ int index; while(peter.hungry() && mrTodd.hungry()){ peter.move(); peter.print(); mrTodd.move(); cout << "\t"; mrTodd.print(); if (isCarrotAt(peter.getX(), peter.getY())) { peter.eat(); index = whichCarrotAt(peter.getX(), peter.getY()); carrots[index].beEaten(); } if ((peter.getX() == mrTodd.getX()) && (peter.getY() == mrTodd.getY())) { mrTodd.eat(); peter.beEaten(); } } } // Printing the world is printing the location of the objects in the // world. We use their print methods to do this. void world::print() const { cout << "The rabbit is at:" << endl; peter.print(); cout << "The fox is at:" << endl; mrTodd.print(); cout << "The carrots are at: " << endl; for(int i = 0; i < CARROTS; i++) { carrots[i].print(); } } //------------------------------------------------------------------------- // In main() we create a rabbit and some carrots at random locations, // and the rabbit then moves randomly until it finds a carrot. int main( void ) { world earth; int x, y; // First set up the objects in the world. srand(time(NULL)); x = rand() % SIZE; y = rand() % SIZE; earth.setRabbit(x, y); x = rand() % SIZE; y = rand() % SIZE; earth.setFox(x, y); for(int i = 0; i < CARROTS; i++){ x = rand() % SIZE; y = rand() % SIZE; earth.setCarrot(x, y, i); } earth.print(); // Now the rabbit roams randomly, until it finds a carrot and eats it. cout << "Rabbit and Fox roaming..." << endl; earth.rabbitRoam(); return 0; } // end of main()