//------------------------------------------------------------------------- // // rabbit4.cpp // // Written by: Simon Parsons // Last modified: 4th November 2007 // A revised version of the ecosystem with virtual function definitions and // abstract classes. // 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 //------------------------------------------------------------------------- // // living // // A living thing has a location. class living { protected: // Location and eaten are protected to allow them to be modified by // derived classes. point location; bool eaten; public: // Most of the interface methods for living 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 thingss are not created // already eaten and a virtual method for being eaten. living(){eaten = false;}; virtual void beEaten() = 0; }; int living::getX() const{ return location.getX(); } int living::getY() const{ return location.getY(); } void living::set(int x, int y){ location.set(x, y); } void living::print() const{ location.print(); } // // End of living //------------------------------------------------------------------------- // // plant // // A plant is a kind of thing that doesn't like to beEaten. class plant : public living { public: void beEaten(); }; void plant::beEaten(){ cout << "Pah!" << endl; eaten = true; } // // End of plant //------------------------------------------------------------------------- // // carrot // // A carrot is a kind of plant which responds differently to being eaten. class carrot : public plant { public: void beEaten(); }; void carrot::beEaten(){ cout << "Oh no, not again!" << endl; eaten = true; } // // End of plant //------------------------------------------------------------------------- // // animal // // An animal is a thing that can move, eat, be eaten, and be // hungry. It contains a data member consumed that counts how many // things it has eaten. class animal : public living { protected: int consumed; public: animal(){consumed = 0;}; void move(); void move(direction d); void eat(); bool hungry(); }; // 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 with its own way to beEaten. class rabbit : public animal { public: void beEaten(); }; void rabbit::beEaten(){ cout << "Drat that fox!" << endl; eaten = true; } // // End of rabbit //------------------------------------------------------------------------- // // fox // // A fox is a kind of animal with its own way of moving. // // Note that even though foxes don't get eaten in this model, we need // to have a function definition for beEaten, or else fox is an // abstract class. class fox : public animal { public: void move(); void move(direction d); void beEaten(); }; 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); } void fox::beEaten(){ }; // // 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++; } return match; } // 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()