// FILE: ecosystem.cpp // // A simple simulation program to model an island that contains foxes, // geese, and ferns. #include <iostream> // Provides cin, cout #include <iomanip> // Provides setw #include <cstdlib> // Provides EXIT_SUCCESS, size_t #include "bag.h" // Provides a Bag template class #include "organism.h" // Provides Carnivore, Herbivore, Plant classes using namespace std; const size_t MANY_FERNS = 20000; // Number of ferns on the island const double FERN_START_SIZE = 15; // Initial size of each fern, in ounces const double FERN_MAX_SIZE = 30000; // Maximum fern size, in ounces const double FERN_RATE = 2.5; // Growth rate of ferns, in ounces/week const size_t GOOSE_START_POP = 3000; // Initial number of geese on the island const double GOOSE_START_SIZE = 10; // Initial size of a goose, in ounces const double GOOSE_MAX_SIZE = 150; // Maximum goose size, in ounces const double GOOSE_RATE = 2.9; // Growth rate of geese, in ounces/week const double GOOSE_FRACTION = 0.279; // A goose must eat this fraction times its // size during one week, or it will die. const double GOOSE_NIBBLES = 30; // Average number of plants nibbled by // a goose over one week const double GOOSE_FERTILITY = 0.25; // At the end of each week in spring, // some geese have babies. // The total number of new goslings born // each week is the current geese // population times the fertility // rounded down to an integer). const size_t FOX_START_POP = 100; // Initial number of foxes on the island const double FOX_START_SIZE = 10; // Initial size of a fox, in ounces const double FOX_MAX_SIZE = 150; // Maximum fox size, in ounces const double FOX_RATE = 2.9; // Growth rate of foxes, in ounces/week const double FOX_FRACTION = 0.5; // A fox must eat this fraction * its // size during one week, or it will die. const double FOX_FERTILITY = 0.25; // At the end of each week in spring, // some foxes have babies. // The total number of new kits born // each week is the current fox // population times the fertility // (rounded down to an integer). const double MEETING_CHANCE = 0.009; // This fraction is the probability that // a randomly selected fox will meet a // randomly selected goose in one week. const double CATCH_CHANCE = 0.5; // If a fox chases a goose, this is the2 // probability that the goose is caught. void island_week(Bag<Organism*>& foxes, Bag<Organism*>& geese, Bag<Organism*>& ferns, bool spring); // Precondition: ferns.size( ) > 0. Also: Each of the Organisms in the foxes // Bag is actually a Carnivore; in the geese Bag they are herbivores, and in // the ferns Bag they are Plants. // Postcondition: One week on the island has been simulated. During this week, // each goose has nibbled on some ferns (with GOOSE_NIBBLES being the average // number of nibbles), some foxes have chased some geese, some animals may have // died because they didn't get enough to eat. Any animals that died have been // removed from their bag. If it is spring, then some new animals have been // born and added to the bags. void simulate_all(Bag<Organism*>& collection, double max, double rate); // Postcondition: The simulate_week member function has been activated for each // Organism in the Bag. If the Organism is then dead, it's removed from Bag. // Also, if the size of an Organism exceeds max, then its growth rate is // set to zero; otherwise its growth rate is set to rate. double total_mass(Bag<Organism*>& collection); // Postcondition: The return value is the total mass of all the organisms in // the collection. void increase_to_next_week(int& day, int& month, int& year); // Precondition: day, month, and year are a valid date with year > 2000. // Postcondition: The day, month, and year have been moved forward one week. void print_date(int day, int month, int year); // Postcondition: The given date has been printed as a string to cout. int main( ) { Bag<Organism*> foxes(FOX_START_POP); // A bag of pointers to the foxes Bag<Organism*> geese(GOOSE_START_POP); // The foxes chase these geese Bag<Organism*> ferns(MANY_FERNS); // And the geese eat these ferns size_t i; // Loop control variable int day = 1, month = 1, year = 2005; // The current date on the island unsigned int many_weeks; // Number of weeks to simulate // Initialize the bags of foxes, geese, and ferns. // Note that the animals start full grown. for (i = 0; i < FOX_START_POP; i++) foxes.insert(new Carnivore(FOX_MAX_SIZE, 0, FOX_MAX_SIZE*FOX_FRACTION)); for (i = 0; i < GOOSE_START_POP; i++) geese.insert(new Herbivore(GOOSE_MAX_SIZE, 0, GOOSE_MAX_SIZE*GOOSE_FRACTION)); for (i = 0; i < MANY_FERNS; i++) ferns.insert(new Plant(FERN_START_SIZE, FERN_RATE)); // Get number of weeks, and format the output: cout << "How many weeks shall I simulate? "; cin >> many_weeks; cout.setf(ios::fixed); cout << endl; cout << " Week Number Number Plant Mass" << endl; cout << " of Foxes of Geese (ounces)" << endl << endl; // Simulate the weeks: for (i = 1; i <= many_weeks; i++) { island_week(foxes, geese, ferns, (month >= 3) && (month <= 6)); print_date(day, month, year); cout << setw(11) << foxes.size( ); cout << setw(10) << geese.size( ); cout << setw(13) << setprecision(0) << total_mass(ferns); cout << endl; increase_to_next_week(day, month, year); } return EXIT_SUCCESS; } void island_week(Bag<Organism*>& foxes, Bag<Organism*>& geese, Bag<Organism*>& ferns, bool spring) { size_t i; size_t many_iterations; Carnivore* fox_ptr; Herbivore* goose_ptr; Plant* fern_ptr; // Have randomly selected geese nibble on randomly selected plants: many_iterations = (size_t)(GOOSE_NIBBLES * geese.size( )); for (i = 0; i < many_iterations; i++) { goose_ptr = (Herbivore *) geese.grab( ); fern_ptr = (Plant *) ferns.grab( ); goose_ptr->nibble(*fern_ptr); } // Have the foxes chase the geese. The chance of a random fox chasing // a random goose is given by the constant MEETING_CHANCE, so the // total number of chases is given by many_iterations: many_iterations = (size_t)(MEETING_CHANCE * geese.size( ) * foxes.size( )); for (i = 0; i < many_iterations; i++) { fox_ptr = (Carnivore *) foxes.grab( ); goose_ptr = (Herbivore *) geese.grab( ); if (goose_ptr->is_alive( ) && fox_ptr->still_need( ) > 0) fox_ptr->chase(*goose_ptr, CATCH_CHANCE); } // Simulate the week for the various bags of organisms: simulate_all(foxes, FOX_MAX_SIZE, FOX_RATE); simulate_all(geese, GOOSE_MAX_SIZE, GOOSE_RATE); simulate_all(ferns, FERN_MAX_SIZE, FERN_RATE); // Create some new animals, according to the birth FERTILITY constants: if (spring) { many_iterations = int(GOOSE_FERTILITY * geese.size( )); geese.resize(geese.size( ) + many_iterations); for (i = 0; i < many_iterations; i++) geese.insert( new Herbivore (GOOSE_START_SIZE, GOOSE_FERTILITY, GOOSE_START_SIZE*GOOSE_FRACTION) ); many_iterations = int(FOX_FERTILITY * foxes.size( )); foxes.resize(foxes.size( ) + many_iterations); for (i = 0; i < many_iterations; i++) foxes.insert( new Carnivore (FOX_START_SIZE, FOX_FERTILITY, FOX_START_SIZE * FOX_FRACTION) ); } } double total_mass(Bag<Organism*>& collection) { double answer; answer = 0; for (collection.start( ); collection.is_item( ); collection.advance( )) answer += collection.current( )->get_size( ); return answer; } void simulate_all(Bag<Organism*>& collection, double max, double rate) { collection.start( ); while (collection.is_item( )) { collection.current( )->simulate_week( ); if (collection.current( )->is_alive( )) { if (collection.current( )->get_size( ) >= max) collection.current( )->assign_rate(0); else collection.current( )->assign_rate(rate); collection.advance( ); } else { delete collection.current( ); collection.remove_current( ); } } } void increase_to_next_week(int& day, int& month, int& year) { int limit; switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: limit = 31; break; case 2: if ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0))) limit = 29; // Leap year else limit = 28; // Not a leap year break; case 4: case 6: case 9: case 11: limit = 30; break; } day += 7; if (day > limit) { day -= limit; month++; } if (month > 12) { month = 1; year++; } } void print_date(int day, int month, int year) { switch (month) { case 1: cout << "Jan "; break; case 2: cout << "Feb "; break; case 3: cout << "Mar "; break; case 4: cout << "Apr "; break; case 5: cout << "May "; break; case 6: cout << "Jun "; break; case 7: cout << "Jul "; break; case 8: cout << "Aug "; break; case 9: cout << "Sep "; break; case 10: cout << "Oct "; break; case 11: cout << "Nov "; break; case 12: cout << "Dec "; break; } cout << setw(2) << day << ", " << year; }