commit 1785e4285af1a0fbc6970ab68494be2b423d59a6 Author: Love Billenius Date: Mon Sep 16 13:18:17 2024 +0200 init diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..cfa84e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +*~ + +.DS_Store + +*.pro.user.* +*.pro.user + +build-*/ +*.app +*.exe + +build diff --git a/Event.cpp b/Event.cpp new file mode 100755 index 0000000..bd6d6a6 --- /dev/null +++ b/Event.cpp @@ -0,0 +1,136 @@ +#include "Event.h" +#include "Simulation.h" +#include +#include + +void hatchEvent::processEvent (Simulation& sim) { + double total = sim.getJuvenilePopulation() + sim.getAdultPopulation(); + double saturation = min(total/STARVE_THRESHOLD, 1.0); + unsigned ageAverage = MAX_AGE * (1 - saturation); + uniform_int_distribution ageDist(0.1 * ageAverage, 1.9 * ageAverage); + unsigned ageExpectancy = ageDist(generator); + + Fish* afish = new Fish(eventTime, ageExpectancy); + sim.decEggPopulation(); + sim.incJuvenilePopulation(); + sim.addFish(afish); + + uniform_int_distribution juvDist(0.8* AVG_MATURATION_TM, 1.2* AVG_MATURATION_TM); + unsigned juvenileFor = juvDist(generator); + + if( ageExpectancy < juvenileFor){ + sim.scheduleEvent(new deathEvent(eventTime + ageExpectancy, afish)); + }else{ + sim.scheduleEvent(new matureEvent(eventTime + juvenileFor, afish, generator)); + } +} + + +void spawnEvent::processEvent (Simulation& sim) { + if(afish->isCaught()){ + delete afish; + afish = nullptr; + return; + } + double concentration = min(sim.getAdultPopulation() / (double)SPAWN_THRESHOLD, 1.0); + unsigned avg_max_egg_num = + (concentration < MIN_SPAWN_CONC ? 0 : concentration * MAX_AVG_EGGS_NUM); + uniform_int_distribution eggDist(0.8 * avg_max_egg_num, 1.2 * avg_max_egg_num); + unsigned eggs_num = eggDist(generator); + + sim.incEggPopulation(eggs_num); + + uniform_int_distribution hatchDist(0.6 * HATCH_TM, 1.4 * HATCH_TM); + for(unsigned e=0; e < eggs_num; e++){ + unsigned hatchIn = hatchDist(generator); + sim.scheduleEvent(new hatchEvent(eventTime + hatchIn, generator)); + } + unsigned nextSeasonIn = round((eventTime + 365)/(double)365)*365 - eventTime; + uniform_int_distribution spawnDist(nextSeasonIn - 30, nextSeasonIn + 30); + unsigned spawningIn = spawnDist(generator); + + if(afish->getRemainingLifeExpectancy(eventTime) < spawningIn){ + sim.scheduleEvent(new deathEvent(eventTime + afish->getRemainingLifeExpectancy(eventTime), afish)); + }else{ + sim.scheduleEvent(new spawnEvent(eventTime + spawningIn, afish, generator)); + } +} + +void spawnEvent::withdrawEvent () { + if(afish->isCaught()){ + delete afish; + afish = nullptr; + } +} + + +void matureEvent::processEvent (Simulation& sim) { + if(afish->isCaught()){ + delete afish; + afish = nullptr; + return; + } + afish->makeAdult(eventTime); + sim.decJuvenilePopulation(); + sim.incAdultPopulation(); + + unsigned nextSeasonIn = round((eventTime + 365)/(double)365)*365 - eventTime; + uniform_int_distribution spawnDist(nextSeasonIn - 30, nextSeasonIn + 30); + unsigned spawningIn = spawnDist(generator); + + if(afish->getRemainingLifeExpectancy(eventTime) < spawningIn) + sim.scheduleEvent(new deathEvent(eventTime + afish->getRemainingLifeExpectancy(eventTime), afish)); + else + sim.scheduleEvent(new spawnEvent(eventTime + spawningIn, afish, generator)); +} + +void matureEvent::withdrawEvent () { + if(afish->isCaught()){ + delete afish; + afish= nullptr; + } +} + +void deathEvent::processEvent (Simulation& sim){ + if(afish->isCaught()){ + delete afish; + afish = nullptr; + return; + } + if(afish->isJuvenile()){ + sim.decJuvenilePopulation(); + } else if(afish->isAdult()) { + sim.decAdultPopulation(); + } + afish->makeDead(); +} + +void deathEvent::withdrawEvent (){ + if(afish->isCaught()){ + delete afish; + afish=nullptr; + } +} + +void harvestEvent::processEvent (Simulation& sim) { + sim.harvestTonnageNow(LANDING,generator); + sim.scheduleEvent(new harvestEvent(eventTime + HARVEST_PERIOD, generator)); +} + +void printEvent::processEvent (Simulation& sim) { + file << eventTime + << '\t' << sim.getEggPopulation() + << '\t' << sim.getJuvenilePopulation() + << '\t' << sim.getAdultPopulation() + << '\t' << sim.getJuvenilePopulation() + sim.getAdultPopulation() + << endl; + + cout << eventTime + << '\t' << sim.getEggPopulation() + << '\t' << sim.getJuvenilePopulation() + << '\t' << sim.getAdultPopulation() + << '\t' << sim.getJuvenilePopulation() + sim.getAdultPopulation() + << endl; + + sim.scheduleEvent(new printEvent(eventTime + PRINT_PERIOD, file)); +} diff --git a/Event.h b/Event.h new file mode 100755 index 0000000..f13c1b3 --- /dev/null +++ b/Event.h @@ -0,0 +1,80 @@ +#ifndef EVENT_H +#define EVENT_H + +#include "Fish.h" +#include "config.h" +#include +#include + +using namespace std; + +class Simulation; + +class Event { +public: + Event (unsigned t) : eventTime(t){ } + virtual ~Event(){} + virtual void processEvent (Simulation&) = 0; + virtual void withdrawEvent() = 0; + const unsigned eventTime; +}; + +struct EventComparator { + bool operator() (const Event * left, const Event * right) const { + return left->eventTime > right->eventTime; + } +}; + + +class hatchEvent : public Event { + mt19937& generator; +public: + hatchEvent (unsigned t, mt19937& gen) : Event(t), generator(gen) {} + virtual void processEvent (Simulation& sim); + virtual void withdrawEvent(){} +}; + +class spawnEvent : public Event { + Fish* afish; + mt19937& generator; +public: + spawnEvent (unsigned t, Fish* _afish, mt19937& gen) : Event(t), afish(_afish), generator(gen){} + virtual void processEvent (Simulation& sim); + virtual void withdrawEvent(); +}; + +class matureEvent : public Event { + Fish* afish; + mt19937& generator; +public: + matureEvent (unsigned t, Fish* _afish, mt19937& gen) : Event(t), afish(_afish),generator(gen){} + virtual void processEvent (Simulation& sim); + virtual void withdrawEvent(); +}; + + +class deathEvent : public Event { + Fish* afish; +public: + deathEvent (unsigned t, Fish* _afish) : Event(t), afish(_afish) {} + virtual void processEvent (Simulation& sim); + virtual void withdrawEvent(); +}; + +class harvestEvent : public Event { + mt19937& generator; +public: + harvestEvent (unsigned t, mt19937& gen): Event(t), generator(gen) {} + virtual void processEvent (Simulation& sim); + virtual void withdrawEvent() {} +}; + +class printEvent : public Event { + ofstream& file; +public: + printEvent (unsigned t, ofstream& f) : Event(t), file(f){} + virtual void processEvent (Simulation& sim); + virtual void withdrawEvent() {} +}; + +#endif // EVENT_H diff --git a/Fish.cpp b/Fish.cpp new file mode 100755 index 0000000..de268cf --- /dev/null +++ b/Fish.cpp @@ -0,0 +1,92 @@ +#include "Fish.h" +#include +#include + +unsigned Fish::counter= 0; + +Fish::Fish(unsigned time, unsigned _lifeExpectancy): + hatchedTime(time),lifeExpectancy(_lifeExpectancy), id(++counter){ +} + +void Fish::makeAdult(unsigned t){ + assert(phase==JuvenilePhase && " making a non juvenile fish adult"); + adultTime = t; + phase = AdultPhase; +} + +void Fish::makeDead(){ + bool aliveFree = isJuvenile() || isAdult(); + assert(aliveFree && " killing a dead or caught fish"); + phase = DeadPhase; +} + +void Fish::makeCaught(){ + bool aliveFree = isJuvenile() || isAdult(); + assert(aliveFree && " catching a dead or caught fish"); + phase = CaughtPhase; +} + + +bool Fish::isJuvenile()const{ + return phase == JuvenilePhase; +} + +bool Fish::isAdult()const{ + return phase == AdultPhase; +} + +bool Fish::isCaught()const{ + return phase == CaughtPhase; +} + +bool Fish::isDead()const{ + return phase == DeadPhase; +} + +unsigned Fish::getRemainingLifeExpectancy(unsigned now)const{ + if (now > (lifeExpectancy + hatchedTime)) + return 0; + return lifeExpectancy + hatchedTime - now; +} + +bool Fish::catchableNow(unsigned now)const{ + return (now - hatchedTime) > MIN_CATCHABLE_AGE; +} + + +unsigned Fish::getWeightOnCatch(unsigned tm)const{ + unsigned age = tm - hatchedTime; + return(age < MIN_KEPT_AGE? 0 : age); +} + +std::string Fish::print()const{ + std::stringstream rslt; + rslt << "fish"; + switch(phase){ + case JuvenilePhase: + rslt << "j("; + break; + case AdultPhase: + rslt << "a("; + break; + case DeadPhase: + rslt << "d("; + break; + case CaughtPhase: + rslt << "c("; + break; + default: + rslt << "x("; + break; + } + rslt << id << ")(le=" << lifeExpectancy; + rslt << ", ht=" << hatchedTime; + rslt << ", at=" << adultTime << ")" ; + return rslt.str(); +} + + +std::ostream& operator<<(std::ostream& out, const Fish& fish){ + out << fish.print(); + return out; +} diff --git a/Fish.h b/Fish.h new file mode 100755 index 0000000..898cccd --- /dev/null +++ b/Fish.h @@ -0,0 +1,45 @@ +#ifndef FISH_H +#define FISH_H + +#include "config.h" +#include + +class Fish { + +public: + enum Phase {JuvenilePhase, AdultPhase, DeadPhase, CaughtPhase}; + Phase phase=JuvenilePhase; + + unsigned hatchedTime=0; + unsigned adultTime=0; + unsigned lifeExpectancy=0; + unsigned id = 0; + static unsigned counter; + + + +public: + Fish(unsigned time, unsigned _lifeExpectancy); + + void makeAdult(unsigned); + void makeDead(); + void makeCaught(); + + + bool isJuvenile() const; + bool isAdult()const; + bool isCaught()const; + bool isDead()const; + + + + std::string print()const; + + bool catchableNow(unsigned)const; + unsigned getWeightOnCatch(unsigned tm)const; + unsigned getRemainingLifeExpectancy(unsigned tm)const; +}; + +std::ostream& operator<<(std::ostream& out, const Fish& fish); + +#endif // FISH_H diff --git a/MyException.h b/MyException.h new file mode 100755 index 0000000..37de199 --- /dev/null +++ b/MyException.h @@ -0,0 +1,16 @@ +#ifndef MYEXCEPTION_H +#define MYEXCEPTION_H + +#include + +#define MYEXCEPTION(msg) MyException(msg, __FILE__, __LINE__) + +inline void MyException(const std::string& msg, + char* file, + unsigned line){ + std::stringstream ss; + ss << msg << " at " << file << ":" << line; + throw std::runtime_error(ss.str()); +} + +#endif // MYEXCEPTION_H diff --git a/MyPriorityQueue.h b/MyPriorityQueue.h new file mode 100755 index 0000000..3ba61b6 --- /dev/null +++ b/MyPriorityQueue.h @@ -0,0 +1,81 @@ +// This is the second .h file you will edit +// We have provided a skeleton for you, +// but you must finish it as described in the spec. +// Also remove these comments here and add your own, as well as on the members. +// TODO: remove this comment header + +#ifndef MY_PRIORITY_QUEUE_H +#define MY_PRIORITY_QUEUE_H + +#include "MyVector.h" +#include "MyException.h" + + +template +class MyPriorityQueue +{ + MyVector vector_array; + C strictly_larger_operator; + +public: + MyPriorityQueue(); + + ~MyPriorityQueue(); + + void push(const T& t); + + T top()const; + + void pop(); + + bool empty()const; + + unsigned size() const; + +private: + // Other private members? +}; + +template +MyPriorityQueue::MyPriorityQueue(){ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +MyPriorityQueue::~MyPriorityQueue(){ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +void MyPriorityQueue::push(const T& t){ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +T MyPriorityQueue::top()const{ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +void MyPriorityQueue::pop(){ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +bool MyPriorityQueue::empty()const{ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +unsigned MyPriorityQueue::size()const{ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +#endif // MY_PRIORITY_QUEUE_H diff --git a/MyVector.h b/MyVector.h new file mode 100755 index 0000000..1044faf --- /dev/null +++ b/MyVector.h @@ -0,0 +1,128 @@ +// This is the first .h file you will edit +// We have provided a skeleton for you, +// but you must finish it as described in the spec. +// Also remove these comments here and add your own, as well as on the members. +// TODO: remove this comment header + +#ifndef MY_VECTOR_H +#define MY_VECTOR_H + +#include "MyException.h" + +template +class MyVector +{ + +public: + MyVector(); + + ~MyVector(); + + MyVector(const MyVector& other); + + MyVector& operator =(const MyVector& other); + + + void push_back(const T&); + + void pop_back(); + + T& operator[](unsigned i); + + const T& operator[](unsigned i)const; + + bool empty()const; + + T* begin(); + + T* end(); + + void clear(); + + unsigned size()const; + +private: + + // private members? + +}; + +template +MyVector::MyVector(){ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +MyVector::~MyVector(){ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +MyVector::MyVector(const MyVector& other){ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +MyVector& MyVector::operator =(const MyVector& other){ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +void MyVector::push_back(const T& e){ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +void MyVector::pop_back(){ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +T& MyVector::operator[](unsigned i){ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +const T& MyVector::operator[](unsigned i)const{ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +bool MyVector::empty()const{ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +void MyVector::clear(){ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +unsigned MyVector::size()const{ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +T* MyVector::begin(){ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +template +T* MyVector::end(){ + // TODO: replace the code below with your code for this member + MYEXCEPTION("unimplemented method"); +} + +#endif // MY_VECTOR_H diff --git a/README.md b/README.md new file mode 100755 index 0000000..d276bdc --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +See: labb 6 @ https://www.ida.liu.se/~TDDD86/info/labs.sv.shtml + diff --git a/Simulation.cpp b/Simulation.cpp new file mode 100755 index 0000000..9754751 --- /dev/null +++ b/Simulation.cpp @@ -0,0 +1,120 @@ +#include "Simulation.h" +#include +#include + +#include + + +Simulation::Simulation(): + simulationTime(0),eggPopulation(0), + juvenilePopulation(0),adultPopulation(0){ +} + + +Simulation::~Simulation(){ + assert(eventQueue.empty()); + for(unsigned i=0; i < allTheFish.size(); ++i){ + assert(! allTheFish[i]->isCaught()); + delete allTheFish[i]; + } +} + + + +void Simulation::run (){ + while (! eventQueue.empty ()){ + Event * nextEvent = eventQueue.top (); + eventQueue.pop (); + if(simulationTime < SIMULATION_HORIZON){ + simulationTime = nextEvent->eventTime; + nextEvent->processEvent(*this); + }else{ + nextEvent->withdrawEvent(); + } + delete nextEvent; + } +} + + +void Simulation::scheduleEvent (Event * newEvent){ + eventQueue.push(newEvent); +} + + +void Simulation::harvestTonnageNow(unsigned target, mt19937& generator){ +// MyVector stillAlive; + std::vector stillAlive; + for(unsigned i=0; i < allTheFish.size(); ++i){ + assert(! allTheFish[i]->isCaught()); + if (allTheFish[i]->isDead()){ + delete allTheFish[i]; + } else{ + stillAlive.push_back(allTheFish[i]); + } + } + allTheFish.clear(); + shuffle(stillAlive.begin(),stillAlive.end(),generator); + unsigned landing =0; + unsigned fish=0; + for(; fish < stillAlive.size() && landing < target; ++fish){ + if(stillAlive[fish]->catchableNow(simulationTime)){ + //fish is large enough to be caught + landing += stillAlive[fish]->getWeightOnCatch(simulationTime); + if(stillAlive[fish]->isJuvenile()){ + juvenilePopulation--; + }else if(stillAlive[fish]->isAdult()){ + adultPopulation--; + }else{ + assert(false && "should not get here"); + } + stillAlive[fish]->makeCaught(); + }else{ + allTheFish.push_back(stillAlive[fish]); + } + } + for(; fish < stillAlive.size(); ++fish){ + allTheFish.push_back(stillAlive[fish]); + } +} + +void Simulation::addFish(Fish* afish){ + allTheFish.push_back(afish); +} + +unsigned Simulation::getEggPopulation()const{ + return eggPopulation; +} + +void Simulation::incEggPopulation(unsigned c){ + eggPopulation+=c; +} + +void Simulation::decEggPopulation(unsigned c){ + eggPopulation-=c; +} + +unsigned Simulation::getJuvenilePopulation()const{ + return juvenilePopulation; +} + +void Simulation::incJuvenilePopulation(unsigned c){ + juvenilePopulation+=c; +} + +void Simulation::decJuvenilePopulation(unsigned c){ + juvenilePopulation-=c; +} + +unsigned Simulation::getAdultPopulation()const{ + return adultPopulation; +} + +void Simulation::incAdultPopulation(unsigned c){ + adultPopulation+=c; +} + +void Simulation::decAdultPopulation(unsigned c){ + adultPopulation-=c; +} + + diff --git a/Simulation.h b/Simulation.h new file mode 100755 index 0000000..7e0a414 --- /dev/null +++ b/Simulation.h @@ -0,0 +1,63 @@ +#ifndef SIMULATION_H +#define SIMULATION_H + +#include "config.h" +#include "Event.h" +#include "MyPriorityQueue.h" +#include "MyVector.h" +#include +#include +#include + +class Fish; + +class Simulation { + +public: + Simulation(); + + ~Simulation(); + + void run (); + + void scheduleEvent (Event*); + + void harvestTonnageNow(unsigned, mt19937&); + + void addFish(Fish*); + + unsigned getEggPopulation()const; + void incEggPopulation(unsigned c=1); + void decEggPopulation(unsigned c=1); + + unsigned getJuvenilePopulation()const; + void incJuvenilePopulation(unsigned c=1); + void decJuvenilePopulation(unsigned c=1); + + unsigned getAdultPopulation()const; + void incAdultPopulation(unsigned c=1); + void decAdultPopulation(unsigned c=1); + + +private: +// MyPriorityQueue eventQueue; + + std::priority_queue >, + EventComparator> eventQueue; + +// MyVector allTheFish; + std::vector allTheFish; + + + unsigned simulationTime; + + unsigned eggPopulation; + unsigned juvenilePopulation; + unsigned adultPopulation; + + + +}; + +#endif // SIMULATION_H diff --git a/answers.txt b/answers.txt new file mode 100755 index 0000000..e69de29 diff --git a/config.h b/config.h new file mode 100755 index 0000000..a900fff --- /dev/null +++ b/config.h @@ -0,0 +1,29 @@ +#ifndef CONFIG_H +#define CONFIG_H + +//life expectancy +const unsigned MAX_AGE = 2000; +const unsigned STARVE_THRESHOLD=20000; + +const unsigned HATCH_TM = 40; +const unsigned AVG_MATURATION_TM = 500; + +// spawning +const unsigned MAX_AVG_EGGS_NUM = 100; +const double MIN_SPAWN_CONC = 0.05; +const unsigned SPAWN_THRESHOLD= 0.05 * STARVE_THRESHOLD; + + +// Harvesting +const unsigned HARVEST_START= 1000; +const unsigned HARVEST_PERIOD= 366; +const unsigned MIN_CATCHABLE_AGE = 550; +const unsigned MIN_KEPT_AGE = 600; +const unsigned LANDING = 70000; + +// Simulation: duration and printing +const unsigned SIMULATION_HORIZON=8000; +const unsigned PRINT_PERIOD=20; + + +#endif // CONFIG_H diff --git a/fisher.pro b/fisher.pro new file mode 100755 index 0000000..44e9c5d --- /dev/null +++ b/fisher.pro @@ -0,0 +1,8 @@ +TEMPLATE = app +CONFIG += console c++11 +CONFIG -= app_bundle +CONFIG -= qt + +SOURCES = Event.cpp Fish.cpp main.cpp Simulation.cpp + +HEADERS = $$files(*.h,true) diff --git a/main.cpp b/main.cpp new file mode 100755 index 0000000..6d5e98b --- /dev/null +++ b/main.cpp @@ -0,0 +1,77 @@ + +#include "Event.h" +#include "Fish.h" +#include "Simulation.h" + +#include +#include +#include +#include +#include + + +using namespace std; + + +void show(); + +int main() +{ + ofstream file("output.dat"); + + random_device rd; + mt19937 generator(rd()); + + + Simulation sim; + sim.scheduleEvent(new printEvent (0,file)); + for(unsigned i=0; i < 100; ++i){ + Event* e = new hatchEvent(0,generator); + sim.scheduleEvent(e); + } + sim.incEggPopulation(100); + sim.scheduleEvent(new harvestEvent(HARVEST_START,generator)); + auto comp_start_time = chrono::high_resolution_clock::now(); + sim.run(); + auto comp_end_time = chrono::high_resolution_clock::now(); + std::cout << "simulation took: " + << chrono::duration_cast(comp_end_time - comp_start_time).count() + << " seconds." + << std::endl; + file.close(); + + show(); + + return 0; +} + +void show(){ + ofstream driver; + driver.open("output.driver", ofstream::out); + driver << "set terminal wxt size 410,250 enhanced font 'Verdana,9' persist\n" + << "set style line 11 lc rgb '#808080' lt 1\n" + << "set border 3 back ls 11\n" + << "set tics nomirror \n" + << "set style line 12 lc rgb '#808080' lt 0 lw 1\n" + << "set grid back ls 12\n" + << "set style line 1 lc rgb '#000000' pt 0 ps 1 lt 1 lw 1 # --- red\n" + << "set style line 2 lc rgb '#5e9c36' pt 0 ps 1 lt 1 lw 1 # --- green\n" + << "set style line 3 lc rgb '#0000ff' pt 0 ps 1 lt 1 lw 1 # --- blue\n" + << "set style line 4 lc rgb '#99004c' pt 0 ps 1 lt 1 lw 1 # --- purple\n" + << "set key top left\n" + << "set xlabel 'time in days'\n" + << "set ylabel 'population'\n" + << "set xrange [0:" << SIMULATION_HORIZON <<"]\n" + << "set yrange [0:" << int(STARVE_THRESHOLD * 1.3) << "]\n" + << "plot 'output.dat' u 1:3 t 'juvenile' w lp ls 2, \\\n" + << " 'output.dat' u 1:4 t 'adult' w lp ls 3"; + driver.close(); + +#ifdef WIN32 + const string exe = "C:\\Progra~1\\gnuplot\\bin\\gnuplot.exe"; +#else + const string exe = "gnuplot"; +#endif + const string cmd = exe + " " + "output.driver"; + system(cmd.c_str()); +} diff --git a/test-harness-myprio.cpp b/test-harness-myprio.cpp new file mode 100755 index 0000000..3679ea4 --- /dev/null +++ b/test-harness-myprio.cpp @@ -0,0 +1,322 @@ +/************************************************* + * File: test-harness-myprio.cpp + * + * File containing several test cases that can be + * used to verify the correctness of the MyPriorityQueue + * implementation. You should make sure to do your + * own testing in addition to ensuring that the test + * cases here pass. + */ +#include +#include +#include +#include +#include +#include +#include +#include "MyPriorityQueue.h" +using namespace std; + +/* These flags control which tests will be run. Initially, only the + * basic test will be executed. As you complete more and more parts + * of the implementation, you will want to turn more and more of these + * flags on. + */ +#define BasicMyPriorityQueueTestEnabled 1 +#define ModerateMyPriorityQueueTestEnabled 1 + +#define BasicCopyTestEnabled 0 +#define ModerateCopyTestEnabled 0 + + +/* Utility function that pauses until the user hits ENTER. */ +void pressEnterToContinue() { + /* Use getline to stall until receiving input. */ + string line; + getline(cin, line); +} + +/* This function is what the test suite uses to ensure that the MyPriorityQueue works + * correctly. It takes as parameters an expression and description, along + * with a file and line number, then checks whether the condition is true. + * If so, it prints that the test passed. Otherwise, it reports that the + * test fails and points the caller to the proper file and line. + */ +void doCheckCondition(bool expr, const string& rationale, const string& file, int line) { + /* It worked! Congrats. */ + if (expr) { + cout << "PASS: " << rationale << endl; + return; + } + + /* Uh oh! The test failed! */ + cout << "FAIL: " << rationale << endl; + cout << " Error at " << file << ", line " << line << endl; + cout << " (ENTER to continue)" << endl; + + /* Pause so that the test fail stands out. */ + pressEnterToContinue(); +} + +/* Reports that an unexpected error occurred that caused a test to fail. */ +void failTest(const exception& e) { + cerr << "TEST FAILED: Unexpected exception: " << e.what() << endl; + pressEnterToContinue(); +} + +/* This macro takes in an expression and a string, then invokes + * doCheckCondition passing in the arguments along with the file + * and line number on which the macro was called. This makes it + * easier to track down the source of bugs if a test case should + * fail. + */ +#define checkCondition(expr, rationale) doCheckCondition(expr, rationale, __FILE__, __LINE__) + +/* Utility function to delimit the start and end of test cases. */ +void printBanner(const string& header) { + cout << "\nBeginning test: " << header << endl; + cout << setw(40) << setfill('-') << "" << setfill(' ') << endl; +} + +/* Utility function to signal that a test isn't begin run. */ +void testDisabled(const string& header) { + cout << "== Test " << header << " NOT RUN: press ENTER to continue ==" << endl; + + /* Pause for the user to hit enter. */ + pressEnterToContinue(); +} + +/* Utility function to signal the end of a test. */ +void endTest() { + cout << "== end of test: press ENTER to continue ==" << endl; + pressEnterToContinue(); +} + +struct comp{ + bool operator()(int l, int r) const{ + return l > r; + } +}; + +/* Basic test: Can we build an empty priority queue? */ +void basicMyPriorityQueueTest() try { +#if BasicMyPriorityQueueTestEnabled + printBanner("Basic MyPriorityQueue Test"); + + /* Construct the MyPriorityQueue. */ + MyPriorityQueue prio; + checkCondition(true, "MyPriorityQueue construction completed."); + + /* Check basic properties of the MyPriorityQueue. */ + checkCondition(prio.size() == 0, "New prio queue has no elements."); + checkCondition(prio.empty(), "prio queue is empty."); + + endTest(); +#else + testDisabled("BasicMyPriorityQueueTest"); +#endif +} catch (const exception& e) { + failTest(e); +} + +/* A trickier test that involves a data set . + */ +void moderateMyPriorityQueueTest() try { +#if ModerateMyPriorityQueueTestEnabled + printBanner("Moderate MyPriorityQueue Test"); + + MyPriorityQueue prio; + for (size_t i = 0; i < 8; ++i) + prio.push(i); + for (size_t i = 0; i < 8; ++i) + prio.push(7-i); + + /* Check that basic properties hold. */ + checkCondition(prio.size() == 16, "New prio has the right number of elements."); + checkCondition(!prio.empty(), "prio queue is nonempty."); + + /* Make sure that the values of these points are correct. */ + for (size_t i = 0; i < 16; ++i){ + checkCondition(prio.size() == 16-i, "prio has the right number of elements."); + int current = prio.top(); + checkCondition(current == i/2, "top prio element is correct."); + prio.pop(); + } + + checkCondition(prio.empty(), "prio is empty."); + + + endTest(); +#else + testDisabled("moderateMyPriorityQueueTest"); +#endif +} catch (const exception& e) { + failTest(e); +} + + + +/* Tests basic behavior of the copy constructor and assignment operator. */ +void basicCopyTest() try { +#if BasicCopyTestEnabled + printBanner("Basic Copy Test"); + + /* For simplicity, we'll use one-dimensional MyPriorityQueues in this step. */ + MyPriorityQueue one; + for (size_t i = 0; i < 10; ++i) + one.push(i); + for (size_t i = 0; i < 10; ++i) + one.push(9 - i); + + + { + /* Create a clone of one and confirm that everything copied correctly. + * This uses the copy constructor. + */ + MyPriorityQueue clone = one; + + /* Basic checks. */ + checkCondition(one.size() == clone.size(), "clone has the same number of elements as original one."); + checkCondition(one.empty() == clone.empty(), "clone and one agree on emptiness."); + + /* Check that everything in one is there. */ + for (size_t i = 0; i < 20; ++i){ + checkCondition(clone.size() == 20-i, "clone has the right number of elements."); + int current = clone.top(); + checkCondition(current == i/2, "top clone element is correct."); + clone.pop(); + } + + checkCondition(clone.empty(), "clone is empty."); + + } + { + /* Create a clone of one and confirm that everything copied correctly. + * This uses the assignment operator. + */ + MyPriorityQueue clone; + clone = one; + + /* Check that everything in one is there. */ + for (size_t i = 0; i < 20; ++i){ + checkCondition(clone.size() == 20-i, "clone has the right number of elements."); + int current = clone.top(); + checkCondition(current == i/2, "top clone element is correct."); + clone.pop(); + } + + checkCondition(clone.empty(), "clone is empty."); + + + } + + /* Check that everything in one is there. */ + for (size_t i = 0; i < 20; ++i){ + checkCondition(one.size() == 20-i, "After clone destructor, one has the right number of elements."); + int current = one.top(); + checkCondition(current == i/2, "After clone destructor, top one element is correct."); + one.pop(); + } + + checkCondition(one.empty(), "one is empty."); + + + endTest(); +#else + testDisabled("BasicCopyTest"); +#endif +} catch (const exception& e) { + failTest(e); +} + +/* A more merciless test of copy behavior.. */ +void moderateCopyTest() try { +#if BasicCopyTestEnabled + printBanner("Moderate Copy Test"); + + MyPriorityQueue one; + for (size_t i = 0; i < 10; ++i) + one.push(i); + for (size_t i = 0; i < 10; ++i) + one.push(9 - i); + + { + /* Create a clone of one and confirm that everything copied correctly. + * This uses the copy constructor. + */ + MyPriorityQueue clone = one; + + for (size_t i = 0; i < 10; ++i) + clone.push(2*(10+i)); + + /* Confirm that they didn't appear in one. */ + checkCondition(one.size() == 20, "Adding to clone does not change original one size."); + } + + /* Check the integrity of the original out here as well to see that the destructor didn't hose things. */ + checkCondition(one.size() == 20, "After destructor, one has original size."); + + + + { + /*Create a clone of one and confirm that everything copied correctly. + * This uses the assignment operator.*/ + MyPriorityQueue clone; + clone = one; + + /* Do awful, awful things to the copy.*/ + clone = clone = (clone = clone); + (clone = one) = clone; + clone = clone = clone = clone = clone; + + /* Check that everything in one is there.*/ + for (size_t i = 0; i < 20; ++i){ + checkCondition(clone.size() == 20-i, "clone has the right number of elements."); + int current = clone.top(); + checkCondition(current == i/2, "top clone element is correct."); + clone.pop(); + } + + checkCondition(clone.empty(), "clone is empty."); + + } + +/* Check that everything in one is there.*/ + for (size_t i = 0; i < 20; ++i){ + checkCondition(one.size() == 20-i, "one has the right number of elements."); + int current = one.top(); + checkCondition(current == i/2, "top one element is correct."); + one.pop(); + } + + checkCondition(one.empty(), "one is empty."); + + + endTest(); +#else + testDisabled("ModerateCopyTest"); +#endif +} catch (const exception& e) { + failTest(e); +} + +/* Main entry point simply runs all the tests. Note that these functions might be no-ops + * if they are disabled by the configuration settings at the top of the program. + */ +int main() { + basicMyPriorityQueueTest(); + moderateMyPriorityQueueTest(); + basicCopyTest(); + moderateCopyTest(); + +#if (BasicMyPriorityQueueTestEnabled && \ + ModerateMyPriorityQueueTestEnabled && \ + BasicCopyTestEnabled && \ + ModerateCopyTestEnabled) + cout << "All tests completed! If they passed, you should be good to go!" << endl << endl; +#else + cout << "Not all tests were run. Enable the rest of the tests, then run again." << endl << endl; +#endif + + pressEnterToContinue(); +} diff --git a/test-harness-myvector.cpp b/test-harness-myvector.cpp new file mode 100755 index 0000000..d392e33 --- /dev/null +++ b/test-harness-myvector.cpp @@ -0,0 +1,422 @@ +/************************************************* + * File: test-harness-myvector.cpp + * + * File containing several test cases that can be + * used to verify the correctness of the MyVector + * implementation. You should make sure to do your + * own testing in addition to ensuring that the test + * cases here pass. + */ +#include +#include +#include +#include +#include +#include +#include +#include "MyVector.h" +using namespace std; + +/* These flags control which tests will be run. Initially, only the + * basic test will be executed. As you complete more and more parts + * of the implementation, you will want to turn more and more of these + * flags on. + */ +#define BasicMyVectorTestEnabled 1 +#define ModerateMyVectorTestEnabled 1 +#define HarderMyVectorTestEnabled 1 +#define MutatingMyVectorTestEnabled 1 + +#define ConstMyVectorTestEnabled 0 +#define BasicCopyTestEnabled 0 +#define ModerateCopyTestEnabled 0 + + +/* Utility function that pauses until the user hits ENTER. */ +void pressEnterToContinue() { + /* Use getline to stall until receiving input. */ + string line; + getline(cin, line); +} + +/* This function is what the test suite uses to ensure that the MyVector works + * correctly. It takes as parameters an expression and description, along + * with a file and line number, then checks whether the condition is true. + * If so, it prints that the test passed. Otherwise, it reports that the + * test fails and points the caller to the proper file and line. + */ +void doCheckCondition(bool expr, const string& rationale, const string& file, int line) { + /* It worked! Congrats. */ + if (expr) { + cout << "PASS: " << rationale << endl; + return; + } + + /* Uh oh! The test failed! */ + cout << "FAIL: " << rationale << endl; + cout << " Error at " << file << ", line " << line << endl; + cout << " (ENTER to continue)" << endl; + + /* Pause so that the test fail stands out. */ + pressEnterToContinue(); +} + +/* Reports that an unexpected error occurred that caused a test to fail. */ +void failTest(const exception& e) { + cerr << "TEST FAILED: Unexpected exception: " << e.what() << endl; + pressEnterToContinue(); +} + +/* This macro takes in an expression and a string, then invokes + * doCheckCondition passing in the arguments along with the file + * and line number on which the macro was called. This makes it + * easier to track down the source of bugs if a test case should + * fail. + */ +#define checkCondition(expr, rationale) doCheckCondition(expr, rationale, __FILE__, __LINE__) + +/* Utility function to delimit the start and end of test cases. */ +void printBanner(const string& header) { + cout << "\nBeginning test: " << header << endl; + cout << setw(40) << setfill('-') << "" << setfill(' ') << endl; +} + +/* Utility function to signal that a test isn't begin run. */ +void testDisabled(const string& header) { + cout << "== Test " << header << " NOT RUN: press ENTER to continue ==" << endl; + + /* Pause for the user to hit enter. */ + pressEnterToContinue(); +} + +/* Utility function to signal the end of a test. */ +void endTest() { + cout << "== end of test: press ENTER to continue ==" << endl; + pressEnterToContinue(); +} + +/* Basic test: Can we build an empty vector and clear it? */ +void basicMyVectorTest() try { +#if BasicMyVectorTestEnabled + printBanner("Basic MyVector Test"); + + /* Construct the MyVector. */ + MyVector vect; + checkCondition(true, "New MyVector construction completed."); + + /* Check basic properties of the MyVector. */ + checkCondition(vect.size() == 0, "vector has no elements."); + checkCondition(vect.empty(), "vector is empty."); + + /* Clear the MyVctor and check basic properties again. */ + vect.clear(); + checkCondition(vect.size() == 0, "vector has no elements."); + checkCondition(vect.empty(), "vector is empty."); + + endTest(); +#else + testDisabled("BasicMyVectorTest"); +#endif +} catch (const exception& e) { + failTest(e); +} + +/* A trickier test that involves a data set and iterating through the vector with pointers. + */ +void moderateMyVectorTest() try { +#if ModerateMyVectorTestEnabled + printBanner("Moderate MyVector Test"); + + /* Build a palindrome. */ + MyVector vect; + for (size_t i = 0; i < 8; ++i) + vect.push_back(i); + for (size_t i = 0; i < 8; ++i) + vect.push_back(7-i); + + /* Check that basic properties hold. */ + checkCondition(vect.size() == 16, "New vector has the right number of elements."); + checkCondition(!vect.empty(), "vector is nonempty."); + + /* Make sure that the values of these points are correct. */ + int* fwd = vect.begin(); + int* bwd = vect.end(); + while(fwd != bwd){ + --bwd; + checkCondition(*fwd == *bwd, "vector has correct values."); + ++fwd; + } + + for (size_t i = 0; i < 8; ++i) + vect.pop_back(); + + /* Check basic properties again. */ + checkCondition(vect.size() == 8, "vector has 8 elements."); + checkCondition(!vect.empty(), "vector is nonempty."); + + + for (size_t i = 0; i < 8; ++i) + vect.pop_back(); + + /* Check basic properties again. */ + checkCondition(vect.size() == 0, "vector has no elements."); + checkCondition(vect.empty(), "vector is empty."); + + endTest(); +#else + testDisabled("moderateMyVectorTest"); +#endif +} catch (const exception& e) { + failTest(e); +} + +/* This test still uses just the basic functionality, but uses larger + * data set and index based access + */ +void harderMyVectorTest() try { +#if HarderMyVectorTestEnabled + printBanner("Harder MyVector Test"); + + MyVector vect; + for (size_t i = 0; i < 4096; ++i) + vect.push_back(i); + + /* Check that basic properties hold. */ + checkCondition(vect.size() == 4096, "New vector has 4096 elements."); + checkCondition(!vect.empty(), "vector is nonempty."); + + for (size_t i = 0; i < 2048; ++i) + vect.pop_back(); + + /* Check basic properties again. */ + checkCondition(vect.size() == 2048, "vector has now 2048 elements."); + checkCondition(!vect.empty(), "vector is nonempty."); + + + for (size_t i = 0; i < 2048; ++i) + vect.push_back(-i); + + /* Check that basic properties hold. */ + checkCondition(vect.size() == 4096, "vector has now 4096 elements."); + checkCondition(!vect.empty(), "vector is nonempty."); + + /* Clear the MyVctor and check basic properties again. */ + vect.clear(); + checkCondition(vect.size() == 0, "vector has no elements."); + checkCondition(vect.empty(), "vector is empty."); + + for (size_t i = 0; i < 4096; ++i) + vect.push_back(i); + + /* Check that basic properties hold. */ + checkCondition(vect.size() == 4096, "vector has again 4096 elements."); + checkCondition(!vect.empty(), "vector is nonempty."); + + + endTest(); +#else + testDisabled("HarderMyVectorTest"); +#endif +} catch (const exception& e) { + failTest(e); +} + + +/* This test actively mutates the elements of the MyVector using + * operator[]. If you are failing this test, check to make sure + * that your implementation of operator[] correctly allows for + * mutation. + */ +void mutatingMyVectorTest() try { +#if MutatingMyVectorTestEnabled + printBanner("Mutating MyVector Test"); + + MyVector vect; + for (size_t i = 0; i < 16; ++i) + vect.push_back(i); + + /* Check that basic properties hold. */ + checkCondition(vect.size() == 16, "New vector has 16 elements."); + checkCondition(!vect.empty(), "vector is nonempty."); + + for (size_t i = 0; i < 16; ++i) + vect[i] = vect[i] + 1; + + for (size_t i = 0; i < 16; ++i) + checkCondition(vect[i] == i + 1, "updated vector has correct values."); + + endTest(); +#else + testDisabled("mutatingMyVectorTest"); +#endif +} catch (const exception& e) { + failTest(e); +} + + +/* A basic test that creates a const MyVector and a non-const MyVector to ensure + * the class still compiles properly. It also tests the const version of + * [] is working correctly on the basic MyVector tests. + */ +void constMyVectorTest() try { +#if ConstMyVectorTestEnabled + printBanner("Const MyVector Test"); + + MyVector vect; + for (size_t i = 0; i < 4; ++i) + vect.push_back(i); + + /* Check that the code compiles for the non-const version. */ + vect.size(); + vect.empty(); + vect[3]=10; + + const MyVector& const_vect = vect; + + /* Check that the code compiles for the const version. */ + const_vect.size(); + const_vect.empty(); + const_vect[3]; + + checkCondition(true, "Const code compiles."); + + /* Run the basic vect tests using a const vect. */ + checkCondition(const_vect[0]==0, "const_vect has element zero."); + checkCondition(const_vect[1]==1, "const_vect has element one."); + checkCondition(const_vect[2]==2, "const_vect has element two."); + checkCondition(const_vect[3]==10, "const_vect has element ten."); + + endTest(); +#else + testDisabled("ConstMyVectorTest"); +#endif +} catch (const exception& e) { + cout << "Note: vect lookup failed, but const code compiles." << endl; + failTest(e); +} + + +/* Tests basic behavior of the copy constructor and assignment operator. */ +void basicCopyTest() try { +#if BasicCopyTestEnabled + printBanner("Basic Copy Test"); + + MyVector one; + for (size_t i = 0; i < 10; ++i) + one.push_back(2*i); + + { + /* Create a clone of one and confirm that everything copied correctly. + * This uses the copy constructor. + */ + MyVector clone = one; + + /* Basic checks. */ + checkCondition(one.size() == clone.size(), "clone has the same number of elements as one."); + checkCondition(one.empty() == clone.empty(), "clone and one agree on emptiness."); + + /* Check that everything in one is there. */ + for (size_t i = 0; i < 10; ++i) + checkCondition(clone[i]==2*i, "Element from one present in clone."); + + } + { + /* Create a clone of one and confirm that everything copied correctly. + * This uses the assignment operator. + */ + MyVector clone; + clone = one; + + /* Basic checks. */ + checkCondition(one.size() == clone.size(), "clone has the same number of elements as the one."); + checkCondition(one.empty() == clone.empty(), "clone and one agree on emptiness."); + + /* Check that everything in one is there. */ + for (size_t i = 0; i < 10; ++i) + checkCondition(clone[i]==2*i, "Element from one present in clone."); + } + + endTest(); +#else + testDisabled("BasicCopyTest"); +#endif +} catch (const exception& e) { + failTest(e); +} + +/* A more merciless test of copy behavior.. */ +void moderateCopyTest() try { +#if BasicCopyTestEnabled + printBanner("Moderate Copy Test"); + + MyVector one; + for (size_t i = 0; i < 10; ++i) + one.push_back(2*i); + + { + /* Create a clone of one and confirm that everything copied correctly. + * This uses the copy constructor. + */ + MyVector clone = one; + + /* Add odd numbers to the clone. */ + for (size_t i = 0; i < 10; ++i) + clone.push_back(2*(10+i)); + + checkCondition(one.size() == 10, "Adding to clone did not change one size."); + } + + /* Check the integrity of the original out here as well to see that the destructor didn't hose things. */ + checkCondition(one.size() == 10, "After clone destructor, one has original size."); + for (size_t i = 0; i < 10; ++i) { + checkCondition(one[i]==2*i, "After clone destructor, one contains same as original."); + } + + { + /* Create a clone of one and confirm that everything copied correctly. + * This uses the assignment operator. + */ + MyVector clone; + clone = one; + + /* Do awful, awful things to the copy. */ + clone = clone = (clone = clone); + (clone = one) = clone; + clone = clone = clone = clone = clone; + } + + endTest(); +#else + testDisabled("ModerateCopyTest"); +#endif +} catch (const exception& e) { + failTest(e); +} + +/* Main entry point simply runs all the tests. Note that these functions might be no-ops + * if they are disabled by the configuration settings at the top of the program. + */ +int main() { + basicMyVectorTest(); + moderateMyVectorTest(); + harderMyVectorTest(); + mutatingMyVectorTest(); + constMyVectorTest(); + + basicCopyTest(); + moderateCopyTest(); + +#if (BasicMyVectorTestEnabled && \ + ModerateMyVectorTestEnabled && \ + HarderMyVectorTestEnabled && \ + MutatingMyVectorTestEnabled && \ + ConstMyVectorTestEnabled && \ + BasicCopyTestEnabled && \ + ModerateCopyTestEnabled) + cout << "All tests completed! If they passed, you should be good to go!" << endl << endl; +#else + cout << "Not all tests were run. Enable the rest of the tests, then run again." << endl << endl; +#endif + + pressEnterToContinue(); +}