This commit is contained in:
Love 2024-09-16 13:18:17 +02:00
commit 1785e4285a
17 changed files with 1633 additions and 0 deletions

12
.gitignore vendored Executable file
View File

@ -0,0 +1,12 @@
*~
.DS_Store
*.pro.user.*
*.pro.user
build-*/
*.app
*.exe
build

136
Event.cpp Executable file
View File

@ -0,0 +1,136 @@
#include "Event.h"
#include "Simulation.h"
#include <iostream>
#include <cassert>
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<int> 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<int> 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<int> 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<int> 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<int> 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<int> 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));
}

80
Event.h Executable file
View File

@ -0,0 +1,80 @@
#ifndef EVENT_H
#define EVENT_H
#include "Fish.h"
#include "config.h"
#include <fstream>
#include <random>
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

92
Fish.cpp Executable file
View File

@ -0,0 +1,92 @@
#include "Fish.h"
#include <sstream>
#include <cassert>
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;
}

45
Fish.h Executable file
View File

@ -0,0 +1,45 @@
#ifndef FISH_H
#define FISH_H
#include "config.h"
#include <string>
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

16
MyException.h Executable file
View File

@ -0,0 +1,16 @@
#ifndef MYEXCEPTION_H
#define MYEXCEPTION_H
#include <sstream>
#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

81
MyPriorityQueue.h Executable file
View File

@ -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 <typename T, typename C>
class MyPriorityQueue
{
MyVector<T> 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 <typename T, typename C>
MyPriorityQueue<T,C>::MyPriorityQueue(){
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template <typename T, typename C>
MyPriorityQueue<T,C>::~MyPriorityQueue(){
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template <typename T, typename C>
void MyPriorityQueue<T,C>::push(const T& t){
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template <typename T, typename C>
T MyPriorityQueue<T,C>::top()const{
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template <typename T, typename C>
void MyPriorityQueue<T,C>::pop(){
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template <typename T, typename C>
bool MyPriorityQueue<T,C>::empty()const{
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template <typename T, typename C>
unsigned MyPriorityQueue<T,C>::size()const{
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
#endif // MY_PRIORITY_QUEUE_H

128
MyVector.h Executable file
View File

@ -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 <typename T>
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<typename T>
MyVector<T>::MyVector(){
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template<typename T>
MyVector<T>::~MyVector(){
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template<typename T>
MyVector<T>::MyVector(const MyVector& other){
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template<typename T>
MyVector<T>& MyVector<T>::operator =(const MyVector& other){
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template<typename T>
void MyVector<T>::push_back(const T& e){
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template<typename T>
void MyVector<T>::pop_back(){
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template<typename T>
T& MyVector<T>::operator[](unsigned i){
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template<typename T>
const T& MyVector<T>::operator[](unsigned i)const{
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template<typename T>
bool MyVector<T>::empty()const{
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template<typename T>
void MyVector<T>::clear(){
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template<typename T>
unsigned MyVector<T>::size()const{
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template<typename T>
T* MyVector<T>::begin(){
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
template<typename T>
T* MyVector<T>::end(){
// TODO: replace the code below with your code for this member
MYEXCEPTION("unimplemented method");
}
#endif // MY_VECTOR_H

2
README.md Executable file
View File

@ -0,0 +1,2 @@
See: labb 6 @ https://www.ida.liu.se/~TDDD86/info/labs.sv.shtml

120
Simulation.cpp Executable file
View File

@ -0,0 +1,120 @@
#include "Simulation.h"
#include <algorithm>
#include <cassert>
#include <iostream>
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<Fish*> stillAlive;
std::vector<Fish*> 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;
}

63
Simulation.h Executable file
View File

@ -0,0 +1,63 @@
#ifndef SIMULATION_H
#define SIMULATION_H
#include "config.h"
#include "Event.h"
#include "MyPriorityQueue.h"
#include "MyVector.h"
#include <random>
#include <vector>
#include <queue>
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<Event*, EventComparator> eventQueue;
std::priority_queue<Event*,
vector<Event *, allocator<Event*> >,
EventComparator> eventQueue;
// MyVector<Fish*> allTheFish;
std::vector<Fish*> allTheFish;
unsigned simulationTime;
unsigned eggPopulation;
unsigned juvenilePopulation;
unsigned adultPopulation;
};
#endif // SIMULATION_H

0
answers.txt Executable file
View File

29
config.h Executable file
View File

@ -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

8
fisher.pro Executable file
View File

@ -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)

77
main.cpp Executable file
View File

@ -0,0 +1,77 @@
#include "Event.h"
#include "Fish.h"
#include "Simulation.h"
#include <fstream>
#include <iostream>
#include <random>
#include <string>
#include <chrono>
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<chrono::seconds>(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());
}

322
test-harness-myprio.cpp Executable file
View File

@ -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 <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <iomanip>
#include <cstdarg>
#include <set>
#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<int,comp> 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<int,comp> 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<int, comp> 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<int,comp> 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<int,comp> 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<int,comp> 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<int,comp> 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<int,comp> 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();
}

422
test-harness-myvector.cpp Executable file
View File

@ -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 <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <iomanip>
#include <cstdarg>
#include <set>
#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<int> 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<int> 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<int> 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<int> 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<int> 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<int>& 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<int> 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<int> 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<int> 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<int> 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<int> 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<int> 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();
}