├── lab3 ├── Yz7962.o ├── bx522.o ├── yh7483.o ├── Jeremy64.o ├── yl23394.o ├── tokens.h ├── LifeForm Detailed.pdf ├── config.test ├── SimTime.h ├── Random.h ├── Color.h ├── Init.h ├── CraigUtils.h ├── Cons.h ├── Praveen.h ├── Craig.h ├── Algae.h ├── Window.h ├── ObjInfo.h ├── Algae.cpp ├── SmartPointer.h ├── animals.cpp ├── Makefile ├── Event.cpp ├── Craig.cpp ├── Event.h ├── Point.h ├── Praveen.cpp ├── Window.cpp ├── Params.cpp ├── Params.h ├── LifeForm.h ├── LifeForm-Craig.cpp ├── LifeForm.cpp └── QuadTree.h ├── midterm ├── test ├── declval.cpp ├── Makefile ├── sp12_8.cpp ├── sp12_7.cpp ├── sp13_6.cpp ├── sp13_1.cpp ├── sp12_1.cpp ├── sp12_6.cpp ├── sp13_3.cpp ├── sp12_2.cpp ├── sp12_3.cpp ├── sp12_4.cpp ├── sp13_4.cpp ├── sp13_5.cpp └── sp13_2.cpp ├── lab2 ├── Instructions.pdf ├── InstanceCounter.h ├── README.md └── Valarray.h ├── lab1 ├── Instructions Phase C.pdf ├── Instructions Phase A and B.pdf ├── README.md └── Vector.h ├── quiz1 ├── Quiz1.h └── Source.cpp └── README.md /lab3/Yz7962.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfiresprairie/epl/HEAD/lab3/Yz7962.o -------------------------------------------------------------------------------- /lab3/bx522.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfiresprairie/epl/HEAD/lab3/bx522.o -------------------------------------------------------------------------------- /lab3/yh7483.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfiresprairie/epl/HEAD/lab3/yh7483.o -------------------------------------------------------------------------------- /midterm/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfiresprairie/epl/HEAD/midterm/test -------------------------------------------------------------------------------- /lab3/Jeremy64.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfiresprairie/epl/HEAD/lab3/Jeremy64.o -------------------------------------------------------------------------------- /lab3/yl23394.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfiresprairie/epl/HEAD/lab3/yl23394.o -------------------------------------------------------------------------------- /lab2/Instructions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfiresprairie/epl/HEAD/lab2/Instructions.pdf -------------------------------------------------------------------------------- /lab3/tokens.h: -------------------------------------------------------------------------------- 1 | 2 | enum Token { 3 | TOK_EOF = 0, 4 | TOK_INT, 5 | TOK_DOUBLE, 6 | TOK_ID 7 | }; 8 | -------------------------------------------------------------------------------- /lab3/LifeForm Detailed.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfiresprairie/epl/HEAD/lab3/LifeForm Detailed.pdf -------------------------------------------------------------------------------- /lab1/Instructions Phase C.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfiresprairie/epl/HEAD/lab1/Instructions Phase C.pdf -------------------------------------------------------------------------------- /lab3/config.test: -------------------------------------------------------------------------------- 1 | Algae 100 2 | xw3893 10 3 | Yz7962 10 4 | Jeremy 10 5 | yl23394 10 6 | Craig 10 7 | Praveen 10 8 | -------------------------------------------------------------------------------- /lab1/Instructions Phase A and B.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfiresprairie/epl/HEAD/lab1/Instructions Phase A and B.pdf -------------------------------------------------------------------------------- /lab3/SimTime.h: -------------------------------------------------------------------------------- 1 | #if !(_Time_h) 2 | #define _Time_h 1 3 | 4 | typedef double SimTime; 5 | 6 | #endif /* !(_Time_h) */ 7 | 8 | -------------------------------------------------------------------------------- /lab3/Random.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if defined (_MSC_VER) 4 | namespace epl { 5 | extern std::default_random_engine random_generator; 6 | extern std::function drand48; 7 | } 8 | #endif 9 | -------------------------------------------------------------------------------- /lab3/Color.h: -------------------------------------------------------------------------------- 1 | #if !(_Color_h) 2 | #define _Color_h 1 3 | 4 | enum Color { 5 | BLACK = 0, 6 | BLUE = 1, 7 | GREEN = 2, 8 | CYAN = 3, 9 | MAGENTA = 4, 10 | RED = 5, 11 | ORANGE = 6, 12 | YELLOW = 7 13 | }; 14 | 15 | 16 | #endif /* !(_Color_h) */ 17 | -------------------------------------------------------------------------------- /lab2/InstanceCounter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #ifndef _InstanceCounter_h 5 | #define _InstanceCounter_h 6 | 7 | class InstanceCounter { 8 | public: 9 | static int counter; 10 | InstanceCounter(void) { 11 | ++counter; 12 | } 13 | }; 14 | 15 | #endif /* _InstanceCounter_h */ -------------------------------------------------------------------------------- /lab3/Init.h: -------------------------------------------------------------------------------- 1 | #if !(_Init_h) 2 | #define _Init_h 1 3 | 4 | template 5 | class Initializer { 6 | int& count(void) { static int x = 0; return x; } 7 | public: 8 | Initializer(void) { 9 | if ((count())++ == 0) { 10 | T::initialize(); 11 | } 12 | } 13 | }; 14 | 15 | 16 | 17 | #endif /* !(_Init_h) */ 18 | -------------------------------------------------------------------------------- /lab3/CraigUtils.h: -------------------------------------------------------------------------------- 1 | #ifndef _CraigUtils_h 2 | #define _CraigUtils_h 1 3 | #include 4 | 5 | template 6 | class Nil { 7 | public: 8 | operator T* () { return static_cast(0); } 9 | }; 10 | 11 | template 12 | void Delete(T*& x) { 13 | delete x; 14 | x = Nil(); 15 | } 16 | 17 | 18 | #define MAXFLOAT (1.0e127) 19 | #endif /* _CraigUtils_h */ 20 | -------------------------------------------------------------------------------- /midterm/declval.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | template ())> 4 | false_type are_you_pointer(T) { 5 | return false_type{}; 6 | } 7 | template 8 | true_type are_you_pointer(...) { 9 | return true_type{}; 10 | } 11 | 12 | template 13 | struct AA : public decltype(are_you_pointer(declval())) {}; 14 | 15 | int main() { 16 | cout << AA{}; 17 | } 18 | 19 | 20 | -------------------------------------------------------------------------------- /lab3/Cons.h: -------------------------------------------------------------------------------- 1 | #if !(_Cons_h) 2 | #define _Cons_h 1 3 | 4 | #include 5 | 6 | template 7 | struct Cons { 8 | T car; 9 | Cons* cdr; 10 | Cons(const T& x) : car(x) { cdr = 0; } 11 | Cons(const Cons& c) : car(c.car) { 12 | if (c.cdr) cdr = new Cons(*c.cdr); 13 | else cdr = 0; 14 | } 15 | ~Cons(void) { delete cdr; } 16 | 17 | private: 18 | 19 | Cons& operator=(const Cons&) { 20 | /* don't assign Cons's! */ 21 | assert(0); 22 | return *this; 23 | } 24 | }; 25 | #endif !(_Cons_h) 26 | -------------------------------------------------------------------------------- /midterm/Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | CXXFLAGS = -g -I $(INCLUDE_DIR) -std=c++11 -Wall -Werror -fmax-errors=1 -std=c++0x 3 | SRCS = sp13_5.cpp 4 | OBJS = $(patsubst %.cpp, %.o, $(SRCS)) 5 | DEPS = $(patsubst %.cpp, %.d, $(SRCS)) 6 | TEST = test 7 | all: $(TEST) 8 | test: $(TEST) 9 | @./$(TEST) 10 | -include $(DEPS) 11 | %.d: %.cpp 12 | @$(CXX) $< $(CXXFLAGS) -MM > $@ 13 | 14 | %.o: %.d 15 | $(CXX) $*.cpp $(CXXFLAGS) -c -o $@ 16 | 17 | $(TEST): $(OBJS) 18 | $(CXX) $^ $(GTEST_LIB) $(CXXFLAGS) -pthread -o $@ 19 | 20 | clean: 21 | -rm -rf *.o $(shell ls *.o) 22 | -rm -rf *.d $(shell ls *.d) 23 | -------------------------------------------------------------------------------- /midterm/sp12_8.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // sp12_8.cpp 3 | // practice 4 | // 5 | // Created by Xingyuan Wang on 3/24/15. 6 | // Copyright (c) 2015 Engineering Programming Language. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | 12 | template 13 | struct F { 14 | }; 15 | 16 | 17 | template 18 | void doit(F f) { 19 | std::cout << "T3's type: " << typeid(T3).name() << std::endl; 20 | std::cout << "T4's type: " << typeid(T4).name() << std::endl; 21 | } 22 | 23 | int main() { 24 | doit(F{}); 25 | } -------------------------------------------------------------------------------- /midterm/sp12_7.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // sp12_7.cpp 3 | // practice 4 | // 5 | // Created by Xingyuan Wang on 3/24/15. 6 | // Copyright (c) 2015 Engineering Programming Language. All rights reserved. 7 | // 8 | #include 9 | 10 | template 11 | void func(DS data, FO compare, VT val) { 12 | for (auto i = data.begin(); i != data.end(); i++) { 13 | if (compare(*i, val)) { 14 | std::cout << *i << std::endl; 15 | } 16 | } 17 | } 18 | //template 19 | //struct CompThing { 20 | // bool operator()(DS x, VT y) { return x < y; } 21 | //}; -------------------------------------------------------------------------------- /lab3/Praveen.h: -------------------------------------------------------------------------------- 1 | #if !(_Praveen_h) 2 | #define _Praveen_h 1 3 | 4 | #include "LifeForm.h" 5 | #include "Init.h" 6 | 7 | class Praveen : public LifeForm { 8 | protected: 9 | int course_changed ; 10 | static void initialize(void); 11 | void spawn(void); 12 | void hunt(void); 13 | void live(void); 14 | Event* hunt_event; 15 | public: 16 | Praveen(void); 17 | ~Praveen(void); 18 | Color my_color(void) const; // defines LifeForm::my_color 19 | static LifeForm* create(void); 20 | std::string species_name(void) const; 21 | Action encounter(const ObjInfo&); 22 | friend class Initializer; 23 | }; 24 | 25 | 26 | #endif /* !(_Praveen_h) */ 27 | -------------------------------------------------------------------------------- /lab3/Craig.h: -------------------------------------------------------------------------------- 1 | #if !(_Craig_h) 2 | #define _Craig_h 1 3 | 4 | #include 5 | #include "LifeForm.h" 6 | #include "Init.h" 7 | 8 | class Craig : public LifeForm { 9 | protected: 10 | static void initialize(void); 11 | void spawn(void); 12 | void hunt(void); 13 | void startup(void); 14 | Event* hunt_event; 15 | public: 16 | Craig(void); 17 | ~Craig(void); 18 | Color my_color(void) const; // defines LifeForm::my_color 19 | static SmartPointer create(void); 20 | virtual std::string species_name(void) const; 21 | virtual Action encounter(const ObjInfo&); 22 | friend class Initializer; 23 | }; 24 | 25 | 26 | #endif /* !(_Craig_h) */ 27 | -------------------------------------------------------------------------------- /midterm/sp13_6.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // sp13_6.cpp 3 | // practice 4 | // 5 | // Created by Xingyuan Wang on 3/26/15. 6 | // Copyright (c) 2015 Engineering Programming Language. All rights reserved. 7 | // 8 | 9 | #include 10 | 11 | class A { 12 | virtual void doit() {}; 13 | }; 14 | 15 | class B :public A { 16 | virtual void doit() {}; 17 | }; 18 | 19 | int main() { 20 | // int a = 3; 21 | // const int* p = &a; 22 | // int* q = &a; 23 | // p = q; 24 | // q = p; 25 | 26 | A a; 27 | B b; 28 | 29 | A* p = &a; 30 | B* q = &b; 31 | 32 | p = q; 33 | 34 | std::cout << ( (void*)p != (void*)q ) << std::endl; 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /lab3/Algae.h: -------------------------------------------------------------------------------- 1 | #if !(_Algae_h) 2 | #define _Algae_h 1 3 | #include 4 | 5 | #include "LifeForm.h" 6 | #include "Init.h" 7 | 8 | class Algae : public LifeForm { 9 | static void initialize(void); 10 | Event* photo_event; 11 | void photosynthesize(void); 12 | public: 13 | Algae(void); 14 | void draw(int,int) const; // defines LifeForm::draw 15 | Color my_color(void) const; // defines LifeForm::my_color 16 | std::string species_name(void) const; 17 | std::string player_name(void) const; 18 | virtual Action encounter(const ObjInfo&); 19 | static SmartPointer create(void); 20 | static void create_spontaneously(void); 21 | friend class Initializer; 22 | }; 23 | 24 | #endif /* !(_Algae_h) */ 25 | -------------------------------------------------------------------------------- /midterm/sp13_1.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // sp13_1.cpp 3 | // practice 4 | // 5 | // Created by Xingyuan Wang on 3/24/15. 6 | // Copyright (c) 2015 Engineering Programming Language. All rights reserved. 7 | // 8 | 9 | #include 10 | 11 | class Fibonacci { 12 | int64_t val1; 13 | int64_t val2; 14 | int64_t size; 15 | public: 16 | Fibonacci(int64_t n): val1{1}, val2{1}, size{n} {} 17 | class iterator { 18 | private: 19 | uint64_t* position = nullptr; 20 | public: 21 | iterator(void): position{&val1} {} 22 | int64_t& operator*(void) { return val1; } 23 | 24 | }; 25 | 26 | }; 27 | int main(void) { 28 | for (int64_t v : Fibonacci(20)) { 29 | std::cout << v << std::endl; 30 | } 31 | } -------------------------------------------------------------------------------- /midterm/sp12_1.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // sp12_1.cpp 3 | // practice 4 | // 5 | // Created by Xingyuan Wang on 3/23/15. 6 | // Copyright (c) 2015 Engineering Programming Language. All rights reserved. 7 | // 8 | 9 | 10 | // Our goal is pass parameter values to a function by name 11 | class ParamProxy { 12 | public: 13 | int spd; 14 | int dst; 15 | ParamProxy(void): spd{50}, dst{50} {}; 16 | }; 17 | 18 | struct SpeedPlaceHolder { 19 | ParamProxy operator=(int x) { 20 | ParamProxy a; 21 | a.spd = x; 22 | return a; 23 | } 24 | }; 25 | 26 | struct DistancePlaceHolder { 27 | ParamProxy operator=(int x) { 28 | ParamProxy a; 29 | a.dst = x; 30 | return a; 31 | } 32 | }; 33 | 34 | SpeedPlaceHolder speed; 35 | DistancePlaceHolder distance; 36 | 37 | void doit(ParamProxy param) { 38 | 39 | } -------------------------------------------------------------------------------- /midterm/sp12_6.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // sp12_6.cpp 3 | // practice 4 | // 5 | // Created by Xingyuan Wang on 3/24/15. 6 | // Copyright (c) 2015 Engineering Programming Language. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | template 15 | bool is_vector(const T& t) {return false;}; 16 | 17 | //template 18 | bool is_vector(typename std::random_access_iterator_tag t) { 19 | return true; 20 | } 21 | 22 | template 23 | void ds_type(DS x) { 24 | typename std::iterator_traits::iterator_category tag{}; 25 | if(is_vector(tag)) 26 | std::cout << "vector like" << std::endl; 27 | else 28 | std::cout << "list like" << std::endl; 29 | } 30 | 31 | //int main() { 32 | // std::vector a; 33 | // std::list b; 34 | // ds_type(a); 35 | // ds_type(b); 36 | // return 0; 37 | //} 38 | -------------------------------------------------------------------------------- /midterm/sp13_3.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // sp13_3.cpp 3 | // practice 4 | // 5 | // Created by Xingyuan Wang on 3/25/15. 6 | // Copyright (c) 2015 Engineering Programming Language. All rights reserved. 7 | // 8 | 9 | #include 10 | 11 | 12 | 13 | class Base { 14 | public: 15 | virtual void doit(void) { std::cout << "TRUE\n"; } 16 | void foo(void) { doit(); } 17 | }; 18 | 19 | class Derived: public Base { 20 | int x; 21 | public: 22 | virtual void doit(void) { std::cout << "FALSE\n"; } 23 | }; 24 | 25 | Base* array = new Derived[10]; 26 | 27 | template void tfun1(T x) { x.doit(); } 28 | 29 | template void tfun2(T x) { x.foo(); } 30 | 31 | int main() { 32 | array -> doit(); 33 | array -> foo(); 34 | (array+1) -> doit(); 35 | array[0].doit(); 36 | array[1].doit(); 37 | auto a = *array; 38 | (*array).doit(); 39 | a.doit(); 40 | tfun1(*array); 41 | tfun2(*array); 42 | return 0; 43 | } -------------------------------------------------------------------------------- /lab3/Window.h: -------------------------------------------------------------------------------- 1 | #if !_Window_h 2 | #define _Window_h 1 3 | 4 | #include "Color.h" 5 | 6 | #if !(NO_WINDOW) 7 | #include 8 | #include 9 | #endif 10 | 11 | class Canvas { 12 | private: 13 | int width; 14 | int height; 15 | 16 | unsigned long color_map[8]; 17 | Color color; 18 | 19 | #if ! (NO_WINDOW) 20 | Fl_Double_Window *window; // defined in Fl_Window.H 21 | #endif 22 | 23 | int scrn; 24 | unsigned int plane_mask; 25 | 26 | /* unsigned */ void initcolor(void); 27 | unsigned initmono(void); 28 | 29 | public: 30 | Canvas(int width = 600, int height = 450); 31 | ~Canvas() {} // should close the window, yes? 32 | 33 | void set_color(Color); 34 | void display(void); 35 | void draw_line(int, int, int, int); 36 | void draw_point(int x, int y); 37 | void draw_rectangle(int x1, int y1, int, int, bool = true); 38 | void flush(void); 39 | void clear(void); 40 | 41 | }; 42 | 43 | #endif /* ! _Window_h */ 44 | -------------------------------------------------------------------------------- /midterm/sp12_2.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // sp12_2.cpp 3 | // practice 4 | // 5 | // Created by Xingyuan Wang on 3/23/15. 6 | // Copyright (c) 2015 Engineering Programming Language. All rights reserved. 7 | // 8 | 9 | // Our goal is pass parameter values to a function by name 10 | class ParamProxy { 11 | public: 12 | int spd; 13 | int dst; 14 | ParamProxy(void): spd{50}, dst{50} {}; 15 | }; 16 | 17 | struct SpeedPlaceHolder { 18 | ParamProxy operator=(int x) { 19 | ParamProxy a; 20 | a.spd = x; 21 | return a; 22 | } 23 | }; 24 | 25 | struct DistancePlaceHolder { 26 | ParamProxy operator=(int x) { 27 | ParamProxy a; 28 | a.dst = x; 29 | return a; 30 | } 31 | }; 32 | 33 | ParamProxy operator,(ParamProxy& x, ParamProxy& y ) { 34 | ParamProxy a; 35 | if (x.spd == a.spd) { 36 | x.spd = y.spd; 37 | } 38 | if (x.dst == a.dst) { 39 | x.dst = y.dst; 40 | } 41 | return x; 42 | } 43 | 44 | SpeedPlaceHolder speed; 45 | DistancePlaceHolder distance; 46 | 47 | void doit(ParamProxy param) { 48 | 49 | } -------------------------------------------------------------------------------- /midterm/sp12_3.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // sp12_3.cpp 3 | // practice 4 | // 5 | // Created by Xingyuan Wang on 3/23/15. 6 | // Copyright (c) 2015 Engineering Programming Language. All rights reserved. 7 | // 8 | 9 | template struct rtype; 10 | template struct rtype { using type = T1; }; 11 | template struct rtype { using type = T2; }; 12 | 13 | template 14 | class Vector{ 15 | //using X = typename choose_type::type; 16 | using X = typename rtype<(sizeof(T1)>sizeof(T2)), T1, T2>::type; 17 | X* data; 18 | int length; 19 | public: 20 | explicit Vector(int sz) { 21 | length = sz; 22 | data = new X[sz]; 23 | } 24 | 25 | T1& operator[](int k) { return *((T1*)(&data[k]));} 26 | }; 27 | 28 | /* 29 | template 30 | struct choose_type { 31 | static constexpr bool flag = sizeof(T1) > sizeof(T2)? true : false; 32 | using type = typename rtype::type; 33 | }; 34 | */ 35 | 36 | -------------------------------------------------------------------------------- /lab3/ObjInfo.h: -------------------------------------------------------------------------------- 1 | #if !(_ObjInfo_h) 2 | #define _ObjInfo_h 1 3 | #include 4 | 5 | //#include "Default_ops.h" 6 | struct ObjInfo { 7 | std::string species; // species of the object 8 | double health; // their health 9 | double distance; // distance between us 10 | double bearing; // course I can take to get where it is now 11 | double their_speed; 12 | double their_course; 13 | bool operator == (const ObjInfo& o) const { 14 | return species == o.species && 15 | distance == o.distance && 16 | bearing == o.bearing && 17 | their_speed == o.their_speed && 18 | their_course == o.their_course; 19 | }; 20 | 21 | void copy(const ObjInfo& o) { // this is exactly what the default copy 22 | // constructor would do. 23 | species = o.species; 24 | health = o.health; 25 | distance = o.distance; 26 | bearing = o.bearing; 27 | their_speed = o.their_speed; 28 | their_course = o.their_course; 29 | } 30 | 31 | ObjInfo(void) {} // use this constructor with care! 32 | ObjInfo(const ObjInfo& o) { copy(o); } 33 | ObjInfo& operator=(const ObjInfo& o) { copy(o); return *this; } 34 | }; 35 | 36 | #endif /* !(_ObjInfo_h) */ 37 | -------------------------------------------------------------------------------- /midterm/sp12_4.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // sp12_4.cpp 3 | // practice 4 | // 5 | // Created by Xingyuan Wang on 3/23/15. 6 | // Copyright (c) 2015 Engineering Programming Language. All rights reserved. 7 | // 8 | #include 9 | 10 | template struct rtype; 11 | template struct rtype { using type = T1; }; 12 | template struct rtype { using type = T2; }; 13 | 14 | template 15 | struct List { 16 | using type = typename rtype<(sizeof(H)>sizeof(Tail)), H, Tail>::type; 17 | }; 18 | 19 | template 20 | struct List> { 21 | using type = typename rtype<(sizeof(H)>sizeof(typename List::type)), H, typename List::type>::type; 22 | }; 23 | 24 | template 25 | class Vector{ 26 | public: 27 | using X = typename rtype<(sizeof(T1)>sizeof(T2)), T1, T2>::type; 28 | X* data; 29 | int length; 30 | public: 31 | explicit Vector(int sz) { 32 | length = sz; 33 | data = new X[sz]; 34 | } 35 | 36 | T1& operator[](int k) { return *((T1*)(&data[k]));} 37 | }; 38 | 39 | template 40 | class Vector> { 41 | public: 42 | using X = typename rtype<(sizeof(T1)>sizeof(typename List::type)), T1, typename List::type>::type; 43 | }; 44 | 45 | //int main() { 46 | // std::cout << "longest:" << sizeof(typename Vector>>::X) << std::endl; 47 | //} 48 | 49 | -------------------------------------------------------------------------------- /midterm/sp13_4.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // sp13_4.cpp 3 | // practice 4 | // 5 | // Created by Xingyuan Wang on 3/26/15. 6 | // Copyright (c) 2015 Engineering Programming Language. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | template 16 | struct CompThing { 17 | bool operator()(const T& x, const T& y) { return x < y; } 18 | }; 19 | 20 | template ::value_type>> 21 | typename std::iterator_traits::value_type findMax(I ib, I ie, C f) { 22 | using T = typename std::iterator_traits::value_type; 23 | T max = *ib; 24 | for (auto i = ib; i != ie ; i++) { 25 | if (f(max, *i)) { 26 | max = *i; 27 | } 28 | } 29 | return max; 30 | } 31 | 32 | template 33 | typename std::iterator_traits::value_type findMax(I ib, I ie) { 34 | using value_type = typename std::iterator_traits::value_type; 35 | return findMax(ib, ie, CompThing{}); 36 | } 37 | 38 | int main() { 39 | int a[] = {3,1,0,0,1,0,4,6,4,2}; 40 | std::vector v{3.14, 2.71, 0, 1.414, 1.732}; 41 | std::list l{3.14, 2.71, 0, 1.414, 1.732}; 42 | 43 | auto amax = findMax(a, a+(sizeof(a)/sizeof(*a))); 44 | std::cout << typeid(amax).name() << ":" << amax << std::endl; 45 | auto vmax = findMax(v.begin(), v.end()); 46 | std::cout << typeid(vmax).name() << ":" << vmax << std::endl; 47 | auto lmax = findMax(l.begin(), l.end()); 48 | std::cout << typeid(lmax).name() << ":" << lmax << std::endl; 49 | } 50 | -------------------------------------------------------------------------------- /lab3/Algae.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "Algae.h" 7 | #include "Event.h" 8 | #include "Params.h" 9 | #include "tokens.h" 10 | #include "Window.h" 11 | 12 | using namespace std; 13 | using String = std::string; 14 | 15 | Initializer __Algae_initializer; 16 | 17 | void Algae::initialize(void) 18 | { 19 | LifeForm::add_creator(Algae::create, "Algae"); 20 | } 21 | 22 | String Algae::species_name(void) const 23 | { 24 | return "Algae"; 25 | } 26 | 27 | String Algae::player_name(void) const 28 | { 29 | return "Algae"; 30 | } 31 | 32 | Algae::Algae(void) { 33 | SmartPointer self{ this }; 34 | photo_event = new Event(algae_photo_time, 35 | [self](void) { self->photosynthesize(); }); 36 | } 37 | 38 | void Algae::draw(int x, int y) const 39 | { 40 | #if DEBUG 41 | cout << "drawing Algae"; 42 | #endif /* DEBUG */ 43 | win.draw_rectangle(x, y, x + 3, y + 3, true); 44 | } 45 | 46 | Color Algae::my_color(void) const 47 | { 48 | return GREEN; 49 | } 50 | 51 | SmartPointer Algae::create(void) 52 | { 53 | return new Algae; 54 | } 55 | 56 | Action Algae::encounter(const ObjInfo&) 57 | { 58 | return LIFEFORM_IGNORE; 59 | } 60 | 61 | void Algae::photosynthesize(void) 62 | { 63 | photo_event = 0; 64 | if (!is_alive) { return; } 65 | energy += Algae_energy_gain; 66 | if (energy > 2.0 * start_energy) { 67 | SmartPointer child = new Algae; 68 | reproduce(child); 69 | } 70 | SmartPointer self{ this }; 71 | photo_event = new Event(algae_photo_time, 72 | [self](void) { self->photosynthesize(); }); 73 | } 74 | 75 | -------------------------------------------------------------------------------- /midterm/sp13_5.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // sp13_5.cpp 3 | // practice 4 | // 5 | // Created by Xingyuan Wang on 3/24/15. 6 | // Copyright (c) 2015 Engineering Programming Language. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | class HotPotato { 12 | public: 13 | ~HotPotato(void) { std::cout << "burned\n"; } 14 | }; 15 | class Container { 16 | HotPotato* pot; 17 | public: 18 | Container(void) { 19 | pot = new HotPotato; 20 | std::cout << "Container()" << std::endl; 21 | } 22 | Container(const Container& that) { 23 | pot = new HotPotato; 24 | *pot = *(that.pot); 25 | std::cout << "Container(T&)" << std::endl; 26 | } 27 | Container(Container&& that) { 28 | pot = that.pot; 29 | that.pot = nullptr; 30 | std::cout << "Container(T&&)" << std::endl; 31 | } 32 | Container& operator=(Container&& that) { 33 | if (this != &that) { 34 | this->pot = that.pot; 35 | that.pot = nullptr; 36 | } 37 | std::cout << "=(&&)" << std::endl; 38 | return *this; 39 | } 40 | Container& operator=(const Container& that) { 41 | if (this != &that) { 42 | *pot = *(that.pot); 43 | } 44 | std::cout << "=(&)" << std::endl; 45 | return *this; 46 | } 47 | ~Container() { 48 | delete pot; 49 | std::cout << "~Container()" << std::endl; 50 | } 51 | }; 52 | 53 | Container pass(Container& c) { 54 | std::cout << "pass" << std::endl; 55 | return std::move(c); 56 | } 57 | 58 | int main(void) { 59 | Container c; 60 | for(int k = 0; k < 10; k += 1) { 61 | c = pass(c); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lab3/SmartPointer.h: -------------------------------------------------------------------------------- 1 | // SmartPointer.h 2 | #include 3 | #include 4 | #include 5 | 6 | class ControlBlock { 7 | public: 8 | uint32_t ref_count = 0; 9 | }; 10 | 11 | 12 | template 13 | class SmartPointer { 14 | static_assert(std::is_base_of::value, "You must use ControlBlock as a base class"); 15 | private: 16 | 17 | public: 18 | T& operator*(void) const { return *ptr; } 19 | T* operator->(void) const { return ptr; } 20 | 21 | SmartPointer(const SmartPointer& rhs) { copy(rhs); } 22 | 23 | SmartPointer& operator=(const SmartPointer& rhs) { 24 | if (this != &rhs) { 25 | destroy(); 26 | copy(rhs); 27 | } 28 | return *this; 29 | } 30 | 31 | template 32 | SmartPointer(const SmartPointer& rhs) { 33 | //static_assert(std::is_base_of::value, "cannot upcast smart pointers"); 34 | 35 | if (rhs.ptr == nullptr) { 36 | this->ptr = nullptr; 37 | return; 38 | } 39 | 40 | ptr = dynamic_cast(rhs.ptr); 41 | ptr->ControlBlock::ref_count += 1; 42 | } 43 | 44 | SmartPointer(T* obj = nullptr) { 45 | ptr = obj; 46 | if (obj) { 47 | ptr->ControlBlock::ref_count += 1; 48 | } 49 | } 50 | 51 | ~SmartPointer(void) { destroy(); } 52 | 53 | operator bool(void) const { return ptr; } 54 | 55 | private: 56 | T* ptr = nullptr; 57 | template 58 | friend class SmartPointer; 59 | 60 | void copy(const SmartPointer& rhs) { 61 | this->ptr = rhs.ptr; 62 | if (ptr) { 63 | ptr->ControlBlock::ref_count += 1; 64 | } 65 | } 66 | 67 | void destroy(void) { 68 | if (ptr) { 69 | ptr->ControlBlock::ref_count -= 1; 70 | if (ptr->ControlBlock::ref_count == 0) { 71 | delete ptr; 72 | } 73 | } 74 | } 75 | }; 76 | 77 | -------------------------------------------------------------------------------- /lab3/animals.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "LifeForm.h" 4 | #include "Algae.h" 5 | #include "Event.h" 6 | #include "Params.h" 7 | #include "Random.h" 8 | 9 | namespace epl { 10 | std::default_random_engine random_generator; 11 | std::function drand48 = std::bind(std::uniform_real_distribution{}, random_generator); 12 | } 13 | 14 | using namespace std; 15 | using namespace epl; 16 | const double Point::tolerance = 1.0e-6; 17 | 18 | bool LifeForm::testMode = false; 19 | void LifeForm::runTests(void) {} 20 | 21 | /* The Tick class creates an event every 1.00 time units 22 | * The event is used to add new Algae to the simulation and can 23 | * also be used to add debugging hooks if you need them 24 | */ 25 | class Tick { 26 | public: 27 | static void tock(void) { 28 | std::function callme = [](void) { tock(); }; 29 | #if ALGAE_SPORES 30 | Algae::create_spontaneously(); 31 | #endif /* ALGAE_SPORES */ 32 | if (Event::num_events() > 1) 33 | (void) new Event(1, callme); 34 | } 35 | }; 36 | 37 | void delay(void) { 38 | std::this_thread::sleep_for(std::chrono::milliseconds{ 10 }); 39 | new Event(1, &delay); 40 | } 41 | 42 | int main(int argc, char** argv) { 43 | double last_time = 0.0; 44 | double time_lapse; 45 | 46 | if (argc > 1) 47 | time_lapse = atof(argv[1]); 48 | else 49 | time_lapse = 1.0; 50 | 51 | LifeForm::create_life(); 52 | new Event(1, &delay); 53 | Tick::tock(); 54 | while (Event::num_events() > 0) { 55 | Event::do_next(); 56 | // periodically redisplay everything 57 | if (Event::now() - last_time > time_lapse) { 58 | last_time = Event::now(); 59 | LifeForm::redisplay_all(); 60 | } 61 | } 62 | 63 | cerr << "Simulation Complete, hit ^C to terminate program\n"; 64 | // sleep(1000); 65 | } 66 | -------------------------------------------------------------------------------- /lab3/Makefile: -------------------------------------------------------------------------------- 1 | # EPL: SP2015 2 | # LifeForm Makefile with FLTK support 3 | # Author: EPL TA 4 | 5 | # Mac OS X users please follow the instructions to setup FLTK. 6 | # 1. Install FLTK through MacPorts using the command: 7 | # sudo port install fltk 8 | # 9 | # 2. Change FLTK_DIR, FLTK_LIB, and LIBS of this Makefile: 10 | # FLTK_DIR=/opt/local 11 | # FLTK_LIB=$(FLTK_DIR)/lib/libfltk.a 12 | # LIBS = $(FLTK_LIB) -lm -ldl -lpthread -framework Cocoa 13 | # 14 | 15 | # For Manual Installation (e.g., Windows) 16 | FLTK_DIR=../../../examples/fltk 17 | # For MacPorts Installation (Mac OS X) 18 | # FLTK_DIR=/opt/local 19 | 20 | FLTK_INC=-I$(FLTK_DIR) 21 | 22 | #choose based on system 23 | FLTK_LIB=$(FLTK_DIR)/lib/fltk64.a #class virtual machine uses this 24 | #FLTK_LIB=$(FLTK_DIR)/lib/libfltk.a # Mac OS X + MacPorts uses this 25 | 26 | IFLAGS = 27 | DFLAGS = -DDEBUG=0 -DNO_WINDOW=0 -DSPECIES_SUMMARY=1 -DALGAE_SPORES=1 -DRANDOM=0 -DSLOWDOWN=0 -DUSE_GC=0 28 | CXX = g++ --std=c++11 $(FLTK_INC) 29 | CC = $(GCC) 30 | GCC = g++ --std=c++11 $(FLTK_INC) 31 | LD = $(CXX) 32 | 33 | LIBS = $(FLTK_LIB) -lX11 -lm -ldl -lpthread 34 | #LIBS = $(FLTK_LIB) -lm -ldl -lpthread -framework Cocoa # Mac OS X uses this 35 | 36 | WFLAGS = -Wall 37 | SYMFLAGS = -g 38 | 39 | PROFILE = #-pg 40 | OPTFLAGS =#-O 41 | CFLAGS = $(OPTFLAGS) $(PROFILE) $(WFLAGS) $(IFLAGS) $(SYMFLAGS) 42 | CXXFLAGS = $(CFLAGS) 43 | CPPFLAGS = $(IFLAGS) $(DFLAGS) 44 | LDFLAGS = $(PROFILE) -g 45 | 46 | PROGRAM = animals 47 | #CXXSRCS = LifeForm.cpp animals.cpp Window.cpp Event.cpp Algae.cpp \ 48 | Craig.cpp LifeForm-Craig.cpp Params.cpp Praveen.cpp Jerry.cpp 49 | 50 | CXXSRCS = $(shell ls *.cpp) 51 | CSRCS = 52 | 53 | SRCS = $(CXXSRCS) $(CSRCS) 54 | 55 | OBJS = $(CXXSRCS:.cpp=.o) $(CSRCS:.c=.o) 56 | 57 | all: $(PROGRAM) 58 | 59 | $(PROGRAM): $(OBJS) 60 | $(LD) $(LDFLAGS) -o $@ $(OBJS) yh7483.o bx522.o yl23394.o Yz7962.o Jeremy64.o $(LIBS) 61 | 62 | test: $(PROGRAM) 63 | ./$(PROGRAM) 64 | 65 | clean: 66 | -rm -f $(OBJS) $(PROGRAM) .*.d 67 | 68 | ifneq ($(strip $(CSRCS)),) 69 | .%.d: %.c 70 | $(SHELL) -ec '$(GCC) -MM $(CPPFLAGS) $< > $@' 71 | 72 | include $(CSRCS:%.c=.%.d) 73 | endif 74 | 75 | ifneq ($(strip $(CXXSRCS)),) 76 | .%.d: %.cpp 77 | $(SHELL) -ec '$(GCC) -MM $(CPPFLAGS) $< > $@' 78 | 79 | include $(CXXSRCS:%.cpp=.%.d) 80 | endif 81 | 82 | -------------------------------------------------------------------------------- /midterm/sp13_2.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // sp13_2.cpp 3 | // practice 4 | // 5 | // Created by Xingyuan Wang on 3/25/15. 6 | // Copyright (c) 2015 Engineering Programming Language. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | //template 14 | //string typeString(T) { return string("unknown type"); } 15 | 16 | class Foo { 17 | public: 18 | static string myType(void) { return string("Foo"); } 19 | }; 20 | 21 | class dFoo : public Foo { 22 | public: 23 | static string myType(void) { return string("dFoo"); } 24 | }; 25 | 26 | //template 27 | //string typeString(T t) { 28 | // string s{"pointer to "}; 29 | // s.append(typeString(*t)); 30 | // return s; 31 | //} 32 | 33 | 34 | template 35 | string typeString(T) { 36 | string s{T::myType()}; 37 | return s; 38 | } 39 | 40 | template 41 | string typeString(T* t) { 42 | string s{"pointer to "}; 43 | return s.append(typeString(*t)); 44 | } 45 | 46 | template 47 | string typeString(T** t) { 48 | string s{"pointer to pointer to"}; 49 | return s.append(typeString(**t)); 50 | } 51 | 52 | 53 | template <> string typeString(int) { return string("int"); } 54 | template <> string typeString(double) { return string("double"); } 55 | template <> string typeString(float) { return string("float"); } 56 | 57 | 58 | template 59 | void fun(const T& x) { 60 | string s = typeString(x); 61 | cout << "x is type: " << s << endl; 62 | } 63 | 64 | //template 65 | //bool isTemp(const T&) { 66 | // return false; 67 | //} 68 | 69 | template 70 | bool isTemp(T&) { 71 | return false; 72 | } 73 | 74 | template 75 | bool isTemp(T&&) { 76 | return true; 77 | } 78 | 79 | int main() { 80 | int a[3][5]; 81 | // int** a; 82 | fun(a); 83 | 84 | float b; 85 | fun(b); 86 | 87 | Foo foo; 88 | fun(foo); 89 | 90 | dFoo dfoo; 91 | Foo* p; 92 | p = &dfoo; 93 | fun(p); 94 | 95 | int x, y; 96 | int *q; 97 | 98 | cout << isTemp(42) << endl; 99 | cout << isTemp(x + y) << endl; 100 | cout << isTemp(new int) << endl; 101 | cout << isTemp(x) << endl; 102 | cout << isTemp(q) << endl; 103 | } 104 | 105 | 106 | -------------------------------------------------------------------------------- /lab3/Event.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "Params.h" 7 | #include "Event.h" 8 | 9 | using namespace std; 10 | 11 | SimTime Event::_now = 0; 12 | 13 | struct EventCompare { 14 | bool operator()(const Event* ep1, const Event* ep2) { 15 | return ep1->t > ep2->t; // backwards on purpose so that events 16 | // are processed in increasing order 17 | } 18 | }; 19 | 20 | class PQueue { 21 | vector V; 22 | public: 23 | PQueue(void) {} // normal construction 24 | ~PQueue(void); 25 | 26 | void insert(Event* e) { 27 | V.push_back(e); 28 | push_heap(V.begin(), V.end(), EventCompare()); 29 | } 30 | 31 | Event* pop_greatest(void) { 32 | pop_heap(V.begin(), V.end(), EventCompare()); 33 | Event* e = V.back(); 34 | V.pop_back(); 35 | return e; 36 | } 37 | 38 | 39 | /* 40 | * remove an event from the queue 41 | */ 42 | void remove(Event* e) { 43 | e->cancel(); 44 | } 45 | 46 | unsigned size(void) const { 47 | return V.end() - V.begin(); 48 | } 49 | }; 50 | 51 | /* delete all of the events */ 52 | PQueue::~PQueue() { 53 | /* this look relies on the events removing themselves from the queue */ 54 | /* it's slow, but it's simple (and who cares how fast it is, 55 | the program's over by now */ 56 | while (!V.empty()) { 57 | Event* e = V.front(); 58 | delete e; 59 | } 60 | } 61 | 62 | PQueue Event::equeue; 63 | 64 | 65 | Event::~Event() { 66 | assert(!in_queue); 67 | } 68 | 69 | /* 70 | * simulate until there are no more events to simulate 71 | */ 72 | void Event::do_next(void) { 73 | Event* e = equeue.pop_greatest(); 74 | e->in_queue = false; 75 | assert(e->t >= _now); 76 | _now = e->t; 77 | #if DEBUG 78 | cout << "doing event at time " << _now << endl; 79 | #endif /* DEBUG */ 80 | (*e)(); 81 | delete e; 82 | } 83 | 84 | unsigned Event::num_events(void) { 85 | return equeue.size(); 86 | } 87 | 88 | void Event::remove(void) { 89 | assert(in_queue); 90 | equeue.remove(this); 91 | in_queue = 0; 92 | } 93 | 94 | void Event::insert() { 95 | in_queue = true; 96 | assert(Event::_now <= t); 97 | equeue.insert(this); 98 | } 99 | 100 | 101 | /*void Event::delete_matching(void* p) 102 | { 103 | equeue.delete_matching(p); 104 | }*/ 105 | -------------------------------------------------------------------------------- /lab3/Craig.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "Craig.h" 7 | #include "CraigUtils.h" 8 | #include "Event.h" 9 | #include "ObjInfo.h" 10 | #include "Params.h" 11 | #include "Random.h" 12 | #include "Window.h" 13 | 14 | #ifdef _MSC_VER 15 | using namespace epl; 16 | #endif 17 | using namespace std; 18 | using String = std::string; 19 | 20 | Initializer __Craig_initializer; 21 | 22 | String Craig::species_name(void) const 23 | { 24 | return "Craig"; 25 | } 26 | 27 | Action Craig::encounter(const ObjInfo& info) 28 | { 29 | if (info.species == species_name()) { 30 | /* don't be cannibalistic */ 31 | set_course(info.bearing + M_PI); 32 | return LIFEFORM_IGNORE; 33 | } 34 | else { 35 | hunt_event->cancel(); 36 | SmartPointer self = SmartPointer(this); 37 | hunt_event = new Event(0.0, [self](void) { self->hunt(); }); 38 | return LIFEFORM_EAT; 39 | } 40 | } 41 | 42 | void Craig::initialize(void) { 43 | LifeForm::add_creator(Craig::create, "Craig"); 44 | } 45 | 46 | /* 47 | * REMEMBER: do not call set_course, set_speed, perceive, or reproduce 48 | * from inside the constructor!!!! 49 | * you must wait until the object is actually alive 50 | */ 51 | Craig::Craig() { 52 | SmartPointer self = SmartPointer(this); 53 | new Event(0, [self](void) { self->startup(); }); 54 | } 55 | 56 | Craig::~Craig() {} 57 | 58 | void Craig::startup(void) { 59 | set_course(drand48() * 2.0 * M_PI); 60 | set_speed(2 + 5.0 * drand48()); 61 | SmartPointer self = SmartPointer(this); 62 | hunt_event = new Event(0, [self](void) { self->hunt(); }); 63 | } 64 | 65 | void Craig::spawn(void) { 66 | SmartPointer child = new Craig; 67 | reproduce(child); 68 | } 69 | 70 | 71 | Color Craig::my_color(void) const { 72 | return RED; 73 | } 74 | 75 | SmartPointer Craig::create(void) { 76 | return new Craig; 77 | } 78 | 79 | 80 | void Craig::hunt(void) { 81 | const String fav_food = "Algae"; 82 | 83 | hunt_event = nullptr; 84 | if (health() == 0.0) { return; } // we died 85 | 86 | ObjList prey = perceive(20.0); 87 | 88 | double best_d = HUGE; 89 | for (ObjList::iterator i = prey.begin(); i != prey.end(); ++i) { 90 | if ((*i).species == fav_food) { 91 | if (best_d > (*i).distance) { 92 | set_course((*i).bearing); 93 | best_d = (*i).distance; 94 | } 95 | } 96 | } 97 | 98 | SmartPointer self = SmartPointer(this); 99 | hunt_event = new Event(10.0, [self](void) { self->hunt(); }); 100 | 101 | if (health() >= 4.0) spawn(); 102 | } 103 | -------------------------------------------------------------------------------- /lab3/Event.h: -------------------------------------------------------------------------------- 1 | #if !(_Event_h) 2 | #define _Event_h 1 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "Params.h" 9 | #include "SimTime.h" // for the SimTime class 10 | 11 | /* necessary forward reference */ 12 | class PQueue; 13 | 14 | /* 15 | * Class name: Event 16 | * Class characterization: Abstract base class 17 | * virtual functions: operator() 18 | * Description: 19 | * An event is something that happens at a specific time 20 | * Events can be compared (comparison is defined over the time at 21 | * which they occur). < and == are defined. 22 | * and events can be applied (via () ). 23 | * There are no arguments allowed when applying an event. 24 | * There is no return value (or the return value is ignored 25 | * 26 | * Recommended Usage: Simulation 27 | * Derive templatized classes from Event. 28 | * make a priority queue (e.g. heap) that contains pointers to 29 | * Events (instances of the derived classes). 30 | * 31 | * Implementation: 32 | * We rely on a class "SimTime" to exist. Most probably SimTime is a typedef 33 | * to either int or double. 34 | * If SimTime does not support operator =, then you must comment out the 35 | * operator = for class Event. 36 | * 37 | */ 38 | class Event { 39 | private: 40 | SimTime t; 41 | using Handler = std::function; 42 | Handler doit; 43 | static PQueue equeue; // a priority queue of all events 44 | static SimTime _now; 45 | bool in_queue; 46 | 47 | /* Implementation NOTE: 48 | If you inline these, you need to include the definition of PQueue 49 | in every file that includes Event.h... Since PQueue is based 50 | on templates, this is very expensive... (compiling is slow) 51 | so, I choose not to inline them */ 52 | void insert(void); // insert this event into the priority queue 53 | void remove(void); // remove this event from the priority queue 54 | bool active; 55 | 56 | public: 57 | /* interface */ 58 | void operator()(void) { if (active) { doit(); } } 59 | 60 | static SimTime now(void) { return _now; } 61 | static unsigned num_events(void); // the total number of events in the world 62 | static void do_next(void); // process the next event 63 | 64 | 65 | /* constructors and destructors */ 66 | Event(SimTime delta_time, Handler f) : doit(f) { 67 | if (delta_time < min_delta_time) delta_time = min_delta_time; 68 | t = _now + delta_time; 69 | active = true; 70 | insert(); 71 | } 72 | ~Event(void); 73 | 74 | void cancel(void) { if (this) active = false; } 75 | bool is_active(void) const { return this && active; } 76 | 77 | private: 78 | /* assignment and copying are forbidden in Events */ 79 | Event(const Event& e) = delete; 80 | void operator=(const Event&) = delete; 81 | 82 | /* The EventCompare class is used in Event.cc to implement the Event Queue */ 83 | friend struct EventCompare; 84 | }; 85 | 86 | #endif /* !(_Event_h) */ 87 | -------------------------------------------------------------------------------- /lab2/README.md: -------------------------------------------------------------------------------- 1 | 2 | Project2. Valarray with Expression Templates 3 | ------------------------------------------------ 4 | This project is to implement the container epl::valarray. A valarray is essentially a vector that contains values , i.e., types that have the arithmetic operators defined. 5 | 6 | ###Features: 7 | 1. Arithmetic operations are valid. That is, it is possible to add two valarrays, and the result should (at least conceptually) be another valarray. 8 | 2. Lazy evaluation of expressions (using expression templates) are requred. 9 | 3. A result of the appropriate type is provided when valarrays with different element types are used. 10 | 11 | ###Function Lists: 12 | 1. push_back--inherited 13 | 2. pop_back--inherited 14 | 3. operator[] -- inherited 15 | 4. appropriate iterator and const_iterator classes (and begin/end functions) -- inherited 16 | 5. the binary operators *,/,-,+ 17 | 6. a unary - (arithmetic negation) 18 | 7. all necessary functions to convert from one valarray type to another 19 | 8. a constructor that takes an initial size -- inherited 20 | 9. a sum() function that adds all elements in the valarray using standard addition 21 | 10. an accumulate function that adds all elements in the valarray using the given function object 22 | 11. an apply member function that takes a unary function argument and returns (conceptually) a new valarray where the function has been applied to each element in the valarray. Of course, this apply method must follow all the rules for lazy evaluation (i.e., it won’t return a real valarray, but rather some sort of expression template). 23 | 12. a sqrt member function that is implemented by passing a sqrt function object to the apply member function. The element type created from sqrt will either be double (for input valarrays that were int, float or double originally), or will be std::complex\ for valarrays that were originally std::complex\ or std::complex\ originally. 24 | 25 | ###General Notes: 26 | 1. The statement: z = x op y should set z[k] = x[k] op y[k] for all k and for any binary operator op. A reasonable subset of the binary and unary operators must be supported. 27 | 2. If the two operands are of differing length, the length of the result should be the minimun of the lengths of the two operands (ignore values past the end of the longer operand). 28 | 3. If one of the operands is a scalar, you should add (or whatever operation is implied) that scalar value to each of the elements in the valarray. In other words, you should implicitly expand the scalar to be a valarray of the appropriate length. But DON'T actually create this implied valarray. 29 | 4. If x,y,z,w are valarrays, optimize the execution of statements like z = ( x * y ) + w so that only one loop gets executed and no temporary arrays are allocated. 30 | 5. Type promotion should be to the strictest type acceptable for the operation to occur – e.g., if a valarray\ is added to a complex\ the result should be a valarray\\>. If a valarray is added to a complex\ then the result should be a valarray\\>. 31 | 32 | Here is how I implemented [Valarray.h](./Valarray.h). 33 | -------------------------------------------------------------------------------- /lab3/Point.h: -------------------------------------------------------------------------------- 1 | #if !(_Point_h) 2 | #define _Point_h 1 3 | 4 | #include 5 | 6 | #ifndef HUGE /* a useful constant (a large floating point number) */ 7 | # define HUGE MAXFLOAT 8 | #endif /* HUGE */ 9 | 10 | #ifndef M_PI 11 | # define M_PI ((double) 3.1415926535897932) 12 | #endif 13 | 14 | class Point { 15 | 16 | public: 17 | static const double tolerance; 18 | 19 | double xpos, ypos; 20 | Point(void); 21 | Point(const Point& p); 22 | Point(double,double); 23 | Point& operator=(const Point& p); 24 | Point operator+(const Point& p) const; 25 | Point& operator+=(const Point& p); 26 | Point& operator-=(const Point& p); 27 | Point& operator*=(double s); 28 | Point& operator/=(double s); 29 | bool operator==(const Point& p) const; 30 | bool operator!=(const Point& p) const { return !operator==(p); } 31 | double distance(const Point& p) const; 32 | double bearing(const Point& p) const; // the direction from 'this' to 'p' 33 | }; 34 | 35 | inline 36 | Point& Point::operator=(const Point& p) 37 | { 38 | xpos = p.xpos; 39 | ypos = p.ypos; 40 | return *this; 41 | } 42 | 43 | inline 44 | Point::Point(const Point& p) { xpos = p.xpos; ypos = p.ypos; } 45 | 46 | inline 47 | Point::Point(void) { xpos = ypos = 0.0; } 48 | 49 | inline 50 | Point::Point(double x, double y) { xpos = x; ypos = y; } 51 | 52 | inline 53 | double Point::distance(const Point& p) const 54 | { 55 | double xdist = (xpos - p.xpos); 56 | double xdist_sqrd = xdist*xdist; 57 | 58 | double ydist = (ypos - p.ypos); 59 | double ydist_sqrd = ydist*ydist; 60 | 61 | return sqrt(xdist_sqrd + ydist_sqrd); 62 | } 63 | 64 | inline 65 | Point Point::operator+(const Point& p) const 66 | { 67 | Point temp(xpos, ypos) ; 68 | temp += p ; 69 | return temp; 70 | } 71 | 72 | inline 73 | Point& Point::operator+=(const Point& p) 74 | { 75 | xpos += p.xpos; 76 | ypos += p.ypos; 77 | return *this; 78 | } 79 | 80 | inline 81 | Point& Point::operator-=(const Point& p) 82 | { 83 | xpos -= p.xpos; 84 | ypos -= p.ypos; 85 | return *this; 86 | } 87 | 88 | inline 89 | Point& Point::operator*=(double s) 90 | { 91 | xpos *= s; 92 | ypos *= s; 93 | return *this; 94 | } 95 | 96 | inline 97 | Point& Point::operator/=(double s) 98 | { 99 | xpos /= s; 100 | ypos /= s; 101 | return *this; 102 | } 103 | 104 | inline 105 | bool Point::operator==(const Point& p) const 106 | { 107 | return distance(p) < tolerance; 108 | } 109 | 110 | inline 111 | double Point::bearing(const Point& p) const 112 | { 113 | assert(*this != p); 114 | double del_x = p.xpos - xpos; 115 | double del_y = p.ypos - ypos; 116 | if (fabs(del_y) <= fabs(1.0e-10 * del_x)) { // delta y is essentially 0 117 | if (del_x > 0.0) return 0.0; 118 | else return M_PI; 119 | } 120 | else { /* atan returns the correct result if delta x is positive */ 121 | if (del_x > 0.0) 122 | return atan(del_y / del_x); 123 | else 124 | return atan(del_y / del_x) + M_PI; 125 | } 126 | } 127 | 128 | 129 | /* NOTE: this ifdef is correct only for g++. 130 | This is an implementation-dependent hack */ 131 | #ifdef _IOSTREAM_H 132 | inline 133 | ostream& operator<<(ostream& ost, const Point& p) 134 | { 135 | ost << "(" << p.xpos << "," << p.ypos << ")"; 136 | return ost; 137 | } 138 | #endif /* _IOSTREAM_H */ 139 | 140 | #endif /* !(_Point_h) */ 141 | -------------------------------------------------------------------------------- /lab3/Praveen.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | Praveen Yalagandula 3 | Amit K Muraleedharan 4 | **************************************************/ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "CraigUtils.h" 10 | #include "Params.h" 11 | #include "Event.h" 12 | #include "ObjInfo.h" 13 | #include "Random.h" 14 | #include "Praveen.h" 15 | #include "Window.h" 16 | 17 | #if defined (_MSC_VER) 18 | using namespace epl; 19 | #endif 20 | using namespace std; 21 | using String = std::string; 22 | 23 | Initializer __Praveen_initializer; 24 | 25 | //int Praveen::total_num = 0 ; // sorry, no statics allowed 26 | 27 | String Praveen::species_name(void) const 28 | { 29 | return "Praveen"; 30 | } 31 | 32 | Action Praveen::encounter(const ObjInfo& info) 33 | { 34 | if (info.species == species_name()) { 35 | /* don't be cannibalistic */ 36 | set_course(info.bearing + M_PI); 37 | return LIFEFORM_IGNORE; 38 | } 39 | else { 40 | hunt_event->cancel(); 41 | SmartPointer me{this}; 42 | hunt_event = new Event(0.0, [me] (void) { me->hunt(); }); 43 | return LIFEFORM_EAT; 44 | } 45 | } 46 | 47 | void Praveen::initialize(void) 48 | { 49 | LifeForm::add_creator(Praveen::create, "Praveen"); 50 | } 51 | 52 | /* 53 | * REMEMBER: do not call set_course, set_speed, perceive, or reproduce 54 | * from inside the constructor!!!! 55 | * you must wait until the object is actually alive 56 | */ 57 | Praveen::Praveen() 58 | { 59 | hunt_event = Nil(); 60 | SmartPointer me{this}; 61 | (void) new Event(0.0, [me] (void) { me->live();}); 62 | } 63 | 64 | 65 | Praveen::~Praveen() 66 | { 67 | } 68 | 69 | void Praveen::spawn(void) 70 | { 71 | Praveen* child = new Praveen; 72 | reproduce(child); 73 | } 74 | 75 | 76 | Color Praveen::my_color(void) const 77 | { 78 | return CYAN; 79 | } 80 | 81 | LifeForm* Praveen::create(void) 82 | { 83 | Praveen* res = Nil(); 84 | res = new Praveen; 85 | res->display(); 86 | return res; 87 | } 88 | 89 | 90 | /* 91 | * this event is only called once, when the object is "born" 92 | * 93 | * I don't want to call "set_course" and "set_speed" from the constructor 94 | * 'cause OBJECTS ARE NOT ALIVE WHEN THEY ARE CONSTRUCTED (remember!) 95 | * so... in the constructor I schedule this event to happen in 0 time 96 | * units 97 | */ 98 | void Praveen::live(void) 99 | { 100 | set_course(drand48() * 2.0 * M_PI); 101 | set_speed(2 + 5.0 * drand48()); 102 | SmartPointer me{this}; 103 | hunt_event = new Event(5.0, [me] (void) { me->hunt();}); 104 | } 105 | 106 | void Praveen::hunt(void) 107 | { 108 | const String fav_food = "Algae"; 109 | 110 | hunt_event = Nil(); 111 | if (health() == 0) { return; } 112 | 113 | ObjList prey = perceive(40.0); 114 | 115 | double best_d = HUGE; 116 | int count = 0 ; 117 | for (ObjInfo i : prey) { 118 | count++ ; 119 | if (i.species == fav_food) { 120 | course_changed = 0 ; 121 | if (best_d > i.distance) { 122 | set_course(i.bearing); 123 | best_d = i.distance; 124 | } 125 | } 126 | } 127 | if(best_d == HUGE){ 128 | if(course_changed == 0){ 129 | course_changed = 1 ; 130 | set_course(get_course() + M_PI) ; 131 | } 132 | } 133 | SmartPointer me{this}; 134 | hunt_event = new Event(10.0, [me] (void) { me->hunt();}); 135 | 136 | if (health() >= 4.0) spawn(); 137 | } 138 | 139 | -------------------------------------------------------------------------------- /lab3/Window.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #if !(NO_WINDOW) 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #endif 12 | 13 | #if defined(_AIX) && !defined(XLC_IS_STUPID) && !defined(__GNUG__) 14 | #define XLC_IS_STUPID 15 | #include 16 | #endif /* _AIX */ 17 | 18 | #if DEBUG 19 | # include 20 | using namespace std; 21 | #endif /* DEBUG */ 22 | 23 | #include "Window.h" 24 | 25 | /* Allocate colors in an X color map and set them up. */ 26 | void Canvas::initcolor() 27 | { 28 | #if !(NO_WINDOW) 29 | 30 | color_map[BLACK] = FL_BLACK; 31 | color_map[GREEN] = FL_GREEN; 32 | color_map[CYAN] = FL_CYAN; 33 | color_map[MAGENTA] = FL_MAGENTA; 34 | color_map[RED] = FL_RED; 35 | color_map[ORANGE] = fl_rgb_color(255, 165, 0); 36 | color_map[YELLOW] = FL_YELLOW; 37 | 38 | #endif /* !(NO_WINDOW) */ 39 | } 40 | 41 | /* 42 | Set up the mapping of color numbers into monochrome values. 43 | Change the raster operations to the logically opposite functions 44 | if black is pixel #1. 45 | */ 46 | unsigned int Canvas::initmono(void) 47 | { 48 | color_map[BLACK] = FL_BLACK; 49 | for (int i = 1; i < 8; i++) 50 | color_map[i] = FL_WHITE; 51 | return 0; 52 | } 53 | 54 | /* 55 | Main procedure: initialize X display, set up monochrome or color 56 | mapping, create a window, wait for it to be mapped, draw rectangles 57 | in various forms, and exit. 58 | */ 59 | Canvas::Canvas(int w, int h) : width(w), height(h) 60 | { 61 | #if !(NO_WINDOW) 62 | 63 | window = new Fl_Double_Window(w, h, "LifeForm Simulation"); 64 | initcolor(); 65 | 66 | #endif /* !(NO_WINDOW) */ 67 | } 68 | 69 | void Canvas::display(void) 70 | { 71 | #if !(NO_WINDOW) 72 | 73 | window->color(FL_BLACK); 74 | window->show(); 75 | Fl::wait(0); 76 | 77 | #endif 78 | } 79 | 80 | 81 | void Canvas::set_color(Color x) 82 | { 83 | #if !(NO_WINDOW) 84 | 85 | color = x; 86 | 87 | #endif 88 | } 89 | 90 | int point_size = 3; 91 | void Canvas::draw_point(int x, int y) 92 | { 93 | draw_rectangle(x, y, x + point_size, y + point_size, true); 94 | } 95 | 96 | void Canvas::flush(void) 97 | { 98 | #if !(NO_WINDOW) 99 | 100 | #if defined (__APPLE__) 101 | Fl::flush(); 102 | #else 103 | Fl::wait(); 104 | #endif 105 | 106 | #endif 107 | } 108 | 109 | 110 | void Canvas::draw_rectangle(int x1, int y1, int x2, int y2, bool fill) 111 | { 112 | #if !(NO_WINDOW) 113 | 114 | Fl_Box *box; 115 | if (fill) { 116 | box = new Fl_Box(x1, y1, (x2 - x1), (y2 - y1)); 117 | box->color(color_map[color]); 118 | box->box(FL_FLAT_BOX); 119 | } 120 | else { 121 | box = new Fl_Box(x1, y1, (x2 - x1), (y2 - y1)); 122 | box->color(color_map[color]); 123 | box->box(FL_BORDER_FRAME); 124 | } 125 | window->add(box); 126 | box->redraw(); 127 | 128 | #endif /* !(NO_WINDOW) */ 129 | } 130 | 131 | class DrawLine : public Fl_Widget { 132 | public: 133 | DrawLine(int X, int Y, int W, int H, const char*L = 0) : Fl_Widget(X, Y, W, H, L) { 134 | } 135 | void draw() { 136 | // DRAW BLACK 'X' 137 | fl_color(FL_BLACK); 138 | int x1 = x(), y1 = y(); 139 | int x2 = x() + w() - 1, y2 = y() + h() - 1; 140 | fl_line(x1, y1, x2, y2); 141 | fl_line(x1, y2, x2, y1); 142 | } 143 | }; 144 | void Canvas::draw_line(int x1, int y1, int x2, int y2) 145 | { 146 | #if !(NO_WINDOW) 147 | 148 | DrawLine drawLine(x1, y1, x2, y2); 149 | window->add(drawLine); 150 | drawLine.redraw(); 151 | 152 | #endif /* !(NO_WINDOW) */ 153 | } 154 | 155 | 156 | void Canvas::clear(void) 157 | { 158 | #if !(NO_WINDOW) 159 | 160 | set_color(BLACK); 161 | draw_rectangle(0, 0, width, height, true); 162 | 163 | #endif /* !(NO_WINDOW) */ 164 | } 165 | -------------------------------------------------------------------------------- /quiz1/Quiz1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Quiz1.h 3 | * 4 | * Created on: Mar 11, 2015 5 | * Author: chase 6 | */ 7 | 8 | #ifndef QUIZ1_H_ 9 | #define QUIZ1_H_ 10 | 11 | namespace epl_quiz1 { 12 | 13 | template 14 | struct assignment; 15 | 16 | /* the IntExpr is a simple wrapper that promotes an integer literal (or constant) 17 | * into something that can appear on the right-hand-side of an assignment 18 | * For example _X = 42 19 | * the 42 is an int, the assignment operator for a Var converts the 42 into an IntExpr 20 | * and returns an assignment struct. 21 | * Having a IntExpr wrapper allows us to generalize to more complicated right-hand-sides 22 | * like _X = _Y + _Z 23 | * where the right hand side is some kind of an expression, i.e., something that has 24 | * an operator() that we can call 25 | * This description will make more sense when you look at the assignment struct 26 | */ 27 | struct IntExpr { 28 | int val; 29 | IntExpr(int v) : val{v} {} 30 | int operator()(void) { return val; } 31 | }; 32 | 33 | struct Var { 34 | int val; 35 | 36 | template 37 | assignment operator=(Expr e); 38 | 39 | assignment operator=(int e); 40 | 41 | /* this operator makes it possible to print a Var, e.g., 42 | * cout << _X will work. My Print functionality relies on this capability 43 | * If you re-implement Print or provide an equivalent capability, you can 44 | * eliminate this conversion operator 45 | */ 46 | operator int(void) const { return val; } 47 | }; 48 | 49 | template 50 | struct assignment { 51 | Var& var; 52 | Expr e; 53 | 54 | assignment(Var& v, Expr ex) : var{v}, e{ex} {} 55 | void operator()(void) { 56 | var.val = e(); 57 | } 58 | }; 59 | 60 | template 61 | assignment Var::operator=(Expr e) { 62 | return assignment{*this, e}; 63 | } 64 | 65 | assignment Var::operator=(int v) { 66 | return assignment{*this, v}; 67 | } 68 | 69 | Var _X{}, _Y{}, _Z{}; 70 | 71 | 72 | /* this is the functionality I used for Print 73 | * You are not required to use this implementation. 74 | * 75 | * Please note that the functionality below is not sufficient to 76 | * print expressions. For example 77 | * Print(_X + _Y) 78 | * will not work in my solution (and is not required for Quiz1) 79 | * However, I can do 80 | * _Z = _X + _Y, Print(_Z) 81 | * 82 | */ 83 | // Here print is a proxy. 84 | template 85 | struct print { 86 | T x; 87 | // Why here using const&? 88 | print(T const& _x) : x{_x} {} 89 | void operator()(void) { cout << x << endl; } 90 | }; 91 | 92 | /* simple Prints like Print(42) */ 93 | template 94 | print Print(const T& v) { return print{v}; } 95 | 96 | /* special overload for Var because Var must be captured by reference 97 | * -- if we make a copy of the Var won't be able to see when the original variable 98 | * is changed via an assignment 99 | */ 100 | inline print Print(Var& v) { return print{v}; } 101 | 102 | /* special overload for const char* because of some C++ obscurity that doesn't 103 | * like deducing T as const char when given an argument like "Hello World" 104 | * If you're curious what the problem is, comment out this overload and try 105 | * to compile part A of the quiz 106 | */ 107 | print Print(char const* v) { return print{v}; } 108 | 109 | /* End functionality for Print */ 110 | 111 | template 112 | struct program; 113 | 114 | template 115 | struct program> { 116 | print _val; 117 | program(print val) : _val(val) {} 118 | void operator()(void) { 119 | _val(); 120 | } 121 | }; 122 | 123 | template 124 | struct program { 125 | T _val; 126 | program _rest; 127 | program(const T& val, const Tails&... rest): _val{val}, _rest{rest...} {} 128 | void operator()(void) { 129 | _val(); 130 | _rest(); 131 | } 132 | }; 133 | 134 | 135 | template 136 | program Program(const T& t) { return program(t); } 137 | 138 | 139 | template 140 | program Program(const Args&... args) { 141 | return program(args...); 142 | } 143 | 144 | } // end namespace epl_quiz1 145 | 146 | #endif /* QUIZ1_H_ */ 147 | -------------------------------------------------------------------------------- /lab1/README.md: -------------------------------------------------------------------------------- 1 | 2 | Project1. Vector Container Basics and Extensions 3 | ------------------------------------------------ 4 | ###Part1 - Basics 5 | 6 | This project is to implement the container vector. A vector is a data structure that provides O(1) random access (via an operator[]), and amortized constant append (via push_back). Our vector differs from the standard library vector in three minor ways. We are not required to implement all of the C++ standard functions, our operator[] performs bounds checking, and we have to implement a “push_front” and “pop_front”. 7 | 8 | ####Method List: 9 | 10 | - vector(void) – creates an array with some minimum capacity (8 is fine) and length equal to zero. Must not use T::T(void). In fact, as long as Vector::Vector(int) is not called, we shall never use T::T(void) 11 | - explicit Vector(uint64_t n) – create an array with capacity and length exactly equal to n. Initialize the n objects using T::T(void). As a special case, if n is equal to zero, you can duplicate the behavior of vector(void). 12 | - copy and move constructors for vector\ arguments 13 | - copy and move assignment operators for vector\ arguments 14 | - destructor 15 | - uint64_t size(void) const – return the number of constructed objects in the vector 16 | - T& operator[](uint64_t k) – if k is out of bounds (equal to or larger than length), then we will throw std::out_of_range(“subscript out of range”). If k is in bounds, then we return a reference to the element at position k 17 | - const T& operator[](uint64_t k) const – same as above, except for constants. 18 | - void push_back(const T&) – add a new value to the end of the array, using amortized doubling if the array has to be resized. Copy construct the argument. 19 | - void push_back(T&&) – same as above, but move construct the argument. 20 | - void push_front(const T&) and void push_front(T&&) -- similar to push_back, but add the element to the front of the Vector 21 | - void pop_back(void) and (B) void pop_front(void) – if the array is empty, throw a std::out_of_range exception (with any reasonable string error message you want). Otherwise, destroy the object at the end (or beginning) of the array and update the length. This action will not reallocate storage, even if the vector becomes empty. It is possible that a vector can have available capacity at both the front and back simultaneously. 22 | 23 | ####Note: 24 | 25 | 1. We implement amortized doubling whenever we increase the allocated space of your vector. 26 | 2. If a call to pop_back succeeds (does not throw an exception) and is followed immediately by a call to push_back, then we will not perform any memory allocations. More generally, if two or more consecutive calls to pop_back succeed and are followed by an equal number of calls to push_back, then no allocations are performed. Similarly if one or more successive calls to pop_front succeed and are followed immediately by an equal number of push_front calls, then no memory allocations are performed. 27 | 28 | 29 | ###Part2 - Extensions 30 | 31 | In this project we are asked to add some new functionality to our Vector\ template class, making it more compliant with the C++ standard, and applying some of the additional knowledge we’ve gained about templates. 32 | 33 | ####Requirement: 34 | 35 | - Create a random-access iterator type for our Vector. 36 | - Write an emplace_back variadic member template function for our vector that constructs the object in place. 37 | - Create a member template constructor that takes an iterator pair b and e and initializes the Vector to contain copies of the values from [b, e). 38 | - Create a constructor that will initialize a Vector from a std::initializer_list\ 39 | 40 | ####Note: 41 | 1. For iterators, specific requirements are as follows 42 | 43 | - Provide begin/end fuctions for our Vector. 44 | - Provide both iterator and const_iterator (and begin/end for each). 45 | - Ensure that an iterator can be converted (without warnings or type casts) to const_iterator. 46 | - Ensure that const_iterator cannot be converted to iterator. 47 | - Design our iterator so that it throws the exception epl::invalid_iterator whenever the value of an invalid iterator is used. “Using the value” of an iterator includes comparison operations (with other iterators), dereferencing the iterator, incrementing the iterator, etc. Assigning to an iterator, for example, is not “using the value” of the iterator, it is assigning a new value to the iterator (and should not throw an exception). 48 | - epl::invalid_iterator has three severity levels: (a) If the iterator references a position that no longer exists (i.e., the old position is out-of-bounds), the exception you throw must use the level SEVERE. (b) If the iterator reference a position that is in-bounds, but the memory location for that position may have been changed (e.g., a reallocation has been performed because of a push_back, or a new assignment has been performed to the Vector), then the exception you throw must have the level MODERATE. (c) If the iterator is invalidated for any other reason, the exception must have the level MILD. 49 | 50 | Here is how I implemented [Vector.h](./Vector.h). 51 | -------------------------------------------------------------------------------- /lab3/Params.cpp: -------------------------------------------------------------------------------- 1 | #include "Params.h" 2 | 3 | /* 4 | * any time you successfully eat something, you pay this cost 5 | * NOTE: if the object you eat has 5 energy (or less) then you'll 6 | * lose energy by trying to eat them 7 | */ 8 | double eat_cost_function(double, double) 9 | { 10 | return 5.0; 11 | } 12 | 13 | /* 14 | * if you attempt to eat an object, then your probability of success 15 | * is determined by this function. 16 | * e1 is the energy of the eater 17 | * e2 is the energy of the food 18 | * 19 | * NOTE: if I'm trying to eat you, you can also try to eat me. 20 | * the simulator must ensure that we both don't succeed 21 | * One way to do this, is to choose one LifeForm and let it attempt 22 | * to eat the other. If it fails, you can allow the food to try and be 23 | * the eater. 24 | */ 25 | double eat_success_chance(double e1, double e2) 26 | { 27 | return std::max(.10, e1 / (e1 + e2)); 28 | } 29 | 30 | /* time between when you eat and when you get the energy */ 31 | const SimTime digestion_time = 5.0; 32 | 33 | /* If you eat an object with E energy, then after digestion you gain 34 | eat_efficiency * E more energy */ 35 | const double eat_efficiency = 0.95; 36 | 37 | /* the amount of energy a life form starts with */ 38 | const double start_energy = 100.0; 39 | 40 | /* 41 | * it costs energy to exist, stationary, isolated objects eventually die 42 | * you should schedule an event every age_frequency time units 43 | * the event should subtract age_penalty units of energy from the LifeForm 44 | * if the energy drops below min_energy, the LifeForm should die 45 | */ 46 | const double age_penalty = 10; 47 | const double age_frequency = 100; // 0.1 unit of energy per unit time 48 | 49 | /* whether you eat or not, you take a penalty for colliding */ 50 | const double encounter_penalty = 5.0; 51 | 52 | /* the cost to move is non-linear */ 53 | double movement_cost(double speed, double time) 54 | { 55 | return 0.01 * pow(speed, 1.5) * time; 56 | } 57 | 58 | 59 | /* all life forms must have at least this much energy, or they die */ 60 | const double min_energy = 1.0 + eat_cost_function(1.0, 1.0); 61 | 62 | /* 63 | * when a LifeForm reproduces, the child must be placed no further than 64 | * reproduce_dist units away. 65 | * The child should be given 1/2 the energy of the parent 66 | * and then both child and parent should be charged the reproduce_cost 67 | * NOTE: reproduce cost is a percentage, so the penalty 68 | * is energy * reproduce_cost 69 | */ 70 | const double reproduce_dist = 5.0; 71 | const double reproduce_cost = 0.05; // a fraction 72 | const double min_reproduce_time = 1.0; 73 | /* 74 | * Algae gain energy automatically 75 | * Every algae_photo_time time units, an Algae gains Algae_energy_gain 76 | * units of energy 77 | */ 78 | const double Algae_energy_gain = 2.0; 79 | const SimTime algae_photo_time = 5.0; 80 | 81 | /* 82 | * two objects whos' centers are encounter_distance away (or closer) 83 | * are considered to have collided. 84 | * you are required to eventually simulate a collision when objects move 85 | * towards each other 86 | * 87 | * you do not need to simulate a collision everytime objects are close 88 | * if you miss collisions because objects to not cross boundaries in the 89 | * QuadTree, that is OK. 90 | * BUT if two objects move towards each other, and do not eat each other 91 | * and continue to move towards each other, you must simulate enough 92 | * events so that the objects eventually die (from the encounter_penalty 93 | * being applied over and over again) 94 | * 95 | * You must also correctly simulate the case that two objects move 96 | * towards each other, collide once, and then turn and go opposite 97 | * directions. (this case is very hard, solve it last) 98 | */ 99 | const double encounter_distance = 1.0; 100 | 101 | /* 102 | * every time an object attempts to look around, it should be assessed this 103 | * penalty. 104 | */ 105 | 106 | double perceive_cost(double radius) { 107 | return radius / 20.0; 108 | } 109 | 110 | /* objects must not be permitted to move faster than max_speed 111 | * if they do, then their speed should be set to max_speed (do not 112 | * kill them for trying) 113 | */ 114 | const double max_speed = 10.0; 115 | 116 | /* objects should not be permitted to percieve more than max_perceive_range 117 | * or perceive less than min_percieve_range. 118 | * If they do, adjust their perceive range to the appropriate bound 119 | * (do not kill them for trying) 120 | */ 121 | const double max_perceive_range = 100.0; 122 | const double min_perceive_range = 2.0; 123 | 124 | const int grid_max = 500; 125 | const int win_x_size = 500; 126 | const int win_y_size = 500; 127 | 128 | const double min_delta_time = 1.0e-6; // minimum time between scheduling an 129 | // event and when that event can occur 130 | 131 | /* 132 | * You may ignore the parameters after this line. Just extra 133 | * stuff I added to the solution 134 | */ 135 | 136 | /* 137 | * set your encounter resolution strategy here. Only affects the 138 | * case where both objects want to eat each other and both objects 139 | * "succeed" 140 | */ 141 | //const EncounterResolver encounter_strategy = FASTER_GUY_WINS; 142 | //const EncounterResolver encounter_strategy = EVEN_MONEY; 143 | const EncounterResolver encounter_strategy = BIG_GUY_WINS; 144 | 145 | const SimulationTerminationStrategy termination_strategy = 146 | // RUN_TILL_ONE_SPECIES_LEFT; 147 | // RUN_TILL_HALF_EXTINCT; 148 | RUN_TILL_EVENTS_EXHAUSTED; // probably runs forever, Algae Spores 149 | -------------------------------------------------------------------------------- /quiz1/Source.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Source.cpp 3 | * 4 | * Created on: Mar 11, 2015 5 | * Author: chase 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using std::cout; 12 | using std::cin; 13 | using std::endl; 14 | 15 | #include "Quiz1.h" 16 | 17 | using namespace epl_quiz1; 18 | 19 | /* 20 | * This quiz gradually increases the complexity required to build 21 | * a "programming language" interpreter using techniques similar to 22 | * expression templates. 23 | * 24 | * The examples in this quiz use a very small subset of a reasonable interpreter. 25 | * On a larger scale, the expression templates might support something like this: 26 | * 27 | * auto my_prog = Program(_X = 1, _Y = 1 28 | * While(_X < 10, 29 | * Print(_Y), 30 | * _X = _X + 1, 31 | * _Y = _Y * _X 32 | * ) 33 | * ) 34 | * 35 | * the statement above would create a variable called "prog", that variable is a function 36 | * object that we can run. When the function object is executed, this particular 37 | * function would print out the first 10 values of N! (factorial) 38 | * 39 | * prog(); // prints the first ten factorial numbers 40 | * 41 | * OK, so that's the concept for this quiz. We are keeping the examples simple for 42 | * your implementation. I'm also providing some starter code that you should consider 43 | * using in your solution. If you use the stater code, then I am likely to understand what 44 | * you are trying to do. If you do not use my starter code, then I may not understand 45 | * what you are trying to do, and if what you are trying to do fails, I may not be able 46 | * to give any partial credit for your attempt. 47 | * 48 | * Write code to solve parts A through D below. Put your solution in Quiz1.h 49 | * while you can make changes to this file, any changes you make to this file, 50 | * and any other files you create, will be ignored. Only your Quiz1.h file will be 51 | * evaluated. 52 | * 53 | * For partial credit, your solution does not need to compile. 54 | * 55 | * YOU WILL NEED TO COMMENT OUT PARTS B-D WHEN YOU FIRST START WORKING ON PART A 56 | * IF YOU WANT PART A TO COMPILE 57 | * 58 | * A correct solution compiles and runs all four parts (part A through part D) 59 | */ 60 | 61 | 62 | /* 63 | * For PartA you must demonstrate lazy evaluation 64 | * The function below reads input from the keyboard. The function must 65 | * print "Hello World" if and only if "y" is entered on the keyboard 66 | */ 67 | void partA(void) { 68 | // Print("Hello World"): return print, here T is const char *; 69 | auto prog = Program( 70 | Print("Hello World") 71 | ); 72 | 73 | cout << "do you want to run program A? (y/n)"; 74 | char c; 75 | cin >> c; 76 | // Victor: 77 | // The class that object prog belongs to has a overload operator(). When triggered, it will 78 | // print out the contents stored 79 | if (c == 'y') { prog(); } 80 | } 81 | 82 | /* 83 | * PartB requires that you develop a solution for multi-statement programs 84 | * There are at least two reasonable approaches to this problem. 85 | * Method 1) use expression templates and overload the "," (comma) operator 86 | * Method 2) use variadic templates (e.g., typename...) 87 | * 88 | * Select one of these methods (or develop your own) that allows an arbitrary 89 | * number of statements to be part of a program. 90 | */ 91 | 92 | 93 | void partB(void) { 94 | auto prog = Program( 95 | Print("Line 1"), 96 | Print("Line 2"), 97 | Print("Line 3") 98 | ); 99 | 100 | cout << "do you want to run program B? (y/n)"; 101 | char c; 102 | cin >> c; 103 | if (c == 'y') { prog(); } 104 | } 105 | 106 | 107 | /* 108 | * Part C introduces variables, expressions and assignment statements 109 | * You'll find three placeholder global variables defined in quiz1.h you can 110 | * assume that these are the only variables that will be used (i.e., I'm not looking 111 | * for you to make a general solution for variables in this quiz). Hence there 112 | * will only be at most three variables in any program and those variables are 113 | * _X _Y and _Z 114 | * The partC function below only uses _X 115 | */ 116 | // _X is a var, _X = 42 returns assignment. This assignment object 117 | // has a val = 42 and a overloaded (), which will return its val. 118 | void partC(void) { 119 | auto prog = Program( 120 | _X = 42, 121 | Print(_X) // prints 42 122 | ); 123 | 124 | cout << "do you want to run program C? (y/n)"; 125 | char c; 126 | cin >> c; 127 | if (c == 'y') { prog(); } 128 | } 129 | 130 | /* partD extends partC slightly 131 | * In addition to using variables _X, _Y and _Z, partD uses expressions with 132 | * integer literals and expressions with two variables. 133 | * To keep your solution short and simple, you can assume the following about expressions 134 | * 1) the only expression operator you need to support is operator+ 135 | * 2) the left-hand-side operand will always be a variable 136 | * _X + 1 is legal 137 | * 1 + _X is not something you need to support 138 | * _X + _Y is legal 139 | * _X + _Y + 1 is not something you need to support 140 | * 3) as suggested above, you only need to support simple expressions with a single + 141 | */ 142 | 143 | void partD(void) { 144 | auto prog = Program( 145 | _X = 42, 146 | Print(_X), // prints 42 147 | _Y = _X + 1, 148 | Print(_Y), // prints 43 149 | _Z = _X + _X, 150 | Print(_Z) // prints 84 151 | ); 152 | 153 | cout << "do you want to run program D? (y/n)"; 154 | char c; 155 | cin >> c; 156 | if (c == 'y') { prog(); } 157 | } 158 | 159 | 160 | 161 | int main(void) { 162 | partA(); 163 | partB(); 164 | partC(); 165 | partD(); 166 | } 167 | 168 | -------------------------------------------------------------------------------- /lab3/Params.h: -------------------------------------------------------------------------------- 1 | #if !(_Params_h) 2 | #define _Params_h 1 3 | 4 | #include 5 | #include 6 | #define ALGAE_SPORES 1 7 | 8 | #if defined(_AIX) && !defined(XLC_IS_STUPID) && !defined(__GNUG__) 9 | #define XLC_IS_STUPID 10 | #endif /* _AIX */ 11 | 12 | #include "SimTime.h" 13 | 14 | /*****************************************************/ 15 | /* PLEASE SEE Params.cpp FOR ACTUAL PARAMETER VALUES */ 16 | /*****************************************************/ 17 | 18 | /* 19 | * any time you successfully eat something, you pay this cost 20 | * NOTE: if the object you eat has 5 energy (or less) then you'll 21 | * lose energy by trying to eat them 22 | */ 23 | double eat_cost_function(double notUsed0=0, double notUsed1=0); 24 | 25 | /* 26 | * if you attempt to eat an object, then your probability of success 27 | * is determined by this function. 28 | * e1 is the energy of the eater 29 | * e2 is the energy of the food 30 | * 31 | * NOTE: if I'm trying to eat you, you can also try to eat me. 32 | * the simulator must ensure that we both don't succeed 33 | * One way to do this, is to choose one LifeForm and let it attempt 34 | * to eat the other. If it fails, you can allow the food to try and be 35 | * the eater. 36 | */ 37 | double eat_success_chance(double e1, double e2); 38 | 39 | /* time between when you eat and when you get the energy */ 40 | extern const SimTime digestion_time; 41 | 42 | /* If you eat an object with E energy, then after digestion you gain 43 | eat_efficiency * E more energy */ 44 | extern const double eat_efficiency; 45 | 46 | /* the amount of energy a life form starts with */ 47 | extern const double start_energy; 48 | 49 | /* 50 | * it costs energy to exist, stationary, isolated objects eventually die 51 | * you should schedule an event every age_frequency time units 52 | * the event should subtract age_penalty units of energy from the LifeForm 53 | * if the energy drops below min_energy, the LifeForm should die 54 | */ 55 | extern const double age_penalty; 56 | extern const double age_frequency; // 0.1 unit of energy per unit time 57 | 58 | /* whether you eat or not, you take a penalty for colliding */ 59 | extern const double encounter_penalty; 60 | 61 | /* the cost to move is non-linear */ 62 | double movement_cost(double speed, double time); 63 | 64 | /* all life forms must have at least this much energy, or they die */ 65 | extern const double min_energy; 66 | 67 | /* 68 | * when a LifeForm reproduces, the child must be placed no further than 69 | * reproduce_dist units away. 70 | * The child should be given 1/2 the energy of the parent 71 | * and then both child and parent should be charged the reproduce_cost 72 | * NOTE: reproduce cost is a percentage, so the penalty 73 | * is energy * reproduce_cost 74 | */ 75 | extern const double reproduce_dist; 76 | extern const double reproduce_cost; // a fraction 77 | extern const double min_reproduce_time; 78 | /* 79 | * Algae gain energy automatically 80 | * Every algae_photo_time time units, an Algae gains Algae_energy_gain 81 | * units of energy 82 | */ 83 | extern const double Algae_energy_gain; 84 | extern const SimTime algae_photo_time; 85 | 86 | /* 87 | * two objects whos' centers are encounter_distance away (or closer) 88 | * are considered to have collided. 89 | * you are required to eventually simulate a collision when objects move 90 | * towards each other 91 | * 92 | * you do not need to simulate a collision everytime objects are close 93 | * if you miss collisions because objects to not cross boundaries in the 94 | * QuadTree, that is OK. 95 | * BUT if two objects move towards each other, and do not eat each other 96 | * and continue to move towards each other, you must simulate enough 97 | * events so that the objects eventually die (from the encounter_penalty 98 | * being applied over and over again) 99 | * 100 | * You must also correctly simulate the case that two objects move 101 | * towards each other, collide once, and then turn and go opposite 102 | * directions. (this case is very hard, solve it last) 103 | */ 104 | extern const double encounter_distance; 105 | 106 | /* 107 | * every time an object attempts to look around, it should be assessed this 108 | * penalty. 109 | */ 110 | double perceive_cost(double radius); 111 | 112 | /* objects must not be permitted to move faster than max_speed 113 | * if they do, then their speed should be set to max_speed (do not 114 | * kill them for trying) 115 | */ 116 | extern const double max_speed; 117 | 118 | /* objects should not be permitted to percieve more than max_perceive_range 119 | * or perceive less than min_percieve_range. 120 | * If they do, adjust their perceive range to the appropriate bound 121 | * (do not kill them for trying) 122 | */ 123 | extern const double max_perceive_range; 124 | extern const double min_perceive_range; 125 | 126 | extern const int grid_max; 127 | extern const int win_x_size; 128 | extern const int win_y_size; 129 | 130 | // minimum time between scheduling an 131 | // event and when that event can occur 132 | extern const double min_delta_time; 133 | 134 | /* 135 | * You may ignore the parameters after this line. Just extra 136 | * stuff I added to the solution 137 | */ 138 | 139 | /* how to resolve encounters when both objects want to eat */ 140 | enum EncounterResolver { 141 | EVEN_MONEY, // flip a coin 142 | BIG_GUY_WINS, // big guy gets first bite 143 | UNDERDOG_IS_HERE, // let the little guy have a chance 144 | FASTER_GUY_WINS, // speeding eagle gets the mouse 145 | SLOWER_GUY_WINS // ambush! 146 | }; 147 | 148 | /* 149 | * set your encounter resolution strategy here. Only affects the 150 | * case where both objects want to eat each other and both objects 151 | * "succeed" 152 | */ 153 | extern const EncounterResolver encounter_strategy; 154 | 155 | enum SimulationTerminationStrategy { 156 | RUN_TILL_HALF_EXTINCT, 157 | RUN_TILL_ONE_SPECIES_LEFT, 158 | RUN_TILL_EVENTS_EXHAUSTED // runs forever if ALGAE_SPORES is on 159 | }; 160 | 161 | extern const SimulationTerminationStrategy termination_strategy; 162 | 163 | #endif /* !(_Params_h) */ 164 | -------------------------------------------------------------------------------- /lab3/LifeForm.h: -------------------------------------------------------------------------------- 1 | #if ! (_LifeForm_h) 2 | #define _LifeForm_h 1 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #ifdef _MSC_VER 11 | # include 12 | #else 13 | #include 14 | # endif /* end #IF for Windows/Linux time.h file */ 15 | 16 | #include "Params.h" 17 | #include "Point.h" 18 | #include "SmartPointer.h" 19 | 20 | 21 | /* forward declarations */ 22 | class LifeForm; 23 | class istream; 24 | struct ObjInfo; 25 | typedef std::vector ObjList; 26 | template class QuadTree; 27 | 28 | /* 29 | * The map will contain IstreamCreators for LifeForms 30 | * The map will be keyed on a String. This String 31 | * must be a keyword that uniquely identifies a type of LifeForm 32 | * (e.g., "Lion", "Tiger", "Bear", oh my). 33 | */ 34 | using IstreamCreator = std::function(void)>; 35 | 36 | typedef std::map LFCreatorTable; 37 | 38 | /* 39 | * The Canvas class is something we can draw on 40 | */ 41 | class Canvas; 42 | 43 | /* 44 | * We draw with Colors 45 | */ 46 | #include "Color.h" 47 | 48 | class Event; 49 | 50 | enum Action { 51 | LIFEFORM_IGNORE, 52 | LIFEFORM_EAT 53 | }; 54 | 55 | class LifeForm : public ControlBlock { 56 | private: 57 | /* space is the global storage that represents the 2-dimensional simulation area */ 58 | static QuadTree> space; 59 | 60 | 61 | /* In order to perform the graphics output and to keep track of 62 | * which species have become extinct, we need a mechanism to scan 63 | * all of the LifeForms that are alive. I'm creating a std::vector 64 | * to hold pointers to every LifeForm. Objects insert themselves (*this) 65 | * into the vector in the LifeForm constructor, and remove themselves 66 | * from the vector in their destructor. The name of the vector is all_life 67 | * 68 | * There are two caveats 69 | * 70 | * 1. some lifeforms may be dead, yet their destructors may not yet 71 | * have been run (e.g., student species can create lots of LifeForm objects 72 | * by just calling "new Craig[1000]"). So, we have an is_alive flag that 73 | * will be false in LifeForms that are outside of the simulation. The all_life 74 | * vector will include pointers to all LifeForms (alive or dead). 75 | * 2. removing LifeForm objects from the vector is facilitated by having each LifeForm 76 | * remember its position in the vector. When we remove LifeForm (e.g,. LifeForm #10) 77 | * we simply replace that position with a pointer to the last LifeForm in the vector 78 | * and then pop_back the LifeForm at the end. The vector_pos data member tells each 79 | * LifeForm object where it can find this in the all_life vector 80 | * 81 | */ 82 | static std::vector all_life; 83 | uint32_t vector_pos; 84 | 85 | /* istream_creators is a map, indexed by strings, and returning functions 86 | * the functions create the correct subtype of LifeForm 87 | * i.e., istream_creators["Craig"] returns a function. If you call that 88 | * function, then the function returns a Craig* allocated on the heap 89 | * 90 | * to avoid race conditions related to the order that global variables 91 | * and static data members are created, the implementation requires 92 | * that we use the syntax 93 | * istream_creators()["Craig"] 94 | * the istream_creators function return a reference to the actual map. 95 | */ 96 | static LFCreatorTable& istream_creators(void); 97 | 98 | 99 | static int scale_x(double); // scale_x and scale_y are used to position the pixel 100 | static int scale_y(double); // in the window when drawing a LifeForm 101 | void print_position(void) const; // print and print_position are provided for debugging purposes 102 | void print(void) const; 103 | 104 | double energy; 105 | bool is_alive; 106 | 107 | Event* border_cross_event; // pointer to the event for the next encounter with a boundary 108 | void border_cross(void); // the event handler function for the border cross event 109 | 110 | void region_resize(void); // the callback function for region resizes (invoked by the quadtree) 111 | 112 | Point pos; 113 | double update_time; // the time when update_position was 114 | // last called 115 | double reproduce_time; // the time when reproduce was last called 116 | double course; 117 | double speed; 118 | 119 | Point start_point; // start_point is sometimes used by the test program(s) 120 | // you can (and should) ignore it 121 | 122 | 123 | void resolve_encounter(SmartPointer); 124 | void eat(SmartPointer); 125 | void age(void); // subtract age_penalty from energy 126 | void gain_energy(double); 127 | void update_position(void); // calculate the current position for 128 | // an object. If less than Time::tolerance 129 | // time units have passed since the last 130 | // call to update_position, then do nothing 131 | // (we can't have moved very far so there's 132 | // no point in updating our position) 133 | 134 | void check_encounter(void); // check to see if there's another object 135 | // within encounter_distance. If there's 136 | // an object nearby, invoke resove_encounter 137 | // on ourself with the closest object 138 | 139 | void die(void); // kill the current life form 140 | 141 | 142 | void compute_next_move(void); // a simple function that creates the next border_cross_event 143 | 144 | ObjInfo info_about_them(SmartPointer); 145 | 146 | const Point& position() const { return pos; } 147 | 148 | static Canvas win; 149 | protected: 150 | double health(void) const { 151 | if (!is_alive) { return 0.0; } 152 | else { return energy / start_energy; } 153 | } 154 | void set_course(double); 155 | void set_speed(double); 156 | double get_course(void) const { return course; } 157 | double get_speed(void) const { return speed; } 158 | void reproduce(SmartPointer); 159 | ObjList perceive(double); 160 | 161 | public: 162 | LifeForm(void); 163 | virtual ~LifeForm(void); 164 | 165 | static void add_creator(IstreamCreator, const std::string&); 166 | static void create_life(); 167 | /* draw the lifeform on 'win' where x,y is upper left corner */ 168 | virtual void draw(int, int) const; 169 | virtual Color my_color(void) const = 0; 170 | 171 | void display(void) const; 172 | static void redisplay_all(void); 173 | static void clear_screen(void); 174 | 175 | virtual Action encounter(const ObjInfo&) = 0; 176 | virtual std::string species_name(void) const = 0; 177 | virtual std::string player_name(void) const; 178 | 179 | friend class Algae; 180 | 181 | /* 182 | * the following functions are used by the test program(s) and should not be used by students (except, of course, 183 | * during testing, feel free to write your own test programs) 184 | */ 185 | bool confirmPosition(double xpos, double ypos) { 186 | return pos.distance(Point(xpos,ypos)) < 0.10; 187 | } 188 | 189 | static void runTests(void); 190 | static bool testMode; 191 | static void place(std::shared_ptr, Point p); 192 | 193 | }; 194 | 195 | #endif /* !(_LifeForm_h) */ 196 | -------------------------------------------------------------------------------- /lab2/Valarray.h: -------------------------------------------------------------------------------- 1 | #ifndef _Valarray_h 2 | #define _Valarray_h 3 | #include "Vector.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using epl::vector; 11 | 12 | /* type promotion */ 13 | template struct to_rank; 14 | template struct to_rank> { static constexpr int value = to_rank::value; }; 15 | template <> struct to_rank { static constexpr int value = 1; }; 16 | template <> struct to_rank { static constexpr int value = 2; }; 17 | template <> struct to_rank { static constexpr int value = 3; }; 18 | 19 | template struct is_complex : public std::false_type {}; 20 | template struct is_complex> : public std::true_type {}; 21 | 22 | template struct to_type; 23 | template <> struct to_type<1> { using type = int; }; 24 | template <> struct to_type<2> { using type = float; }; 25 | template <> struct to_type<3> { using type = double; }; 26 | 27 | template struct to_complex; 28 | template struct to_complex { using type = T; }; 29 | template struct to_complex { using type = std::complex; }; 30 | 31 | template 32 | struct _choose_type { 33 | static constexpr int t1_rank = to_rank::value; 34 | static constexpr int t2_rank = to_rank::value; 35 | static constexpr int result_rank = std::max(t1_rank, t2_rank); 36 | 37 | static constexpr bool t1_is_complex = is_complex::value; 38 | static constexpr bool t2_is_complex = is_complex::value; 39 | static constexpr bool result_is_complex = t1_is_complex || t2_is_complex; 40 | 41 | using primitive_type = typename to_type::type; 42 | using type = typename to_complex::type; 43 | }; 44 | 45 | template 46 | using choose_type = typename _choose_type::type; 47 | 48 | template 49 | class iterator_helper { 50 | private: 51 | V obj; 52 | uint64_t index; 53 | public: 54 | iterator_helper(V const& arg, uint64_t k) : obj{ arg }, index{ k } {} 55 | iterator_helper(iterator_helper const& that) : obj{ that.obj }, index{ that.index } {} 56 | auto operator*(void) { 57 | return obj[index]; 58 | } 59 | iterator_helper& operator++(void) { 60 | index += 1; 61 | return *this; 62 | } 63 | iterator_helper operator++(int) { 64 | iterator_helper t{ *this }; 65 | operator++(); 66 | return t; 67 | } 68 | bool operator==(iterator_helper const& that) const { 69 | return obj == that.obj && index == that.index; 70 | } 71 | bool operator!=(iterator_helper const& that) const { 72 | return !(*this == that); 73 | } 74 | }; 75 | 76 | /* 77 | * template meta function to decide the type (reference or object) 78 | * of left and right operands in binary_proxy.we want to store a reference 79 | * to a valarray i.e. vector, but we need to store a copy of binary_proxy, 80 | * because intermediate binary_proxy would vanish after being used 81 | */ 82 | template struct _ref { using type = T; }; 83 | template struct _ref> { using type = vector const&; }; 84 | template using ref = typename _ref::type; 85 | 86 | /* binary_proxy */ 87 | template 88 | class binary_proxy { 89 | private: 90 | ref lhs; 91 | ref rhs; 92 | FUN f; 93 | public: 94 | binary_proxy(ref x, ref y, FUN op) : lhs{ x }, rhs{ y }, f{ op } {} 95 | binary_proxy(binary_proxy const& that) : lhs{ that.lhs }, rhs{ that.rhs }, f{ that.f } {} 96 | /* vector concept interface */ 97 | using const_iterator = iterator_helper; 98 | using value_type = choose_type; 99 | uint64_t size(void) const { 100 | return std::min(lhs.size(), rhs.size()); 101 | } 102 | auto operator[](uint64_t k) const { 103 | return f(static_cast(lhs[k]), static_cast(rhs[k])); 104 | } 105 | const_iterator begin(void) const { 106 | return const_iterator(*this, 0); 107 | } 108 | const_iterator end(void) const { 109 | return const_iterator(*this, size()); 110 | } 111 | }; 112 | 113 | /* unary_proxy */ 114 | template 115 | class unary_proxy { 116 | private: 117 | ref val; 118 | FUN f; 119 | public: 120 | unary_proxy(ref x, FUN op) : val{ x }, f{ op } {} 121 | unary_proxy(unary_proxy const& that) : val{ that.val }, f{ that.f } {} 122 | /* vector concept interface */ 123 | using const_iterator = iterator_helper; 124 | using value_type = typename V::value_type; 125 | uint64_t size(void) const { 126 | return val.size(); 127 | } 128 | auto operator[](uint64_t k) const { 129 | return f(val[k]); 130 | } 131 | const_iterator begin(void) const { 132 | return const_iterator(*this, 0); 133 | } 134 | const_iterator end(void) const { 135 | return const_iterator(*this, size()); 136 | } 137 | }; 138 | 139 | /* scalar */ 140 | template 141 | class scalar { 142 | private: 143 | T val; 144 | public: 145 | scalar(T const& x) : val{ x } {} 146 | scalar(scalar const& that) : val{ that[0] } {} 147 | /* vector concept interface */ 148 | using const_iterator = iterator_helper; 149 | using value_type = T; 150 | uint64_t size(void) const { 151 | return std::numeric_limits::max(); 152 | } 153 | auto operator[](uint64_t) const { 154 | return val; 155 | } 156 | const_iterator begin(void) const { 157 | return const_iterator(*this, 0); 158 | } 159 | const_iterator end(void) const { 160 | return const_iterator(*this, size()); 161 | } 162 | }; 163 | 164 | 165 | template 166 | struct root { 167 | constexpr auto operator() (T const& x) const { return sqrt(x); } 168 | }; 169 | 170 | /* vector concept wrapper 171 | * vector concept should at least provide these interfaces: 172 | * 1. value_type 173 | * 2. size() 174 | * 3. operator[](uint64_t k) 175 | * 4. begin() 176 | * 5. end() 177 | */ 178 | template 179 | class wrap : public V { 180 | public: 181 | using V::V; 182 | using value_type = typename V::value_type; 183 | wrap(void) : V{} {} 184 | wrap(V const& that) : V{ that } {} 185 | 186 | /* Three cases: 187 | * 1. construct a proxy using a proxy - copy ctor 188 | * 2. construct a valarray using a valarray - copy ctor 189 | * 3. construct a valarray using a proxy - special ctor 190 | */ 191 | wrap(wrap const& that) : V{ that } {} 192 | 193 | template 194 | wrap(wrap const& that) : V(that.size()) { 195 | for (auto i = 0; i < this->size(); i += 1) { 196 | (*this)[i] = static_cast(that[i]); 197 | } 198 | } 199 | 200 | /* Two cases: 201 | * 1. assign a valarray to a valarray 202 | * 2. assign a proxy to a valarray 203 | * note: proxy is not mutable 204 | */ 205 | template 206 | wrap& operator=(wrap const& that) { 207 | auto size = std::min(this->size(), that.size()); 208 | for (auto i = 0; i < size; i += 1) { 209 | (*this)[i] = static_cast(that[i]); 210 | } 211 | return *this; 212 | } 213 | 214 | template ::value>::type> 215 | void operator=(T const& that) { 216 | this->operator=(wrap>(that)); 217 | } 218 | 219 | template 220 | auto accumulate(FUN f) const { 221 | if (!this->size()) return 0; 222 | value_type result{ (*this)[0] }; 223 | for (auto i = 1; i < this->size(); i += 1) { 224 | result = f(result, (*this)[i]); 225 | } 226 | return result; 227 | } 228 | 229 | template 230 | auto apply(FUN f) const { 231 | V const& self{ *this }; 232 | unary_proxy proxy{ self, f }; 233 | return wrap>{ proxy }; 234 | } 235 | 236 | auto sum(void) const { 237 | return accumulate(std::plus{}); 238 | } 239 | 240 | auto operator-(void) const { 241 | return apply(std::negate{}); 242 | } 243 | 244 | auto sqrt(void) const { 245 | return apply(root{}); 246 | } 247 | 248 | void print(std::ostream& out) const { 249 | for (auto i = 0; i < this->size(); i += 1) { 250 | out << (*this)[i] << " "; 251 | } 252 | out << "\n"; 253 | } 254 | }; 255 | 256 | template 257 | auto lazy(wrap const& lhs, wrap const& rhs, FUN f) { 258 | V1 const& left{ lhs }; 259 | V2 const& right{ rhs }; 260 | binary_proxy proxy{ left, right, f }; 261 | return wrap< binary_proxy >{ proxy }; 262 | }; 263 | 264 | template ::value>::type> 265 | auto lazy(wrap const& lhs, T const& rhs, FUN f) { 266 | using V2 = scalar; 267 | V1 const& left{ lhs }; 268 | V2 right{ rhs }; 269 | binary_proxy proxy{ left, right, f }; 270 | return wrap>{ proxy }; 271 | }; 272 | 273 | template ::value>::type> 274 | auto lazy(T const& lhs, wrap const& rhs, FUN f) { 275 | using V1 = scalar; 276 | V1 left{ lhs }; 277 | V2 const& right{ rhs }; 278 | binary_proxy proxy{ left, right, f }; 279 | return wrap>{ proxy }; 280 | }; 281 | 282 | 283 | template 284 | auto operator+(T1 const& lhs, T2 const& rhs) { 285 | return lazy(lhs, rhs, std::plus{}); 286 | }; 287 | 288 | template 289 | auto operator-(T1 const& lhs, T2 const& rhs) { 290 | return lazy(lhs, rhs, std::minus{}); 291 | }; 292 | 293 | template 294 | auto operator*(T1 const& lhs, T2 const& rhs) { 295 | return lazy(lhs, rhs, std::multiplies{}); 296 | }; 297 | 298 | template 299 | auto operator/(T1 const& lhs, T2 const& rhs) { 300 | return lazy(lhs, rhs, std::divides{}); 301 | }; 302 | 303 | template 304 | std::ostream& operator<<(std::ostream& out, wrap const& that) { 305 | that.print(out); 306 | return out; 307 | } 308 | 309 | template 310 | using valarray = wrap>; 311 | 312 | #endif /* _Valarray_h */ 313 | -------------------------------------------------------------------------------- /lab3/LifeForm-Craig.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "tokens.h" 12 | #include "Params.h" 13 | #include "Event.h" 14 | #include "Window.h" 15 | #include "ObjInfo.h" 16 | #include "CraigUtils.h" 17 | #include "QuadTree.h" 18 | #include "LifeForm.h" 19 | #include "Algae.h" 20 | #include "Random.h" 21 | 22 | #if defined (_MSC_VER) 23 | using namespace epl; 24 | #endif 25 | using namespace std; 26 | using String = std::string; 27 | double MAX_SIMULATION_TIME = 50000.0; 28 | 29 | /* 30 | * Implementation NOTE: 31 | * Here's a cute trick....... 32 | * we want to make *SURE* that the istream_creators hash table is 33 | * constructed *BEFORE* we try to insert anything into it.... 34 | * But HOW can we force that to happen? Well, instead of making 35 | * istream_creators a static data member, I make it a static member 36 | * function (returning a reference to the table). 37 | * the *REAL* hash table is a static local variable in this member 38 | * function. 39 | * So... when add_creator is called, it will call istream_creators() 40 | * and 'the_real_table' will be constructed before anything is 41 | * actually inserted. 42 | */ 43 | LFCreatorTable& LifeForm::istream_creators() 44 | { 45 | static LFCreatorTable the_real_table; 46 | return the_real_table; 47 | } 48 | 49 | QuadTree> LifeForm::space(0.0, 0.0, grid_max, grid_max); 50 | Canvas LifeForm::win(win_x_size, win_y_size); 51 | 52 | std::vector LifeForm::all_life; 53 | 54 | LifeForm::LifeForm(void) { 55 | energy = start_energy; 56 | course = speed = 0.0; // stationary 57 | pos = Point(0, 0); 58 | is_alive = false; 59 | update_time = Event::now(); 60 | reproduce_time = 0.0; 61 | border_cross_event = nullptr; 62 | vector_pos = all_life.size(); 63 | all_life.push_back(this); 64 | } 65 | 66 | 67 | LifeForm::~LifeForm(void) { 68 | #if DEBUG 69 | cout << "death event\n"; 70 | #endif /* DEBUG */ 71 | 72 | assert(!is_alive); 73 | assert(all_life[vector_pos] == this); 74 | 75 | /* remove from all_life list */ 76 | LifeForm* last = all_life.back(); 77 | all_life[vector_pos] = last; 78 | last->vector_pos = vector_pos; 79 | all_life.pop_back(); 80 | } 81 | 82 | 83 | String LifeForm::player_name(void) const { 84 | return species_name(); 85 | } 86 | 87 | 88 | 89 | void LifeForm::create_life(void) 90 | { 91 | SmartPointer obj; 92 | 93 | if (testMode) { runTests(); return; } 94 | 95 | string line; 96 | ifstream inFile; 97 | #if defined (_MSC_VER) 98 | inFile.open("../../config.test"); 99 | #else 100 | inFile.open("config.test"); 101 | #endif 102 | 103 | while (!inFile.eof()) 104 | { 105 | getline(inFile, line); 106 | istringstream iss(line); 107 | vector tokens{ istream_iterator{iss}, istream_iterator{} }; 108 | 109 | if (tokens.size() == 2) 110 | { 111 | IstreamCreator factory_fun = (istream_creators())[tokens[0]]; 112 | bool first = true; 113 | int numCreated = stoi(tokens[1]); 114 | for (int i = 0; i < numCreated; i++) { 115 | obj = factory_fun(); 116 | SmartPointer nearest; 117 | do { 118 | obj->pos.ypos = drand48() * grid_max * 0.75 + grid_max / 8.0; 119 | obj->pos.xpos = drand48() * grid_max * 0.75 + grid_max / 8.0; 120 | if (first) { 121 | nearest = nullptr; 122 | first = false; 123 | } 124 | else { 125 | nearest = space.closest(obj->pos); 126 | } 127 | } while (nearest 128 | && nearest->position().distance(obj->position()) <= encounter_distance); 129 | obj->start_point = obj->pos; 130 | space.insert(obj, obj->pos, [obj]() { obj->region_resize(); }); 131 | (void) new Event(age_frequency, [obj](void) { obj->age(); }); 132 | obj->is_alive = true; 133 | } 134 | } 135 | } 136 | 137 | redisplay_all(); 138 | win.display(); 139 | //cout << "continue?" << endl; 140 | //string x; 141 | //cin >> x; 142 | //if (x != string("Yes")) exit(0); 143 | } 144 | 145 | void LifeForm::add_creator(IstreamCreator f, const String& s) { 146 | (istream_creators())[s] = f; 147 | } 148 | 149 | int LifeForm::scale_x(double x) { 150 | double rel_x = (double)x / (double)grid_max; 151 | return (int)(rel_x * win_x_size); 152 | } 153 | 154 | int LifeForm::scale_y(double y) { 155 | double rel_y = (double)y / (double)grid_max; 156 | return (int)(rel_y * win_y_size); 157 | } 158 | 159 | void LifeForm::print(void) const { 160 | cout << species_name() << " at "; 161 | print_position(); 162 | } 163 | 164 | void LifeForm::print_position(void) const { 165 | cout << "(" << pos.xpos << "," << pos.ypos << ")"; 166 | } 167 | 168 | 169 | void LifeForm::display(void) const 170 | { 171 | #if DEBUG 172 | cout << "drawing LF at"; 173 | cout << "(" << pos.xpos << "," << pos.ypos << ")"; 174 | #endif /* DEBUG */ 175 | win.set_color(my_color()); 176 | draw(scale_x(pos.xpos), scale_y(pos.ypos)); 177 | #if DEBUG 178 | cout << endl; 179 | #endif /* DEBUG */ 180 | } 181 | 182 | typedef pair Rank; 183 | struct RankCompare { 184 | bool operator()(const Rank& x, const Rank& y) { 185 | return x.second > y.second; 186 | } 187 | }; 188 | 189 | 190 | void LifeForm::redisplay_all(void) { 191 | typedef map SpeciesHT; 192 | SpeciesHT species_table; 193 | static int max_species = 0; // the maximum number of species ever. 194 | 195 | win.clear(); 196 | uint32_t num_life = 0; 197 | for (LifeForm* k : all_life) { 198 | if (k->is_alive) { 199 | num_life += 1; 200 | k->display(); 201 | String name = k->player_name(); 202 | name = name.substr(0, name.find(':')); 203 | if (species_table.find(name) == species_table.end()) { 204 | species_table[name] = 0.0; 205 | } 206 | species_table[name] += k->energy; 207 | 208 | /* uncomment the next line to get accurate graphics at the expense 209 | of slowing down the simulator */ 210 | // k->update_position(); 211 | } 212 | } 213 | win.flush(); 214 | 215 | #if (SPECIES_SUMMARY) 216 | cout << "\n\n\n"; 217 | cout << "At Time " << Event::now() 218 | << " there are " << num_life << " / " << all_life.size() << " total life forms, "; 219 | int count = 0; 220 | vector rankings; 221 | for (const auto& i : species_table) { 222 | rankings.push_back(Rank(i.first, i.second)); 223 | count += 1; 224 | } 225 | cout << "and " << count << " distinct species\n"; 226 | cout << "There are " << Event::num_events() 227 | << " events (" << (double)Event::num_events() 228 | / (double)num_life << " events per life form)\n"; 229 | 230 | if (count > max_species) { max_species = count; } 231 | sort(rankings.begin(), rankings.end(), RankCompare()); 232 | int specs = 0; 233 | 234 | for (const Rank& best : rankings) { 235 | cout << "Species: " << best.first << " has total of " 236 | << best.second << " energy\n"; 237 | specs += 1; 238 | if (specs >= max_species / 2) { // draw line to indicate winners/losers 239 | cout << "----------------------------------------"; 240 | cout << "----------------------------------------\n"; 241 | specs = -specs; // make sure the line is drawn only once 242 | } 243 | } 244 | 245 | if ((termination_strategy == RUN_TILL_HALF_EXTINCT && count <= max_species / 2) 246 | || (termination_strategy == RUN_TILL_ONE_SPECIES_LEFT && count <= 2) 247 | || Event::now() > MAX_SIMULATION_TIME) { 248 | // abort the simulation 249 | cout << "\t!!Simulation Complete at time " << Event::now() << " !!\n"; 250 | //cout << "hit CTRL-C to stop\n"; // uncomment if you want to see the 251 | //sleep(1000); // final state of the graphics display 252 | exit(0); 253 | } 254 | #endif /* SPECIES_SUMMARY */ 255 | } 256 | 257 | void LifeForm::draw(int x, int y) const 258 | { 259 | win.draw_rectangle(x, y, x + 4, y + 4); 260 | } 261 | 262 | void LifeForm::clear_screen(void) 263 | { 264 | win.clear(); 265 | } 266 | 267 | 268 | void Algae::create_spontaneously(void) 269 | { 270 | SmartPointer a = new Algae; 271 | SmartPointer nearest; 272 | do { 273 | a->pos.ypos = drand48() * grid_max * 0.75 + grid_max / 8.0; 274 | a->pos.xpos = drand48() * grid_max * 0.75 + grid_max / 8.0; 275 | nearest = space.closest(a->pos); 276 | } while (nearest && nearest->position().distance(a->position()) 277 | <= encounter_distance); 278 | 279 | a->start_point = a->pos; 280 | space.insert(a, a->pos, 281 | [a](void) { a->region_resize(); }); 282 | a->is_alive = true; 283 | } 284 | 285 | 286 | void LifeForm::die(void) 287 | { 288 | if (!is_alive) return; // already called. 289 | // it is possible to call die twice in some 290 | // very peculiar circumstances. 291 | // you have two objects that are bumping 292 | // into each other without ever eating 293 | // one another. 294 | // Eventually, they run low on energy. 295 | // they encounter each other, and both 296 | // are weak enough to die 297 | // object 1 calls obj1->die(); 298 | // object 1 is removed from the tree. 299 | // region resize is called for object 2 300 | // region resize calls update position, 301 | // which kills object 2 ('cause it's too weak) 302 | // space.remove(obj1) returns 303 | // resolve_encounter calls obj2->die(); 304 | space.remove(pos); 305 | is_alive = false; 306 | } 307 | 308 | -------------------------------------------------------------------------------- /lab3/LifeForm.cpp: -------------------------------------------------------------------------------- 1 | /* main test simulator */ 2 | #include 3 | #include "CraigUtils.h" 4 | #include "Window.h" 5 | #include "tokens.h" 6 | #include "ObjInfo.h" 7 | #include "QuadTree.h" 8 | #include "Params.h" 9 | #include "LifeForm.h" 10 | #include "Event.h" 11 | 12 | using namespace std; 13 | 14 | template 15 | void bound(T& x, const T& min, const T& max) { 16 | assert(min < max); 17 | if (x > max) { x = max; } 18 | if (x < min) { x = min; } 19 | } 20 | 21 | 22 | 23 | ObjInfo LifeForm::info_about_them(SmartPointer neighbor) { 24 | ObjInfo info; 25 | 26 | info.species = neighbor->species_name(); 27 | info.health = neighbor->health(); 28 | info.distance = pos.distance(neighbor->position()); 29 | info.bearing = pos.bearing(neighbor->position()); 30 | info.their_speed = neighbor->speed; 31 | info.their_course = neighbor->course; 32 | return info; 33 | } 34 | 35 | /** 36 | * the event handler function for the border cross event 37 | */ 38 | void LifeForm::border_cross(void) { 39 | if (!is_alive) return; 40 | border_cross_event = nullptr; 41 | update_position(); 42 | check_encounter(); 43 | compute_next_move(); 44 | } 45 | 46 | /** 47 | * the callback function for region resizes (invoked by the quadtree) 48 | */ 49 | void LifeForm::region_resize(void) { 50 | update_position(); 51 | compute_next_move(); 52 | } 53 | 54 | void LifeForm::eat(SmartPointer that) { 55 | that->die(); 56 | energy -= eat_cost_function(this->energy, that->energy); 57 | if (energy < min_energy) { 58 | die(); 59 | return; 60 | } 61 | double e = that->energy * eat_efficiency; 62 | SmartPointer self = SmartPointer(this); 63 | (void) new Event (digestion_time, [self, e](void){ self->gain_energy(e); }); 64 | } 65 | 66 | void LifeForm::gain_energy(double e) { 67 | // this lifeform may die in digestion time 68 | if (!is_alive) return; 69 | energy += e; 70 | if (energy < min_energy) { 71 | energy = 0; 72 | die(); 73 | } 74 | } 75 | 76 | /** 77 | * subtract age_penalty from energy 78 | */ 79 | void LifeForm::age(void) { 80 | if (!is_alive) return; 81 | energy -= age_penalty; 82 | if (energy > min_energy) { 83 | SmartPointer self = SmartPointer(this); 84 | (void) new Event(age_frequency, [self](void){ self->age(); }); 85 | } 86 | else { 87 | energy = 0; 88 | die(); 89 | } 90 | } 91 | 92 | /** 93 | * calculate the current position for an object. 94 | */ 95 | void LifeForm::update_position(void) { 96 | double delta_time = Event::now() - this->update_time; 97 | Point newpos; 98 | // don't update position if time less than min_delta_time 99 | if (!is_alive || delta_time < min_delta_time) return; 100 | 101 | // calculate new position 102 | newpos.xpos = pos.xpos + cos(course) * delta_time * speed; 103 | newpos.ypos = pos.ypos + sin(course) * delta_time * speed; 104 | 105 | // go out of bound, die 106 | if (space.is_out_of_bounds(newpos)) { 107 | energy = 0; 108 | die(); 109 | return; 110 | } 111 | 112 | // stationary, nothing happens 113 | if (newpos == pos) return; 114 | 115 | // lack of energy, die 116 | energy -= movement_cost(speed, delta_time); 117 | if (energy < min_energy) { 118 | energy = 0; 119 | die(); 120 | return; 121 | } 122 | 123 | update_time = Event::now(); 124 | space.update_position(pos, newpos); 125 | pos = newpos; 126 | } 127 | 128 | 129 | /** 130 | * check to see if there's another object 131 | * within encounter_distance. If there's 132 | * an object nearby, invoke resove_encounter 133 | * on ourself with the closest object 134 | */ 135 | void LifeForm::check_encounter(void) { 136 | if (!is_alive) return; 137 | auto closest_obj = space.closest(pos); 138 | update_position(); 139 | if( is_alive && closest_obj->is_alive && pos.distance(closest_obj->pos) < encounter_distance ) 140 | resolve_encounter(closest_obj); 141 | } 142 | 143 | void LifeForm::resolve_encounter(SmartPointer that) { 144 | energy -= encounter_penalty; 145 | that->energy -= encounter_penalty; 146 | if (energy < min_energy) { 147 | energy = 0; 148 | die(); 149 | } 150 | if (that->energy < min_energy) { 151 | energy = 0; 152 | die(); 153 | } 154 | 155 | if (!is_alive || !(that->is_alive)) return; 156 | 157 | auto this_info = that->info_about_them(SmartPointer(this)); 158 | auto that_info = this->info_about_them(that); 159 | auto this_act = this->encounter(that_info); 160 | auto that_act = that->encounter(this_info); 161 | 162 | if (this_act == LIFEFORM_EAT && that_act == LIFEFORM_EAT) { 163 | auto rand1 = drand48(); 164 | auto rand2 = drand48(); 165 | if ( rand1 < eat_success_chance(energy, that->energy) && rand2 < eat_success_chance(that->energy, energy)) { 166 | switch (encounter_strategy) { 167 | case EVEN_MONEY: 168 | if (drand48() < 0.5) { eat(that); } 169 | else { that->eat(SmartPointer(this)); } 170 | break; 171 | case BIG_GUY_WINS: 172 | if (energy > that->energy) { eat(that); } 173 | else { that->eat(SmartPointer(this)); } 174 | break; 175 | case UNDERDOG_IS_HERE: 176 | if (energy <= that->energy) { eat(that); } 177 | else { that->eat(SmartPointer(this)); } 178 | break; 179 | case FASTER_GUY_WINS: 180 | if (speed > that->speed) { eat(that); } 181 | else { that->eat(SmartPointer(this)); } 182 | break; 183 | case SLOWER_GUY_WINS: 184 | if (energy <= that->energy) { eat(that); } 185 | else { that->eat(SmartPointer(this)); } 186 | break; 187 | default: 188 | break; 189 | } 190 | } 191 | else if ( rand1 < eat_success_chance(energy, that->energy) && rand2 >= eat_success_chance(that->energy, energy) ) { 192 | eat(that); 193 | } 194 | else if ( rand1 >= eat_success_chance(energy, that->energy) && rand2 < eat_success_chance(that->energy, energy)) { 195 | that->eat(SmartPointer(this)); 196 | } 197 | else {} 198 | 199 | } 200 | else if ( this_act == LIFEFORM_EAT && that_act == LIFEFORM_IGNORE ) { 201 | if (drand48() < eat_success_chance(energy, that->energy)) { 202 | eat(that); 203 | } 204 | } 205 | else if ( this_act == LIFEFORM_IGNORE && that_act == LIFEFORM_EAT ) { 206 | if (drand48() < eat_success_chance(that->energy, energy)) { 207 | that->eat(SmartPointer(this)); 208 | } 209 | } 210 | else {} 211 | } 212 | 213 | /** 214 | * a simple function that creates the next border_cross_event 215 | */ 216 | void LifeForm::compute_next_move(void) { 217 | // cancel previous border_cross_event 218 | if (border_cross_event != nullptr) { 219 | border_cross_event->cancel(); 220 | border_cross_event = nullptr; 221 | } 222 | 223 | // schedule a new new border_cross event 224 | SmartPointer self = SmartPointer(this); 225 | if (speed > 0.0) { 226 | double delta_time = (space.distance_to_edge(pos, course) + Point::tolerance)/speed; 227 | border_cross_event = new Event(delta_time, [self](void){ self->border_cross(); }); 228 | } 229 | } 230 | 231 | void LifeForm::set_course(double c) { 232 | if (!is_alive) return; 233 | update_position(); 234 | course = c; 235 | compute_next_move(); 236 | } 237 | void LifeForm::set_speed(double s) { 238 | if (!is_alive) return; 239 | update_position(); 240 | speed = s < max_speed? s : max_speed; 241 | compute_next_move(); 242 | } 243 | 244 | void LifeForm::reproduce(SmartPointer child) { 245 | if (!is_alive) return; 246 | 247 | update_position(); 248 | 249 | if (Event::now() - reproduce_time < min_reproduce_time) return; 250 | 251 | energy = child->energy = energy * (1 - reproduce_cost) / 2; 252 | 253 | if (energy < min_energy) { 254 | child->energy = 0; 255 | child->is_alive = false; 256 | energy = 0; 257 | die(); 258 | } 259 | else { 260 | SmartPointer nearest; 261 | // try 5 times, if all fail, ignore the attempt to reproduce 262 | for (int i = 0 ; i < 5; ++i) { 263 | // place child in [encouter_distance, reproduce_dist] from parent 264 | // of courese child shoude be in bound 265 | do { 266 | double r = encounter_distance + drand48() * (reproduce_dist - encounter_distance); 267 | double rad = drand48() * 2 * M_PI; 268 | child->pos.xpos = pos.xpos + r * cos(rad); 269 | child->pos.ypos = pos.ypos + r * sin(rad); 270 | } while (space.is_out_of_bounds(child->pos)); 271 | 272 | // if child's position is within other lifeform's encounter_distance 273 | // fail this try 274 | nearest = space.closest(child->pos); 275 | if (nearest) { 276 | nearest->update_position(); 277 | if (nearest->pos.distance(child->pos) > encounter_distance) break; 278 | } 279 | else break; 280 | } 281 | 282 | child->start_point = child->pos; 283 | space.insert(child, child->pos, [child](void) { child->region_resize(); }); 284 | (void) new Event(age_frequency, [child](void) { child->age(); }); 285 | child->is_alive = true; 286 | reproduce_time = Event::now(); 287 | } 288 | } 289 | 290 | ObjList LifeForm::perceive(double perceive_range) { 291 | if (!is_alive) return ObjList(0); 292 | 293 | if (perceive_range > max_perceive_range) { perceive_range = max_perceive_range; } 294 | else if (perceive_range < min_perceive_range) { perceive_range = min_perceive_range; } 295 | 296 | energy -= perceive_cost(perceive_range); 297 | if (energy < min_energy) { 298 | energy = 0; 299 | die(); 300 | return ObjList(0); 301 | } 302 | 303 | vector> obj_vector = space.nearby(pos, perceive_range); 304 | ObjList obj_info_vector(0); 305 | for (auto obj : obj_vector) { 306 | obj->update_position(); 307 | if (pos.distance(obj->pos) < perceive_range) { 308 | obj_info_vector.push_back(info_about_them(obj)); 309 | } 310 | } 311 | return obj_info_vector; 312 | } 313 | 314 | 315 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Advanced C++ Programming Project # 2 | 3 | Instructor: Prof. Craig Chase 4 | 5 | Engineering Programming Language (EPL) is a graduate software design and implementation class that emphasizes engineering level insight into the mechanics of contemporary programming languages. EPL makes extensive use of the C++ language (C++11 standard), in part because C++ is sufficiently low level that the mechanics by which object-oriented programming are implemented become readily visible to C++ programmers. Topics covered in EPL change annually, but often include, Template Meta Programming, Object Oriented Design, Design for Performance, Memory Management and Garbage Collection. 6 | 7 | ## Project1. Vector Container Basics and Extensions ## 8 | 9 | ### Part1 - Basics ### 10 | 11 | This project is to implement the container vector. A vector is a data structure that provides O(1) random access (via an operator[]), and amortized constant append (via push_back). Our vector differs from the standard library vector in three minor ways. We are not required to implement all of the C++ standard functions, our operator[] performs bounds checking, and we have to implement a “push_front” and “pop_front”. 12 | 13 | #### Method List: #### 14 | 15 | - vector(void) – creates an array with some minimum capacity (8 is fine) and length equal to zero. Must not use T::T(void). In fact, as long as Vector::Vector(int) is not called, we shall never use T::T(void) 16 | - explicit Vector(uint64_t n) – create an array with capacity and length exactly equal to n. Initialize the n objects using T::T(void). As a special case, if n is equal to zero, you can duplicate the behavior of vector(void). 17 | - copy and move constructors for vector\ arguments 18 | - copy and move assignment operators for vector\ arguments 19 | - destructor 20 | - uint64_t size(void) const – return the number of constructed objects in the vector 21 | - T& operator[](uint64_t k) – if k is out of bounds (equal to or larger than length), then we will throw std::out_of_range(“subscript out of range”). If k is in bounds, then we return a reference to the element at position k 22 | - const T& operator[](uint64_t k) const – same as above, except for constants. 23 | - void push_back(const T&) – add a new value to the end of the array, using amortized doubling if the array has to be resized. Copy construct the argument. 24 | - void push_back(T&&) – same as above, but move construct the argument. 25 | - void push_front(const T&) and void push_front(T&&) -- similar to push_back, but add the element to the front of the Vector 26 | - void pop_back(void) and (B) void pop_front(void) – if the array is empty, throw a std::out_of_range exception (with any reasonable string error message you want). Otherwise, destroy the object at the end (or beginning) of the array and update the length. This action will not reallocate storage, even if the vector becomes empty. It is possible that a vector can have available capacity at both the front and back simultaneously. 27 | 28 | #### Note: #### 29 | 30 | 1. We implement amortized doubling whenever we increase the allocated space of your vector. 31 | 2. If a call to pop_back succeeds (does not throw an exception) and is followed immediately by a call to push_back, then we will not perform any memory allocations. More generally, if two or more consecutive calls to pop_back succeed and are followed by an equal number of calls to push_back, then no allocations are performed. Similarly if one or more successive calls to pop_front succeed and are followed immediately by an equal number of push_front calls, then no memory allocations are performed. 32 | 33 | 34 | ### Part2 - Extensions ### 35 | 36 | In this project we are asked to add some new functionality to our Vector\ template class, making it more compliant with the C++ standard, and applying some of the additional knowledge we’ve gained about templates. 37 | 38 | #### Requirement: #### 39 | 40 | - Create a random-access iterator type for our Vector. 41 | - Write an emplace_back variadic member template function for our vector that constructs the object in place. 42 | - Create a member template constructor that takes an iterator pair b and e and initializes the Vector to contain copies of the values from [b, e). 43 | - Create a constructor that will initialize a Vector from a std::initializer_list\ 44 | 45 | #### Note: #### 46 | 1. For iterators, specific requirements are as follows 47 | 48 | - Provide begin/end fuctions for our Vector. 49 | - Provide both iterator and const_iterator (and begin/end for each). 50 | - Ensure that an iterator can be converted (without warnings or type casts) to const_iterator. 51 | - Ensure that const_iterator cannot be converted to iterator. 52 | - Design our iterator so that it throws the exception epl::invalid_iterator whenever the value of an invalid iterator is used. “Using the value” of an iterator includes comparison operations (with other iterators), dereferencing the iterator, incrementing the iterator, etc. Assigning to an iterator, for example, is not “using the value” of the iterator, it is assigning a new value to the iterator (and should not throw an exception). 53 | - epl::invalid_iterator has three severity levels: (a) If the iterator references a position that no longer exists (i.e., the old position is out-of-bounds), the exception you throw must use the level SEVERE. (b) If the iterator reference a position that is in-bounds, but the memory location for that position may have been changed (e.g., a reallocation has been performed because of a push_back, or a new assignment has been performed to the Vector), then the exception you throw must have the level MODERATE. (c) If the iterator is invalidated for any other reason, the exception must have the level MILD. 54 | 55 | Here is how I implemented [Vector.h](./lab1/Vector.h). 56 | 57 | ## Project2. Valarray with Expression Templates ## 58 | This project is to implement the container epl::valarray. A valarray is essentially a vector that contains values , i.e., types that have the arithmetic operators defined. 59 | 60 | ### Features: ### 61 | 1. Arithmetic operations are valid. That is, it is possible to add two valarrays, and the result should (at least conceptually) be another valarray. 62 | 2. Lazy evaluation of expressions (using expression templates) are requred. 63 | 3. A result of the appropriate type is provided when valarrays with different element types are used. 64 | 65 | ### Function Lists: ### 66 | 1. push_back--inherited 67 | 2. pop_back--inherited 68 | 3. operator[] -- inherited 69 | 4. appropriate iterator and const_iterator classes (and begin/end functions) -- inherited 70 | 5. the binary operators *,/,-,+ 71 | 6. a unary - (arithmetic negation) 72 | 7. all necessary functions to convert from one valarray type to another 73 | 8. a constructor that takes an initial size -- inherited 74 | 9. a sum() function that adds all elements in the valarray using standard addition 75 | 10. an accumulate function that adds all elements in the valarray using the given function object 76 | 11. an apply member function that takes a unary function argument and returns (conceptually) a new valarray where the function has been applied to each element in the valarray. Of course, this apply method must follow all the rules for lazy evaluation (i.e., it won’t return a real valarray, but rather some sort of expression template). 77 | 12. a sqrt member function that is implemented by passing a sqrt function object to the apply member function. The element type created from sqrt will either be double (for input valarrays that were int, float or double originally), or will be std::complex\ for valarrays that were originally std::complex\ or std::complex\ originally. 78 | 79 | ### General Notes: ### 80 | 1. The statement: z = x op y should set z[k] = x[k] op y[k] for all k and for any binary operator op. A reasonable subset of the binary and unary operators must be supported. 81 | 2. If the two operands are of differing length, the length of the result should be the minimun of the lengths of the two operands (ignore values past the end of the longer operand). 82 | 3. If one of the operands is a scalar, you should add (or whatever operation is implied) that scalar value to each of the elements in the valarray. In other words, you should implicitly expand the scalar to be a valarray of the appropriate length. But DON'T actually create this implied valarray. 83 | 4. If x,y,z,w are valarrays, optimize the execution of statements like z = ( x * y ) + w so that only one loop gets executed and no temporary arrays are allocated. 84 | 5. Type promotion should be to the strictest type acceptable for the operation to occur – e.g., if a valarray\ is added to a complex\ the result should be a valarray\\>. If a valarray is added to a complex\ then the result should be a valarray\\>. 85 | 86 | Here is how I implemented [Valarray.h](./lab2/Valarray.h). 87 | 88 | ## Project3. LifeForm Simulation (OOP) ## 89 | 90 | This project is to complete the simulation infrastructure that we get from the instructor and also to invent at least one new LifeForm and simulate the LifeForm's existance (or evolution) of that LifeForm. 91 | 92 | ### Overview: ### 93 | 1. Events: We use the make_procedure function to create function objects as described in class. Events can then be dynamically allocated. The Event constructor takes a time and a procedure. The procedure will be called that many time units into the future (the time is relative, not absolute). Creating an event automatically puts the event in the central event queue. Events automatically delete themselves when they occur. If we delete an event before it occurs it automatically removes itself from the event queue. 94 | 2. Region of space(quadtree): We use the QuadTree\ data structure to represent space. 95 | 3. How to move around: 96 | - LifeForm::update_position(void) - computes the new position, charge for energy consumed. 97 | - LifeForm::border_cross(void) - movement event handler function. It calls update_position and then schedules the next movement event. 98 | - LifeForm::region_resize(void) - this function will be a callback from the QuadTree. When another object is created nearby, the object needs to determine the next possible time that they could collide. The QuadTree knows when objects are inserted inside it, so it can invoke this callback function on your objects. We have to have region_resize cancel any pending border crossing events, update the position, and schedule the next movement event (since the region has changed size, we will encounter the boundary at a different time than before.) 99 | - LifeForm::set_course and LifeForm::set_speed - These functions should cancel any pending border_cross event, update the current position of the object and then schedule a new border_cross event based on the new course and speed. Note that an object that is stationary will never cross a border. 100 | 4. Creation of LifeForms: LifeForms cannot be created spontaneously and just expect to be simulated. There are two ways that LifeForms can be created. First, they can be created by the LifeForm::create_life method during initialization. The other way that objects can be created is by calling reproduce. 101 | 102 | ### Rules of the Game ### 103 | 1. Encounter: If two creatures ever get within one unit of distance of each other, they have an enounter. The encounter method returns either EAT or IGNORE. Since there are two LifeForms colliding, there are four cases; IGNORE/IGNORE, EAT/IGNORE, IGNORE/EAT and EAT/EAT. Provided at least one LifeForm attempts to eat, we need to generate a random number and compare the result to eat_success_chance(eater-\>energy, eatee-\>energy). 104 | 2. Names: There are two functions, player_name and species_name. By default, player_name returns the species name. The player name is used during the contest to select the winning LifeForms among all students in the class. The player_name is used only by the contest and only to print out which LifeForms are surviving (and which have become extinct). The species_name is used when objects collide with or perceive each other. The species_name can be anything we'd like. (We can lie to enemies in the species_name!!) 105 | 3. Perception: The perceive routine can be invoked by any derived LifeForm class at any time. max_perceive_range and min_perceive_range define the maximum and minimum radii for the perception circle. Each time an object attempts to perceive, it should be charged the perceive_cost. Note that perceive_cost is a function of the radius. The perceive function should return a list of ObjInfos. Each ObjInfo includes the name, bearing, speed, health and distance to the object. One ObjInfo should be placed into the list for every object within the prescribed radius. 106 | 4. Eating: Objects eat each other according to their desire (indicated by the return value of encounter) and their eat_success_chance (defined in Params.h). If object A wants to eat object B, then the simulator should generate a random number and compare it to the eat_success_chance(A, B). If the random number is less than the eat success chance, then A gets to eat B. B could also be trying to eat A at the same time. Params.h includes a variable called encounter_strategy which explains how to break the tie. Once we've figured out who got to eat whom, we have to award the victor the spoils. The energy is awarded to the eatee after exactly digestion_time time units have passed (create an event). The energy awarded is reduced by the eat_efficiency multiplier. (Since eat_efficiency is less than 1, it is usually not a good idea to eat your own young!!) 107 | 5. Aging: Objects must eventually die if they don't eat. This is true even if they act like rocks and don't move and don't perceive. Not all LifeForms are born at the same time (some are children of other LifeForms) and so they shouldn't be penalized at the same time. 108 | 6. Reproduction: When a LifeForm reproduces, the energy from the parent LifeForm is divided in half. This amount of energy is given to both the parent and the child. Then, the fractional reproduce_cost is subtracted from both the parent and the child. For example, a LifeForm with 100 energy that reproduces will produce a child that has 50 * (1.0 - reproduce_cost) energy. The parent will have the same energy as the child. As a special rule, do not allow an object to reproduce faster than min_reproduce_time. 109 | 110 | Here is how I implemented [LifeForm.cpp](./lab3/LifeForm.cpp). 111 | -------------------------------------------------------------------------------- /lab1/Vector.h: -------------------------------------------------------------------------------- 1 | #ifndef _VECTOR_H_ 2 | #define _VECTOR_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /* 10 | * Utility gives std::rel_ops which will fill in relational 11 | * iterator operations so long as you provide the 12 | * operators discussed in class. In any case, ensure that 13 | * all operations listed in this website are legal for your 14 | * iterators: 15 | * http://www.cplusplus.com/reference/iterator/RandomAccessIterator/ 16 | */ 17 | 18 | using namespace std::rel_ops; 19 | 20 | namespace epl{ 21 | class invalid_iterator { 22 | public: 23 | enum SeverityLevel {SEVERE,MODERATE,MILD,WARNING}; 24 | SeverityLevel level; 25 | 26 | invalid_iterator(SeverityLevel level = SEVERE){ this->level = level; } 27 | virtual const char* what() const { 28 | switch(level){ 29 | case WARNING: return "Warning"; // not used in Spring 2015 30 | case MILD: return "Mild"; 31 | case MODERATE: return "Moderate"; 32 | case SEVERE: return "Severe"; 33 | default: return "ERROR"; // should not be used 34 | } 35 | } 36 | }; 37 | 38 | template 39 | class vector { 40 | private: 41 | /* constant */ 42 | static constexpr uint64_t MIN_CAPACITY = 8; 43 | 44 | /* data member */ 45 | T* cap; // start address of the allocated storage 46 | T* len; // start address of constructed elements in the vector 47 | uint64_t capacity; // storage size 48 | uint64_t length; // vector size (number of elements) 49 | uint64_t modification; // version number for vector modification 50 | uint64_t reallocation; // version number for memory reallocation 51 | 52 | /* nested class: iterator */ 53 | template 54 | class iterator_base : public std::iterator { 55 | private: 56 | /* type alias */ 57 | using data_structure_pointer_type = typename std::conditional::type; 58 | using value_reference_type = typename std::conditional::type; 59 | using value_pointer_type = typename std::conditional::type; 60 | 61 | /* data member */ 62 | data_structure_pointer_type ds; 63 | int64_t offset; 64 | uint64_t modification_snapshot; 65 | uint64_t reallocation_snapshot; 66 | public: 67 | /* type alias */ 68 | using typename std::iterator::iterator_category; 69 | using typename std::iterator::value_type; 70 | using typename std::iterator::difference_type; 71 | using typename std::iterator::pointer; 72 | using typename std::iterator::reference; 73 | 74 | /* copy-constructible, copy-assignable and destructible */ 75 | iterator_base() 76 | : ds{ nullptr }, 77 | offset{ 0 }, 78 | modification_snapshot{ 0 }, 79 | reallocation_snapshot{ 0 } 80 | {} 81 | 82 | iterator_base(data_structure_pointer_type ds, int64_t offset, uint64_t modification, uint64_t reallocation) 83 | : ds{ ds }, 84 | offset{ offset }, 85 | modification_snapshot{ modification }, 86 | reallocation_snapshot{ reallocation } 87 | {} 88 | 89 | iterator_base(iterator_base const& that) { iterator_base::copy(that); } 90 | 91 | iterator_base& operator=(iterator_base const& that) { 92 | if (this != &that) { 93 | copy(that); 94 | } 95 | return *this; 96 | } 97 | 98 | ~iterator_base() {} 99 | 100 | /* 101 | * an iterator can be converted (without warnings or type 102 | * casts) to const_iterator 103 | */ 104 | operator iterator_base(void) { 105 | return iterator_base(ds, offset, modification_snapshot, reallocation_snapshot); 106 | } 107 | 108 | /* Can be incremented */ 109 | iterator_base& operator++(void) { // pre-increment operator, e.g. ++it 110 | assert_valid(); 111 | ++offset; 112 | return *this; 113 | } 114 | 115 | iterator_base operator++(int) { // post-increment operator, e.g. it++ 116 | iterator_base t{ *this }; 117 | operator++(); 118 | return t; 119 | } 120 | 121 | /* Supports equality/inequality comparisons */ 122 | bool operator==(iterator_base const& that) const { 123 | assert_valid(); 124 | that.assert_valid(); 125 | return ds == that.ds && offset == that.offset; 126 | } 127 | 128 | /* Can be dereferenced */ 129 | value_reference_type operator*(void) const { 130 | assert_valid(); 131 | return (*ds)[offset]; 132 | } 133 | 134 | value_pointer_type operator->(void) const { 135 | return &(operator*()); 136 | } 137 | 138 | /* Can be decremented */ 139 | iterator_base& operator--(void) { // pre-decrement operator, e.g. --it 140 | assert_valid(); 141 | --offset; 142 | return *this; 143 | } 144 | 145 | iterator_base operator--(int) { // post-decrement operator, e.g. it--; 146 | iterator_base t{ *this }; 147 | operator--(); 148 | return t; 149 | } 150 | 151 | /* Supports compound assignment operations += and -= */ 152 | iterator_base& operator+=(int64_t k) { 153 | assert_valid(); 154 | offset += k; 155 | return *this; 156 | } 157 | 158 | iterator_base& operator-=(int64_t k) { 159 | operator+=(-k); 160 | return *this; 161 | } 162 | 163 | /* Supports arithmetic operators + and - */ 164 | iterator_base operator+(int64_t k) const { 165 | iterator_base t{ *this }; 166 | return t += k; 167 | } 168 | 169 | iterator_base operator-(int64_t k) const { 170 | iterator_base t{ *this }; 171 | return t -= k; 172 | } 173 | 174 | difference_type operator-(iterator_base const& that) const { 175 | assert_valid(); 176 | that.assert_valid(); 177 | return offset - that.offset; 178 | } 179 | 180 | /* Supports inequality comparisons (<, >, <= and >=) between iterators */ 181 | bool operator<(iterator_base const& that) const { 182 | return *this - that < 0; 183 | } 184 | 185 | /* Supports offset dereference operator ([]) */ 186 | value_reference_type operator[](uint64_t k) const { 187 | return *(*this + k); 188 | } 189 | private: 190 | void copy(iterator_base const& that) { 191 | ds = that.ds; 192 | offset = that.offset; 193 | modification_snapshot = that.modification_snapshot; 194 | reallocation_snapshot = that.reallocation_snapshot; 195 | } 196 | 197 | void assert_valid(void) const { 198 | bool is_modified = (modification_snapshot != ds->modification); 199 | bool is_reallocated = (reallocation_snapshot != ds->reallocation); 200 | bool is_inbound = (offset >= 0 && offset < ds->length); 201 | 202 | if (is_modified || is_reallocated) { 203 | if (!is_inbound) 204 | throw invalid_iterator(invalid_iterator::SEVERE); 205 | else if (is_reallocated) 206 | throw invalid_iterator(invalid_iterator::MODERATE); 207 | else 208 | throw invalid_iterator(invalid_iterator::MILD); 209 | } 210 | } 211 | }; 212 | public: 213 | using const_iterator = iterator_base; 214 | using iterator = iterator_base; 215 | 216 | vector(void) { 217 | init(MIN_CAPACITY); 218 | } 219 | 220 | explicit vector(uint64_t n) { 221 | if (n) { 222 | init(n); 223 | length = n; 224 | for (uint64_t i = 0; i < n; i += 1) { 225 | new (len + i) T{}; 226 | } 227 | } 228 | else { 229 | vector(); 230 | } 231 | } 232 | 233 | vector(vector const& that) { 234 | copy(that); 235 | } 236 | 237 | vector(vector&& that) { 238 | move(std::move(that)); 239 | } 240 | 241 | template 242 | vector(IT b, IT e) : vector(b, e, typename std::iterator_traits::iterator_category{}) {} 243 | 244 | template 245 | vector(IT b, IT e, std::random_access_iterator_tag) { 246 | init(e - b); 247 | length = 0; 248 | while (b != e) { 249 | new (len + length) T{ *b }; 250 | ++b; 251 | ++length; 252 | } 253 | } 254 | 255 | template 256 | vector(IT b, IT e, std::input_iterator_tag) : vector() { 257 | while (b != e) { 258 | push_back(*b); 259 | ++b; 260 | } 261 | } 262 | 263 | vector(std::initializer_list list): vector(list.begin(), list.end()) {} 264 | 265 | vector& operator=(vector const& that) { 266 | if (this != &that) { 267 | destroy(); 268 | copy(that); 269 | } 270 | return *this; 271 | } 272 | 273 | vector& operator=(vector&& that) { 274 | if (this != &that) { 275 | destroy(); 276 | move(std::move(that)); 277 | } 278 | return *this; 279 | } 280 | 281 | ~vector() { 282 | destroy(); 283 | } 284 | 285 | /* Member Function Group: Capacity */ 286 | uint64_t size(void) const { 287 | return length; 288 | } 289 | 290 | /* Member Function Group: Element Access */ 291 | T const& operator[](uint64_t n) const { 292 | if (n >= length) { 293 | throw std::out_of_range{ "index out of range" }; 294 | } 295 | return len[n]; 296 | } 297 | 298 | T& operator[](uint64_t n) { 299 | return const_cast(static_cast(*this)[n]); 300 | } 301 | 302 | 303 | /* Member Function Group: Modifiers */ 304 | void pop_back(void) { 305 | if (!length) { 306 | throw std::out_of_range{ "fatal error: popping from an empty vector" }; 307 | } 308 | (len + length - 1) -> ~T(); 309 | length -= 1; 310 | modification += 1; 311 | } 312 | 313 | void pop_front(void) { 314 | if (!length) { 315 | throw std::out_of_range{ "fatal error: popping from an empty vector" }; 316 | } 317 | len -> ~T(); 318 | len++; 319 | length -= 1; 320 | modification += 1; 321 | } 322 | 323 | /* 324 | * Since ensure_back_capacity will destroy original vector, 325 | * if it is the element of original vector that is to be push_back 326 | * a segmentation fault will occur. That's why I need a temp. 327 | * Example: 328 | * vector> x(8); 329 | * x[0].push_front(Foo()); 330 | * x.push_back(x[0]); 331 | */ 332 | void push_back(T const& elem) { 333 | T temp{ elem }; 334 | ensure_back_capacity(1); 335 | new (len + length) T{ std::move(temp) }; 336 | length += 1; 337 | modification += 1; 338 | } 339 | 340 | void push_back(T&& elem) { 341 | T temp{ std::move(elem) }; 342 | ensure_back_capacity(1); 343 | new (len + length) T{ std::move(temp) }; 344 | length += 1; 345 | modification += 1; 346 | } 347 | 348 | void push_front(T const& elem) { 349 | T temp{ elem }; 350 | ensure_front_capacity(1); 351 | new (len - 1) T{ std::move(temp) }; 352 | len--; 353 | length += 1; 354 | modification += 1; 355 | } 356 | 357 | void push_front(T&& elem) { 358 | T temp{ std::move(elem) }; 359 | ensure_front_capacity(1); 360 | new(len - 1) T{ std::move(temp) }; 361 | len--; 362 | length += 1; 363 | modification += 1; 364 | } 365 | 366 | template 367 | void emplace_back(Args... args) { 368 | ensure_back_capacity(1); 369 | new (len + length) T{ std::forward(args)... }; 370 | length += 1; 371 | modification += 1; 372 | } 373 | 374 | /* Member Function Group: Iterators */ 375 | const_iterator begin(void) const { 376 | return const_iterator(this, 0, modification, reallocation); 377 | } 378 | 379 | const_iterator end(void) const { 380 | return const_iterator(this, length, modification, reallocation); 381 | } 382 | 383 | iterator begin(void) { 384 | return iterator(this, 0, modification, reallocation); 385 | } 386 | 387 | iterator end(void) { 388 | return iterator(this, length, modification, reallocation); 389 | } 390 | private: 391 | void init(uint64_t n) { 392 | cap = static_cast(::operator new(n * sizeof(T))); 393 | len = cap; 394 | capacity = n; 395 | length = 0; 396 | modification = 0; 397 | reallocation = 0; 398 | } 399 | 400 | void copy(vector const& that) { 401 | capacity = that.capacity; 402 | length = that.length; 403 | cap = static_cast(::operator new(capacity * sizeof(T))); 404 | len = cap + (that.len - that.cap); 405 | for (uint64_t i = 0; i < length; i += 1) { 406 | new (len + i) T{ that[i] }; 407 | } 408 | reallocation += 1; 409 | } 410 | 411 | void move(vector&& that) { 412 | capacity = that.capacity; 413 | length = that.length; 414 | cap = that.cap; 415 | len = that.len; 416 | that.cap = nullptr; 417 | that.len = nullptr; 418 | /* 419 | * the storage cap points to is different, 420 | * it can be considered as a kind of 421 | * "reallocation" 422 | */ 423 | reallocation += 1; 424 | that.reallocation += 1; 425 | } 426 | 427 | void destroy(void) { 428 | if (len) { 429 | for (uint64_t i = 0; i < length; i += 1) { 430 | (len + i) -> ~T(); 431 | } 432 | } 433 | if (cap) { 434 | ::operator delete(cap); 435 | } 436 | } 437 | 438 | void ensure_back_capacity(uint64_t capacity_required) { 439 | uint64_t back_capacity = (cap + capacity) - (len + length); 440 | 441 | if (back_capacity >= capacity_required) return; 442 | 443 | uint64_t new_capacity = capacity; 444 | while (back_capacity < capacity_required) { 445 | new_capacity += capacity; 446 | back_capacity += capacity; 447 | } 448 | 449 | T* new_cap = static_cast(::operator new(new_capacity * sizeof(T))); 450 | T* new_len = new_cap + (len - cap); 451 | 452 | for (uint64_t i = 0; i < length; i += 1) { 453 | new (new_len + i) T{ std::move(len[i]) }; 454 | (len + i) -> ~T(); 455 | } 456 | 457 | ::operator delete(cap); 458 | 459 | cap = new_cap; 460 | len = new_len; 461 | capacity = new_capacity; 462 | reallocation += 1; 463 | } 464 | 465 | void ensure_front_capacity(uint64_t capacity_required) { 466 | uint64_t front_capacity = len - cap; 467 | if (front_capacity >= capacity_required) return; 468 | 469 | uint64_t new_capacity = capacity; 470 | while (front_capacity < capacity_required) { 471 | new_capacity += capacity; 472 | front_capacity += capacity; 473 | } 474 | 475 | T* new_cap = static_cast(::operator new(new_capacity * sizeof(T))); 476 | T* new_len = new_cap + new_capacity - length - ((cap + capacity) - (len + length)); 477 | 478 | for (uint64_t i = 0; i < length; i += 1) { 479 | new (new_len + i) T{ std::move(len[i]) }; 480 | (len + i) -> ~T(); 481 | } 482 | ::operator delete(cap); 483 | 484 | cap = new_cap; 485 | len = new_len; 486 | capacity = new_capacity; 487 | reallocation += 1; 488 | } 489 | }; 490 | } //namespace epl 491 | 492 | #endif 493 | -------------------------------------------------------------------------------- /lab3/QuadTree.h: -------------------------------------------------------------------------------- 1 | #if !(_QuadTree_h) 2 | #define _QuadTree_h 1 3 | #include 4 | #include 5 | 6 | /* 7 | * I use "region" to refer to a TreeNode. Usually, I'm referring to a leaf 8 | * Hopefully, the meaning is clear from context 9 | * 10 | * On insert and remove events the tree changes size. Some objects that 11 | * are in the tree may see the size of their enclosing region change. 12 | * During simulation, it is important to know of these changes. So, 13 | * each object has a "callback" (a Procedure0 object) that is inserted with 14 | * it into the tree. When the object's region is resized, the callback is 15 | * called. Note, the callback should be invoked only after the insert 16 | * or remove operation is completed (that is, QuadTree invokes the 17 | * callback, not TreeNode). This ensures that the tree is at a stable 18 | * state before the callback is invoked. 19 | * 20 | * === IMPORTANT note on resize callbacks === 21 | * It is difficult to see at first, but... 22 | * during an insert event, at most one existing object will have its 23 | * region resized. That is, if we are inserting object 'x', then there 24 | * is at most one other object (object y) that will have its region 25 | * resized as a result of x's insertion. This is because an object is 26 | * only inserted into a leaf. During insertion, we decend the tree until 27 | * we find a leaf. We resize that leaf if it contains an object. Although 28 | * we may resize that leaf many times, it's always the same two objects that 29 | * are involved (the new one). 30 | * 31 | * Similarly, if we are removing object x, then there is at most one 32 | * other object (object y) that will have its region resized as 33 | * a result of y's insertion. This is because the only way a region 34 | * is resized is when a region has exactly one sibling region that contains 35 | * an object. When the sibling region has its object removed, then 36 | * all four siblings are collapsed into their parent. If three siblings 37 | * had objects, and one was removed, the region would not be resized. 38 | */ 39 | 40 | /* 41 | * EE380L NOTE: 42 | * there's a bug minor inaccuracy in the simulation that could be fixed 43 | * by using the quad tree in a slightly different way 44 | * 45 | * the defect is that we can have a "false encounter" in the following 46 | * circumstance 47 | * ------------- 48 | * | | | 49 | * | y->| | 50 | * |-----+-----| 51 | * | |x | 52 | * | | | 53 | * ------------- 54 | * 55 | * where x and y are objects and y is moving to the right. 56 | * y does not enter x's region, so x does not experience a resize event. 57 | * y may be arbitrarily close to x, close enough to have an encounter. 58 | * however, the position that is used will be x's old position. 59 | * note that if y moved into x's region, the region resize callback 60 | * can update x's position variable. That is, in *most* cases, 61 | * false encounters do not occur. Only an objects most up-to-date position 62 | * is used when determining an encounter. 63 | * 64 | * anyway, this defect can be fixed by invoking the resize callback (or 65 | * some similar mechanism) on all objects that are inside regions that 66 | * intersect the unit circle about y. 67 | * that is, take the encounter distance (currently 1.0 units), and put 68 | * a circle around y *after* it has moved. Any region that intersects 69 | * that circle may contain an object that has moved into or out of the 70 | * circle since its position variable was last updated. So, any object 71 | * in those regions should have its position updated 72 | * 73 | * note that such an object doesn't need a new border_cross_event defined 74 | * (its region hasn't changed size). We just need up-to-date position info 75 | * before we test for an encounter. We know that 'y' cannot encounter 76 | * any objects in any other regions, so we should only update those 77 | * object in regions sufficiently close by 78 | * 79 | * 80 | * CODING NOTE: there should be more 'const' member functions on the QuadTree 81 | * 82 | */ 83 | 84 | 85 | #include 86 | #include 87 | #include 88 | #include "Point.h" 89 | 90 | template class TreeNode; // used for implementation of the QuadTree 91 | 92 | template 93 | /* NOTE class Obj must implement 94 | Point position(void) const; 95 | This function will return the current position of the object 96 | */ 97 | class QuadTree { 98 | TreeNode* root; 99 | Point uleft, lright; // not really needed, as "root" duplicates 100 | // this data, but having the copies of the 101 | // boundary points is convenient 102 | 103 | /* COPYING is NOT YET DEFINED NOR PERMITTED */ 104 | QuadTree(const QuadTree&) { assert(0); } 105 | QuadTree& operator=(const QuadTree&) { 106 | assert(0); 107 | return *this; 108 | } 109 | public: 110 | // insert a *reference* to the object into the 111 | // tree. It is an error to insert an object 112 | // which 'is_out_of_bounds'. 113 | void insert(const Obj&, const Point& pos, std::function = [](){}); 114 | 115 | Obj remove(const Point&); 116 | // find the identical object 'x' in the tree 117 | // and remove it. It is an error to attempt 118 | // to remove an object that is not in the tree 119 | 120 | Obj closest(const Point&) const; // find the (cartesian distance) closest Obj 121 | // to the specified point. The QuadTree must 122 | // not be empty (i.e., there must be a closest 123 | // object) 124 | 125 | std::vector nearby(const Point& center, double radius) const; 126 | // return a vector of Objs that are within 127 | // the specified circle 128 | // the object located at the center of the 129 | // circle is not included in the list 130 | // (objects are not "nearby" to themselves) 131 | 132 | bool is_out_of_bounds(const Point&) const; // return true iff the Point is outside 133 | // the boundaries of this QuadTree 134 | 135 | double distance_to_edge(const Point& p, double rads) const; // return the distance 136 | // between 'p' and the next edge to be crossed 137 | // if one continues to travel in direction 138 | // 'rads' (in radians). 139 | 140 | bool is_occupied(const Point&) const; // return true if the position is 141 | // already occupied by some other object 142 | 143 | void update_position(const Point&, const Point&) ; 144 | // updates position of object to new position 145 | 146 | 147 | QuadTree(double xmin, double ymin, double xmax, double ymax) { 148 | uleft = Point(xmin,ymax); 149 | lright = Point(xmax,ymin); 150 | root = new TreeNode(uleft, lright); 151 | } 152 | 153 | ~QuadTree(void); 154 | }; 155 | 156 | template 157 | class TreeNode { 158 | typedef std::pair> Result; 159 | 160 | Obj obj; // the object that is in this region 161 | // (valid only if num_objects == 1) 162 | 163 | Point obj_pos; // the location of the object 164 | // (valid only if num_objects == 1) 165 | 166 | std::function resize_event; // a callback that should be invoked when 167 | // this region is either merged or split 168 | 169 | typedef TreeNode* TNPtr; 170 | TNPtr *child; // an array of four pointers to children; 171 | // we maintain the invariant that child is 172 | // always NULL unless 173 | // a) there exists two or more children 174 | // that are non-empty OR 175 | // b) one child has decendents with two 176 | // or more objects. 177 | 178 | unsigned num_objects; // the number of objects inside this region 179 | // (including objects inside my children) 180 | 181 | void split(void) { 182 | child = new TNPtr[4]; 183 | double x = right() - left(); 184 | double y = top() - bottom(); 185 | double halfx = x / 2.0; 186 | double halfy = y / 2.0; 187 | 188 | /* 1st quadrant (the upper right quad) */ 189 | child[0] = new TreeNode(uleft() + Point(halfx, 0), 190 | lright() + Point(0, halfy)); 191 | 192 | /* 2nd quadrant (upper left quad) */ 193 | child[1] = new TreeNode(uleft(), uleft() + Point(halfx, -halfy)); 194 | 195 | /* 3rd quadrant (lower left quad) */ 196 | child[2] = new TreeNode(uleft() + Point(0, -halfy), 197 | lright() + Point(-halfx, 0)); 198 | 199 | /* 3th quadrant (lower right quad) */ 200 | child[3] = new TreeNode(uleft() + Point(halfx, -halfy), lright()); 201 | 202 | unsigned k; // checked at end of "for" loop 203 | std::function dummy = [](){}; // not used 204 | for (k = 0; k < 4; k++) { 205 | if (child[k]->in_bounds(obj_pos)) { 206 | bool tmp = child[k]->insert(obj, obj_pos, resize_event, dummy); 207 | assert(tmp); 208 | break; 209 | } 210 | } 211 | assert(k < 4); 212 | } 213 | 214 | void merge() { 215 | assert(num_objects == 1); // must have exactly one obj 216 | 217 | /* take the object from our child */ 218 | for (unsigned k = 0; k < 4; k++) { 219 | if (!child[k]->is_empty()) { 220 | obj = child[k]->obj; 221 | obj_pos = child[k]->obj_pos; 222 | resize_event = child[k]->resize_event; 223 | } 224 | delete child[k]; 225 | } 226 | 227 | delete[] child; 228 | child = 0; 229 | } 230 | 231 | /* 232 | * does a circle centered about 'center' with radius 'dist' 233 | * intersect any part of the current region? 234 | * 235 | * Technique: find the point on the boundary of this region and 236 | * measure the distance between that point and 'center' 237 | * 238 | * NOTE: this code assumes all four boundary edges are inside 239 | * the region (usually we assume only the top and left edges 240 | * are inside). 241 | */ 242 | bool intersects(const Point& center, double dist) const { 243 | if (in_bounds(center)) return true; 244 | 245 | double xval, yval; // x and y coords of point on boundary 246 | // nearest center 247 | // NOTE: the following code assumes that 248 | // 'center' is not inside this region 249 | 250 | xval = center.xpos; yval = center.ypos; 251 | 252 | if (xval < left()) xval = left(); 253 | if (xval > right()) xval = right(); 254 | if (yval < bottom()) yval = bottom(); 255 | if (yval > top()) yval = top(); 256 | 257 | Point edge_pt(xval, yval); // this is the point on the edge closest to 258 | // 'center' 259 | 260 | return (center.distance(edge_pt) <= dist); 261 | } 262 | 263 | 264 | TreeNode(const TreeNode&) { assert(0); } 265 | TreeNode& operator=(const TreeNode&) { 266 | assert(0); 267 | return *this; 268 | } 269 | 270 | /* return which of the four child quadrants is closest to 'center' */ 271 | unsigned nearest_region(const Point& center) const { 272 | 273 | /* assume quadrant 1 is closest to the object */ 274 | unsigned region = 0; 275 | double best_dist = center.distance(uright()); 276 | double d; 277 | 278 | /* check if quadrant 2 is closer */ 279 | d = center.distance(uleft()); 280 | if (d < best_dist) { 281 | best_dist = d; 282 | region = 1; 283 | } 284 | 285 | /* check if quadrant 3 is closer */ 286 | d = center.distance(lleft()); 287 | if (d < best_dist) { 288 | best_dist = d; 289 | region = 2; 290 | } 291 | 292 | /* check if quadrant 4 is closer */ 293 | d = center.distance(lright()); 294 | if (d < best_dist) { 295 | best_dist = d; 296 | region = 3; 297 | } 298 | 299 | return region; 300 | } 301 | 302 | 303 | Point _uleft; // upper left corner 304 | Point _lright; // lower right corner 305 | public: 306 | 307 | const Point& uleft(void) const { return _uleft; } 308 | const Point& lright(void) const { return _lright; } 309 | Point lleft(void) const { return Point(uleft().xpos, lright().ypos); } 310 | Point uright(void) const { return Point(lright().xpos, uleft().ypos); } 311 | double left(void) const { return uleft().xpos; } 312 | double right(void) const { return lright().xpos; } 313 | double top(void) const { return uleft().ypos; } 314 | double bottom(void) const { return lright().ypos; } 315 | 316 | std::function get_callbk(void) const { return resize_event;} 317 | 318 | TreeNode(const Point& _uleft, const Point& _lright) { 319 | this->_uleft = _uleft; this->_lright = _lright; 320 | child = (TNPtr*) 0; 321 | num_objects = 0; 322 | } 323 | 324 | ~TreeNode(void) { 325 | if (child) { 326 | for (unsigned k = 0; k < 4; k++) 327 | delete child[k]; 328 | delete[] child; 329 | } 330 | } 331 | 332 | bool is_leaf(void) const { return child == (const TNPtr*) 0; } 333 | 334 | bool is_empty(void) const { return (num_objects == 0) && is_leaf(); } 335 | 336 | bool in_bounds(const Point& p) const { 337 | return p.xpos >= left() && 338 | p.ypos <= top() && 339 | p.xpos < right() && 340 | p.ypos > bottom(); 341 | } 342 | 343 | /* new_resize is the callback for newobj 344 | invoke_this is an output parameter. It is the resize callback for 345 | the object who's region gets resized */ 346 | bool insert(const Obj& newobj, const Point& pos, std::function new_resize, 347 | std::function& invoke_this) { 348 | if (! in_bounds(pos)) return false; 349 | 350 | if (is_empty()) { 351 | obj = newobj; 352 | obj_pos = pos; 353 | resize_event = new_resize; 354 | num_objects += 1; 355 | return true; 356 | } 357 | else { 358 | if (child == (const TNPtr*) 0) { 359 | invoke_this = resize_event; 360 | split(); 361 | } 362 | unsigned k; // checked at end of for loop 363 | for (k = 0; k < 4; k++) 364 | if (child[k]->insert(newobj, pos, new_resize, invoke_this)) break; 365 | assert(k < 4); 366 | num_objects += 1; 367 | return true; 368 | } 369 | 370 | /* NOT REACHED */ 371 | } 372 | 373 | bool remove(const Point& pos, Obj& oldobj, std::function& invoke_this) { 374 | if (!in_bounds(pos)) return false; 375 | assert(num_objects > 0); 376 | 377 | /* first, simply remove the object, and keep 'num_objects' correct */ 378 | if (num_objects == 1) { 379 | if (pos != obj_pos) { 380 | std::cout << "oh shit\n"; 381 | } 382 | assert(pos == obj_pos); 383 | oldobj = obj; 384 | resize_event = std::function(); 385 | num_objects -= 1; 386 | } 387 | else { 388 | assert(child != (TNPtr*) 0); 389 | unsigned k; // checked at end of "for" loop 390 | for (k = 0; k < 4; k++) { 391 | if (child[k]->in_bounds(pos)) { 392 | bool tmp = child[k]->remove(pos, oldobj, invoke_this); 393 | assert(tmp); 394 | break; 395 | } 396 | } 397 | assert(k < 4); 398 | num_objects -= 1; 399 | } 400 | 401 | /* second, clean up so that our invariants are maintained */ 402 | if (num_objects == 1) { 403 | merge(); 404 | invoke_this = resize_event; 405 | } 406 | 407 | return true; 408 | } 409 | 410 | 411 | /* 412 | * return the vector of objects (not including one at 'center') that 413 | * are inside this region, and also not more than 'dist' units 414 | * away from 'center' 415 | */ 416 | void find_nearby(std::vector& list, const Point& center, 417 | double dist) const { 418 | if (is_empty()) return; 419 | if (! intersects(center, dist)) return; 420 | 421 | if (num_objects == 1) { 422 | if (obj_pos != center && center.distance(obj_pos) <= dist) 423 | list.push_back(obj); 424 | } 425 | else { 426 | for (unsigned k = 0; k < 4; k++) { 427 | child[k]->find_nearby(list, center, dist); 428 | } 429 | } 430 | } 431 | 432 | /* 433 | * return the closest object to 'center' that is within this region 434 | * (other than 'center' itself). Consider only objects that are 435 | * at most dist' units away 436 | * 437 | * if no object can be found, return a pair with 'first' == false 438 | * 439 | * Technique: search the sub regions in order to minimize search time 440 | * Do this by searching first inside the nearest region to 441 | * 'center.position()' 442 | */ 443 | std::pair closest(const Point& center, double& dist) const { 444 | /* three cases, 0 objects, 1 object or more than one object 445 | are in this region */ 446 | if (! intersects(center, dist)) 447 | return std::pair(false, Obj()); 448 | 449 | if (num_objects == 0) 450 | return std::pair(false, Obj()); 451 | 452 | else if (num_objects == 1) { 453 | double d = center.distance(obj_pos); 454 | if (d < dist && obj_pos != center) { 455 | dist = d; 456 | return std::pair(true, obj); 457 | } 458 | else return std::pair(false, Obj()); 459 | } 460 | 461 | else if (num_objects > 1) { // "else if" is for documentation purposes 462 | // (must be the case that num_object > 1) 463 | std::pair result(false, Obj()); 464 | 465 | unsigned first_region = nearest_region(center); 466 | 467 | for (unsigned k = 0; k < 4; k++) { 468 | unsigned region = (k + first_region) % 4; 469 | std::pair tmp = child[region]->closest(center, dist); 470 | if (tmp.first) result = tmp; 471 | } 472 | return result; 473 | } 474 | /* NOT REACHED */ 475 | return std::pair(); 476 | } 477 | 478 | /* return the leaf node where this object would be (or is) in the tree */ 479 | /* For the meantime replace Nil > with (TNPtr) 0 */ 480 | 481 | std::pair< TreeNode*, TreeNode*> 482 | find_leaf(const Point& pos, const TreeNode* parent= (TNPtr)0 ) const 483 | { 484 | assert(in_bounds(pos)); 485 | if (is_leaf()) return std::make_pair( (TNPtr)this, (TNPtr)parent); 486 | else { 487 | for (unsigned k = 0; k < 4; k++) { 488 | if (child[k]->in_bounds(pos)) 489 | return child[k]->find_leaf(pos, this); 490 | } 491 | /* NOT REACHED */ 492 | assert(0); 493 | return std::make_pair( (TNPtr) 0, (TNPtr) 0); 494 | } 495 | /* NOT REACHED */ 496 | } 497 | 498 | bool is_occupied(const Point& x) const { 499 | const TreeNode* leaf = find_leaf(x).first; 500 | if (leaf->is_empty()) return false; 501 | else 502 | return leaf->obj_pos == x; 503 | } 504 | 505 | unsigned check_tree(void) const { 506 | if (is_leaf()) { 507 | assert(num_objects < 2); 508 | return num_objects; 509 | } 510 | else { 511 | unsigned child_nums = 0; 512 | for (int k = 0; k < 4; ++k) 513 | child_nums += child[k]->check_tree(); 514 | assert(num_objects == child_nums && child_nums > 1); 515 | return child_nums; 516 | } 517 | } 518 | 519 | friend class QuadTree; 520 | }; 521 | 522 | 523 | template 524 | QuadTree::~QuadTree(void) { 525 | delete root; 526 | } 527 | 528 | template 529 | void QuadTree::insert(const Obj& obj, const Point& pos, 530 | std::function resize) { 531 | std::function callback = [](){}; 532 | bool is_ok = root->insert(obj, pos, resize, callback); 533 | assert(is_ok); 534 | callback(); 535 | } 536 | 537 | template 538 | Obj QuadTree::remove(const Point& pos) { 539 | std::function callback = [](){}; 540 | Obj result; 541 | bool is_ok = root->remove(pos, result, callback); 542 | assert(is_ok); 543 | callback(); 544 | return result; 545 | } 546 | 547 | template 548 | Obj QuadTree::closest(const Point& pos) const { 549 | double dist = HUGE; 550 | std::pair tmp = root->closest(pos, dist); 551 | assert(tmp.first); 552 | return tmp.second; 553 | } 554 | 555 | template 556 | std::vector QuadTree::nearby(const Point& pos, double dist) const { 557 | std::vector result; 558 | root->find_nearby(result, pos, dist); 559 | return result; 560 | } 561 | 562 | template 563 | bool QuadTree::is_out_of_bounds(const Point& pos) const { 564 | return ! root->in_bounds(pos); 565 | } 566 | 567 | template 568 | double QuadTree::distance_to_edge(const Point& pos, double course) const { 569 | assert(root != (TreeNode*) 0); 570 | const TreeNode* leaf = root->find_leaf(pos).first; 571 | assert(leaf != (TreeNode*) 0); 572 | 573 | double cos_theta = cos(course); 574 | double sin_theta = sin(course); 575 | 576 | double xdist = 0.0; // distance to nearest vertical boundary 577 | double ydist = 0.0; // distance to nearest horizontal boundary 578 | 579 | if (cos_theta < 0.0) // headed left 580 | xdist = pos.xpos - leaf->left(); 581 | else 582 | xdist = leaf->right() - pos.xpos; 583 | 584 | if (cos_theta < 0.0) cos_theta = - cos_theta; 585 | if (cos_theta > Point::tolerance) xdist = xdist / cos_theta; 586 | else xdist = HUGE; 587 | 588 | if (sin_theta > 0.0) // headed up 589 | ydist = leaf->top() - pos.ypos; 590 | else 591 | ydist = pos.ypos - leaf->bottom(); 592 | 593 | if (sin_theta < 0.0) sin_theta = - sin_theta; 594 | if (sin_theta > Point::tolerance) ydist = ydist / sin_theta; 595 | else ydist = HUGE; 596 | 597 | assert(xdist >= 0.0 && ydist >= 0.0); 598 | 599 | if (xdist < ydist) return xdist; 600 | else return ydist; 601 | } 602 | 603 | template 604 | bool QuadTree::is_occupied(const Point& pos) const { 605 | return root->is_occupied(pos); 606 | } 607 | 608 | 609 | template 610 | void QuadTree::update_position(const Point& pos_old, 611 | const Point& pos_new) { 612 | 613 | std::pair*, TreeNode*> res = root->find_leaf(pos_old); 614 | TreeNode* leaf = res.first; 615 | TreeNode* parent = res.second; 616 | if (pos_old != leaf->obj_pos) { 617 | std::cerr << "Object Position: (" << pos_old.xpos << ", " << pos_old.ypos << ")" << std::endl; 618 | std::cerr << "Leaf Position: (" << leaf->obj_pos.xpos << ", " << leaf->obj_pos.ypos << ")" << std::endl; 619 | } 620 | assert(pos_old == leaf->obj_pos); 621 | 622 | /* three cases: */ 623 | if (leaf->in_bounds(pos_new)) { // case 1: no callbacks 624 | /* for case 1 we know the object did not leave it's bounding leaf */ 625 | leaf->obj_pos = pos_new; 626 | } else if (parent->in_bounds(pos_new)) { // case 2: at most one callback 627 | /* for case 2 we know the object left it's bounding leaf, 628 | but it did not leaf the bounds of the parent node. 629 | In this case, we know that no leaves will be deleted as a result 630 | of moving this object. 631 | NOTE: new leaves may be created if the object is moving into an 632 | occupied sibling. */ 633 | std::function obj_callback = leaf->get_callbk(); 634 | 635 | /* remove the object FROM THE LEAF (not from the root) to 636 | avoid collapsing levels in the tree */ 637 | Obj obj; 638 | std::function null_callback = [](){}; // must be null since removing from a leaf 639 | bool remove_ok = leaf->remove(pos_old, obj, null_callback); 640 | parent->num_objects -= 1; 641 | assert(remove_ok); 642 | 643 | /* inserting from the parent level and inserting at the root level 644 | should be the same */ 645 | std::function insert_callback = [](){};; 646 | bool insert_ok = parent->insert(obj, pos_new, 647 | obj_callback, insert_callback); 648 | assert(insert_ok); 649 | 650 | /* tree is now stable, invoke the callback from inserting */ 651 | insert_callback(); 652 | } 653 | else { // case 3: up to two callbacks 654 | std::function obj_callback = leaf->get_callbk(); 655 | 656 | Obj obj; 657 | std::function remove_callback = [](){}; 658 | bool remove_ok = root->remove(pos_old, obj, remove_callback); 659 | assert(remove_ok); 660 | 661 | std::function insert_callback = [](){}; 662 | bool insert_ok = root->insert(obj, pos_new, obj_callback, insert_callback); 663 | assert(insert_ok); 664 | 665 | /* now the tree is stable, invoke both callbacks */ 666 | remove_callback(); 667 | insert_callback(); 668 | } 669 | 670 | #ifdef DEBUG_QUADTREE 671 | root->check_tree(); 672 | #endif /* DEBUG_QUADTREE */ 673 | 674 | } 675 | 676 | 677 | 678 | #endif /* !(_QuadTree_h) */ 679 | --------------------------------------------------------------------------------