//------------------------------------------------------------------------- // // rabbit.cpp // // Written by: Simon Parsons // Last modified: 4th November 2007 // A first version of a simple ecosystem. The world contains carrots and a // rabbit. The rabbit moves around randomly until it finds a carrot and eats // it. // 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 //------------------------------------------------------------------------- // // rabbit // // A rabbit makes random moves. class rabbit { private: // The only private data member is a location, a point, and an count // of how many carrots the rabbit 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. rabbit(){consumed = 0;}; void move(); void move(direction d); void eat(); bool hungry(); }; int rabbit::getX() const{ return location.getX(); } int rabbit::getY() const{ return location.getY(); } void rabbit::set(int x, int y){ location.set(x, y); } void rabbit::print() const{ location.print(); } // Pick a random direction to move in, and then move one unit in that direction void rabbit::move(){ direction d; d = static_cast(rand() % 4); move(d); } // When the rabbit moves, the world "wraps around", so, for example, // if the rabbit 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 rabbit::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 rabbit to those coordinates location.set(x, y); }; void rabbit::eat(){ cout << "Yum!" << endl; consumed++; } // A rabbit is hungry unless it has eaten a carrot bool rabbit::hungry(){ if (consumed == 0){ return true; } else { return false; } } // // End of rabbit //------------------------------------------------------------------------- // // world // // Class world represents the little ecosystem we are building // class world { private: // The world contains a rabbit and some carrots. rabbit brer; 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 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 and carrots is easy since they have methods // to do this. void world::setRabbit(int x, int y){ brer.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. void world::rabbitRoam(){ int index; while(brer.hungry()){ brer.move(); brer.print(); if (isCarrotAt(brer.getX(), brer.getY())) { brer.eat(); index = whichCarrotAt(brer.getX(), brer.getY()); carrots[index].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: "; brer.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); 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 roaming..." << endl; earth.rabbitRoam(); return 0; } // end of main()