summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorroot <root@bpcserver.bpcserver>2024-02-27 21:53:44 -0600
committerroot <root@bpcserver.bpcserver>2024-02-27 21:53:44 -0600
commitafa02f645056c5823b0d8a29d37c1ff10aedce7a (patch)
tree0bc89e7909c17d8f33538ac9f31a641872b89f40
-rw-r--r--.gitignore9
-rw-r--r--README.md2
-rw-r--r--city.cpp227
-rw-r--r--city.h164
-rw-r--r--coordinate.cpp45
-rw-r--r--coordinate.h70
-rw-r--r--cop.h48
-rw-r--r--cop.hpp48
-rw-r--r--gameObject.cpp29
-rw-r--r--gameObject.h81
-rw-r--r--grade.md10
-rw-r--r--input_1.txt0
-rw-r--r--jewl.cpp26
-rw-r--r--jewl.h35
-rw-r--r--main.cpp38
-rw-r--r--makefile23
-rw-r--r--npc.h83
-rw-r--r--npc.hpp21
-rw-r--r--output_1.txt457
-rw-r--r--output_student_1.txt313
-rw-r--r--robber.h70
-rw-r--r--robber.hpp91
22 files changed, 1890 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9c26e93
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+*
+!.gitignore
+!*.cpp
+!*.md
+!*.h
+!*.hpp
+!*.txt
+!makefile
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..832f35d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+# CS1570-SP2023 Final Programming Project
+While this project was a final for a pretty low level class, I store it on my server as I believe it demonstrates my ability to create a somewhat complex polymorphic hierarchy. The way this project was created ensured later development was possible, which was not part of the requirements. After being manually reviewed, the project scored (if I remember correctly) 100%.
diff --git a/city.cpp b/city.cpp
new file mode 100644
index 0000000..aa009f9
--- /dev/null
+++ b/city.cpp
@@ -0,0 +1,227 @@
+#include <iostream>
+#include <cstdlib>
+#include <typeinfo>
+
+// Programmer: Brett Weiland
+// Date: 4/30/23
+// File: city.cpp
+// Assignment: SP-B-finalProject
+// Purpose: functions for class city. see header for more details
+
+#include "city.h"
+
+unsigned int city::rounds_taken = 0;
+
+city::city(const unsigned int robber_win_value, const unsigned int rounds)
+ : ROBBER_WIN_VALUE(robber_win_value), MAX_ROUNDS(rounds) {
+ for(size_t cop_i = 0; cop_i < COPS_COUNT; cop_i++) {
+ cops[cop_i].includeInMap(this, randomLocation());
+ addMapMarker(cops[cop_i]);
+ }
+
+ for(size_t robber_i = 0; robber_i < ROBBERS_COUNT; robber_i++) {
+ robbers[robber_i].includeInMap(this, randomLocation());
+ addMapMarker(robbers[robber_i]);
+ robbers[robber_i].setGreedy(robber_i < ROBBERS_GREEDY);
+ }
+
+ for(size_t jewl_i = 0; jewl_i < JEWL_COUNT; jewl_i++) {
+ jewls[jewl_i].includeInMap(this, randomLocation());
+ addMapMarker(jewls[jewl_i]);
+ jewls_available[jewl_i] = &jewls[jewl_i];
+ }
+
+ renderMap();
+ printMap();
+}
+
+void city::printMap() const {
+ if(rounds_taken) {
+ //prints round in middle at top of map
+ const std::string round_header = "ROUND " + std::to_string(rounds_taken);
+ const size_t header_size = round_header.length();
+ if(header_size > (MAP_WIDTH * 2)) { std::cout << round_header << std::endl; }
+ else {
+ for(size_t spacing = 0; spacing < (MAP_WIDTH - ((header_size + 1) / 2.0)); spacing++)
+ std::cout << " ";
+ std::cout << round_header << std::endl;
+ }
+ }
+ else {
+ //initial print before rounds are startred
+ std::cout << "Initial positions" << std::endl;
+ }
+
+ for(size_t y = 0; y < MAP_HEIGHT; y++) {
+ for(size_t x = 0; x < MAP_HEIGHT; x++) {
+ std::cout << rendered_map[y][x] << " " << std::flush;
+ }
+ std::cout << "\r\n";
+ }
+ std::cout << std::endl;
+}
+
+coordinate city::randomLocation() const {
+ coordinate rand_cord;
+ do {
+ rand_cord.set_xy(rand() % MAP_WIDTH, rand() % MAP_HEIGHT);
+ } while (map_ptr[rand_cord.get_y()][rand_cord.get_x()] != NULL);
+ return rand_cord;
+}
+
+//see coordinate.h for a descriptions of how directions work.
+direction::TYPE city::randomDirection(const coordinate &scanner) const {
+ direction::TYPE rand_dir;
+
+ direction::TYPE border_map = (
+ ((scanner.get_y() <= 0) << direction::N) |
+ ((scanner.get_x() >= (MAP_WIDTH - 1)) << direction::E) |
+ ((scanner.get_y() >= (MAP_HEIGHT - 1)) << direction::S) |
+ ((scanner.get_x() <= 0) << direction::W));
+
+ do {
+ rand_dir = ((1 | ((rand() % 2) << 1)) << (rand() % 4));
+ rand_dir |= ((rand_dir & (1 << 4)) >> 4);
+ rand_dir &= (~(border_map) & direction::MASK) ;
+ } while(!rand_dir);
+
+ return rand_dir;
+}
+
+direction::TYPE city::directionToAnyJewl(const coordinate &scanner) const {
+ direction::TYPE d = scanner.getDirection(jewls_available[rand() % jewls_available_qty]->getLocation());
+ if(d) return d;
+ return randomDirection(scanner);
+}
+
+gameObject *city::findObjsByLocation(const coordinate loc) {
+ return map_ptr[loc.get_y()][loc.get_x()];
+}
+
+direction::TYPE city::nearestCopDirection(const coordinate &scanner) const {
+ int min_steps = INT_MAX;
+ int min_cop_id = INT_MAX;
+ int distance;
+ const cop<jewl> *closest_cop;
+ for(size_t cop_i = 0; cop_i < COPS_COUNT; cop_i++) {
+ distance = scanner.getSteps(cops[cop_i].getLocation());
+ if((distance < min_steps) ||
+ ((distance == min_steps) && (cops[cop_i].get_id() < min_cop_id))) {
+ min_steps = distance;
+ min_cop_id = cops[cop_i].get_id();
+ closest_cop = &cops[cop_i];
+ }
+ }
+ return scanner.getDirection(closest_cop->getLocation());
+}
+
+void city::renderMap() {
+ const char MAP_EMPTY = '*';
+ for(size_t y = 0; y < MAP_HEIGHT; y++) {
+ for(size_t x = 0; x < MAP_HEIGHT; x++) {
+ if(map_ptr[y][x] == NULL) {
+ rendered_map[y][x] = MAP_EMPTY;
+ continue;
+ }
+ rendered_map[y][x] = map_ptr[y][x]->getIcon();
+ }
+ }
+}
+
+void city::addMapMarker(gameObject &item) {
+ gameObject **map_location = &map_ptr[item.getLocation().get_y()][item.getLocation().get_x()];
+ gameObject *lower_item = *map_location;
+ gameObject *upper_item = NULL;
+
+ while((lower_item != NULL) && (item.get_drawPriority() > lower_item->get_drawPriority())) {
+ lower_item = lower_item->get_bottom();
+ if(upper_item == NULL) { upper_item = *map_location; }
+ else { upper_item = upper_item->get_bottom(); }
+ }
+ if(upper_item != NULL) { upper_item->set_bottom(&item); }
+ else { *map_location = &item; }
+ if(lower_item != NULL) { lower_item->set_top(&item); }
+ item.set_top(upper_item);
+ item.set_bottom(lower_item);
+
+}
+
+void city::delMapMarker(gameObject &item) {
+ gameObject **map_location = &map_ptr[item.getLocation().get_y()][item.getLocation().get_x()];
+ if(item.get_top() != NULL) item.get_top()->set_bottom(item.get_bottom());
+ if(item.get_bottom() != NULL) item.get_bottom()->set_top(item.get_top());
+ if(&item == *map_location) *map_location = item.get_bottom();
+}
+
+void city::moveNPC(npc<jewl> &character) {
+ if((!character.is_attached()) || (!character.is_active())) return;
+ delMapMarker(character);
+ character.move();
+ addMapMarker(character);
+}
+
+city::CITY_STATUS city::runTurn() {
+ rounds_taken += 1;
+ for(size_t robber_i = 0; robber_i < ROBBERS_COUNT; robber_i++) {
+ moveNPC(robbers[robber_i]);
+ if(robbers[0].get_totalRobberValue() >= ROBBER_WIN_VALUE) return CITY_STATUS::ROBBERS_MAX_VAL;
+ if(allRobbersArrested()) return CITY_STATUS::COPS_WIN;
+ }
+
+ for(size_t cop_i = 0; cop_i < COPS_COUNT; cop_i++) {
+ moveNPC(cops[cop_i]);
+ if(allRobbersArrested()) return CITY_STATUS::COPS_WIN;
+ }
+ renderMap();
+ if(rounds_taken >= MAX_ROUNDS) return CITY_STATUS::ROUNDS_DEPLETED;
+ return CITY_STATUS::CONTINUE;
+}
+
+void city::summarize() const {
+ for(size_t cop_i = 0; cop_i < COPS_COUNT; cop_i++) {
+ std::cout << "Police ID: " << cops[cop_i].get_id()
+ << "\n\tConfiscated jewls amount: $" << cops[cop_i].get_inventoryValue()
+ << "\n\tFinal number of robbers caught: " << cops[cop_i].get_robbersCaught() << "\n\n";
+
+ }
+
+ for(size_t robber_i = 0; robber_i < ROBBERS_COUNT; robber_i++) {
+ std::cout << (robbers[robber_i].isGreedy() ? "Greedy" : "Ordinary")
+ << " Robber ID: " << robbers[robber_i].get_id()
+ << "\n\tJewls picked up: " << robbers[robber_i].get_inventoryQty()
+ << "\n\tTotal jewl worth: " << robbers[robber_i].get_inventoryValue() << "\n\n";
+ }
+ std::cout << std::endl;
+}
+
+//I would have liked to set up a linked list for this as well, however I was running out of time.
+//Probably would have been nice to set up a generic linked list header type.
+void city::markJewlTaken(jewl &item) {
+ size_t jewl_i;
+ for(jewl_i = 0; jewls_available[jewl_i] != &item; jewl_i++); //find jewl in array
+
+ //shift all jewls over by 1 at/after position of removed jewls
+ for(; jewl_i < jewls_available_qty - 1; jewl_i++)
+ jewls_available[jewl_i] = jewls_available[jewl_i + 1];
+
+ jewls_available_qty--;
+}
+
+void city::markJewlAvailable(jewl &item) {
+ jewls_available[jewls_available_qty++] = &item;
+}
+
+void city::freeAllRobbers() {
+ for(size_t robber_i = 0; robber_i < ROBBERS_COUNT; robber_i++)
+ robbers[robber_i].free();
+ for(size_t cop_i = 0; cop_i < COPS_COUNT; cop_i++)
+ cops[cop_i].robbersReleased();
+
+}
+
+bool city::allRobbersArrested() const {
+ for(size_t robber_i = 0; robber_i < ROBBERS_COUNT; robber_i++)
+ if(robbers[robber_i].is_active()) return false;
+
+ return true;
+}
diff --git a/city.h b/city.h
new file mode 100644
index 0000000..de8e17f
--- /dev/null
+++ b/city.h
@@ -0,0 +1,164 @@
+#ifndef CITY_H
+#define CITY_H
+// Programmer: Brett Weiland
+// Date: 4/30/23
+// File: city.h
+// Assignment: SP-B-finalProject
+// Purpose: Contains the city object,
+// which acts as a game engine for gameObject based objects to interact with eachother.
+// Also containts game over conditions.
+
+
+#include <iostream>
+#include <cstddef>
+#include <climits>
+
+#include "gameObject.h"
+#include "coordinate.h"
+#include "npc.h"
+#include "cop.h"
+#include "robber.h"
+#include "jewl.h"
+
+
+class city {
+ private:
+ //inventory for NPCs are relient on this being 47 unless modified.
+ //Please see npc.h for explaination.
+ static const unsigned int JEWL_COUNT = 47;
+ static const unsigned int ROBBERS_COUNT = 4;
+ static const unsigned int COPS_COUNT = 1;
+ const unsigned int ROBBERS_GREEDY = 2; //must be lower then JEWL_COUNT
+
+ //map dimentions
+ static const int MAP_WIDTH = 10;
+ static const int MAP_HEIGHT = 10;
+
+ //used for keeping track of which jewls are free outside of map_ptr;
+ //useful for finding random free jewls
+ unsigned int jewls_available_qty = JEWL_COUNT;
+ jewl *jewls_available[JEWL_COUNT];
+
+ //this array of gameObject pointers is useful for looking up objects on location,
+ //as well as keep track of where objects are in a sane way.
+ //If objects are stacked, they are linked in a doubly linked list for that cell.
+ //If there are no objects, the cell is a null pointer.
+ gameObject *map_ptr[MAP_HEIGHT][MAP_WIDTH] = {NULL};
+
+ char rendered_map[MAP_HEIGHT][MAP_WIDTH]; //map as seen by humans. use for display only
+
+ static unsigned int rounds_taken;
+
+ //win conditions for robbers.
+ //robbers win if they collectively get more then ROBBER_WIN_VALUE or uncaught in MAX_ROUNDS
+ const unsigned int ROBBER_WIN_VALUE; //if robber gets more money then this, they win
+ const unsigned int MAX_ROUNDS; //if robbers aren't caught b
+
+
+ //gameObjects
+ cop<jewl> cops[COPS_COUNT];
+ robber<jewl> robbers[ROBBERS_COUNT];
+ jewl jewls[JEWL_COUNT];
+
+
+ //Desc: gets a random UNOCUPIED location in the map.
+ //Pre: map_ptr is updated with objects to avoid stacking.
+ //Post: random unocupied coordinate within bounds returned
+ coordinate randomLocation() const;
+
+ //Desc: uses map_ptr to generate a 2d array of characters, rendered_map.
+ // when gameObjects are stacked, the first one on the linked list is printed.
+ // checks the gameObject's get_icon() function.
+ //Pre: map_ptr updated
+ //Post: rendered_map updated
+ void renderMap();
+
+ //Desc: tests if npc derived class is movable, and calls its move() function.
+ // updates map_ptr accordingly.
+ //Pre: valid npc passed
+ //Post: character is moved, map_ptr updated
+ void moveNPC(npc<jewl> &character);
+
+ //Desc: tests to see if all robbers arrested for game over condition.
+ //Pre: none
+ //Post: returns true if all robbers arrested
+ bool allRobbersArrested() const;
+
+
+ public:
+ //used to communicate if/why the game has stopped running.
+ enum class CITY_STATUS { CONTINUE, COPS_WIN, ROBBERS_MAX_VAL, ROUNDS_DEPLETED };
+
+ //Desc: city constructor
+ //Pre: win conditions passed (see docs in private section of this object)
+ //Post: city is constructed along with all of its gameObjects
+ city(const unsigned int robber_win_value, const unsigned int rounds);
+
+
+ //Desc: operate city for a single turn.
+ //Pre: none
+ //Post: CITY_STATUS describing win condition or nothing returned
+ CITY_STATUS runTurn();
+
+ //Desc: Adds gameObject to map_ptr location.
+ // order in doubly linked list based on gameObject.get_drawPriority().
+ //Pre: gameObject with updated coordinates passed
+ //Post: gameObject added to map_ptr
+ void addMapMarker(gameObject &item);
+
+ //Desc: removes gameObject from map_ptr location.
+ //Pre: coordinates of gameObjects reflect where it is on the map_ptr
+ //Post: gameObject removed from that location on map_ptr
+ void delMapMarker(gameObject &item);
+
+ //Desc: prints rendered_map.
+ //Pre: rendered_map is updated using renderMap()
+ //Post: map is printed
+ void printMap() const;
+
+ //Desc: finds top gameObject in location.
+ // Other gameObjects at that location can be found using the top's linked list.
+ //Pre: coordinate for location to check is passed
+ //Post: pointer to top gameoOject returned or NULL if nothing resides that space
+ gameObject *findObjsByLocation(const coordinate loc);
+
+ //Desc: gets a random directoin while avoiding borders.
+ //Pre: coordinates to get direction from passed
+ //Post: random direction is returned
+ direction::TYPE randomDirection(const coordinate &scanner) const;
+
+ //Desc: gets direction to nearest cop.
+ //Pre: one cop must exist.
+ //Post: direction to nearest cop returned.
+ direction::TYPE nearestCopDirection(const coordinate &scanner) const;
+
+ //Desc: gets the direction to any jewl in jewls_available.
+ //Pre: one unpicked jewl must exist.
+ //Post: direction to any random unpicked jewl returned.
+ // returns random direction if no jewl found.
+ direction::TYPE directionToAnyJewl(const coordinate &scanner) const;
+
+ //Desc: unarrests every robber.
+ //Pre: none
+ //Post: all robbers freed
+ void freeAllRobbers();
+
+ //Desc: adds jewl to list of available/unpicked jewls.
+ //Pre: jewl passed. this function not responsible for adding jewl to map
+ //Post: jewl is added to list
+ void markJewlAvailable(jewl &item);
+
+ //Desc: removes jewl from list of unpicked jewls.
+ //Pre: jewl passed. this function not responsible for removing jewl from map
+ //Post: jewl is removed from list
+ void markJewlTaken(jewl &item);
+
+ //Desc: prints summary of NPCs.
+ //Pre: none
+ //Post: prints NPC info
+ void summarize() const;
+
+};
+
+
+#endif
diff --git a/coordinate.cpp b/coordinate.cpp
new file mode 100644
index 0000000..54a225c
--- /dev/null
+++ b/coordinate.cpp
@@ -0,0 +1,45 @@
+// Programmer: Brett Weiland
+// Date: 4/30/23
+// File: coordinate.cpp
+// Assignment: SP-B-finalProject
+// Purpose: function for computing info and interacting with coordinates and directions.
+
+#include <cmath>
+#include "coordinate.h"
+
+int coordinate::get_x() const { return x; }
+int coordinate::get_y() const { return y; }
+void coordinate::set_x(const int pos_x) { x = pos_x; }
+void coordinate::set_y(const int pos_y) { y = pos_y; }
+coordinate::coordinate() : x(0), y(0) {} ;
+coordinate::coordinate(int pos_x, int pos_y) : x(pos_x), y(pos_y) {};
+
+void coordinate::set_xy(const int pos_x, const int pos_y) {
+ x = pos_x;
+ y = pos_y;
+}
+
+
+int coordinate::getSteps(const coordinate &objective) const {
+ int steps1, steps2;
+ steps1 = abs(this->get_x() - objective.get_x());
+ steps2 = abs(this->get_y() - objective.get_y());
+ return (steps1 > steps2) ? steps1 : steps2; //no max function allowed
+}
+
+
+direction::TYPE coordinate::getDirection(const coordinate &objective) const {
+ return (
+ (this->get_y() > objective.get_y()) |
+ ((this->get_x() < objective.get_x()) << 1) |
+ ((this->get_y() < objective.get_y()) << 2) |
+ ((this->get_x() > objective.get_x()) << 3));
+}
+
+void coordinate::stepDirection(const direction::TYPE path) {
+ y -= ((path & (1 << direction::N)) >> direction::N);
+ y += ((path & (1 << direction::S)) >> direction::S);
+ x += ((path & (1 << direction::E)) >> direction::E);
+ x -= ((path & (1 << direction::W)) >> direction::W);
+}
+
diff --git a/coordinate.h b/coordinate.h
new file mode 100644
index 0000000..451df12
--- /dev/null
+++ b/coordinate.h
@@ -0,0 +1,70 @@
+#ifndef COORDINATE_H
+#define COORDINATE_H
+
+// Programmer: Brett Weiland
+// Date: 4/30/23
+// File: coordinate.h
+// Assignment: SP-B-finalProject
+// Purpose: conatins class for coordinates,
+// as well as namespace for direction parsing and computations.
+
+#include <cstdint>
+
+//Directions are represented by a 4 bit bitmap,
+//where north is the least significant bit.
+//direction typed vars should never have more then 2 bits set,
+//bits must be next to eachother or wrapped around.
+namespace direction {
+ //type is used to gaurentee we have an unsigned integer of at least 8 bits
+ typedef uint8_t TYPE;
+ const direction::TYPE NONE = 0;
+ const direction::TYPE N = 0;
+ const direction::TYPE E = 1;
+ const direction::TYPE S = 2;
+ const direction::TYPE W = 3;
+
+ //used to ensure a direction doesn't contain bits past its MSB
+ const direction::TYPE MASK = ((1 << N) | (1 << E) | (1 << S) | (1 << W));
+}
+
+class coordinate {
+ private:
+ int x, y;
+ public:
+ //Desc: initilizer for coordinate, sets X/Y to 0
+ //Pre: none
+ //Post: coordinate initilized
+ coordinate();
+
+ //Desc: initilizer for coordinate with X/Y to passed value
+ //Pre: X/Y passed
+ //Post: coordinate initilized
+ coordinate(int pos_x, int pos_y);
+
+ //Desc: finds the amount of steps it takes from one point to the other,
+ // takes limited movement into account
+ //Pre: objective is passed
+ //Post: returns number of steps it'd take an npc to get to objective
+ int getSteps(const coordinate &objective) const;
+
+ //Desc: finds the direction an object at this coordinate would need to take
+ // to arrive at objective
+ //Pre: objective with coordinates within city bounds passed
+ //Post: direction returned
+ direction::TYPE getDirection(const coordinate &objective) const;
+
+ //Desc: modifies this coordinate to step one direction in a certain path
+ //Pre: direction given, does not check for possible obstructions
+ //Post: this modified to take step in path
+ void stepDirection(const direction::TYPE path);
+
+ //geters and seters
+ int get_x() const;
+ int get_y() const;
+ void set_x(const int pos_x);
+ void set_y(const int pos_y);
+ void set_xy(const int pos_x, const int pos_y);
+
+};
+
+#endif
diff --git a/cop.h b/cop.h
new file mode 100644
index 0000000..2b46fb9
--- /dev/null
+++ b/cop.h
@@ -0,0 +1,48 @@
+#ifndef COP_H
+#define COP_H
+
+// Programmer: Brett Weiland
+// Date: 4/30/23
+// File: cop.h
+// Assignment: SP-B-finalProject
+// Purpose: defines cop npc which arrests robbers and takes money on contact.
+// cops will also release robbers if bribed (see robbers.h).
+
+template <class T>
+class robber;
+
+template <class T>
+class cop : public npc<T> {
+ private:
+ unsigned int robbers_caught = 0;
+ public:
+ //overrides; see relevant files for descriptions
+ void move() override; //npc.h
+ char getIcon() const override; //gameObject.h
+ unsigned int get_drawPriority() const override; //gameObject.h
+
+ //getters and setters
+ unsigned int get_robbersCaught() const;
+
+ //Desc: notifies all previously arrested robbers are now active, set robbers_caught to 0.
+ //Pre: none
+ //Post: none
+ void robbersReleased();
+
+ //Desc: arrests robber, calls robbers getArrested() function.
+ // takes all robbers inventory for self.
+ //Pre: active robber is passed
+ //Post: robber is arrested
+ void arrest(robber<T> &offender);
+
+ //Desc: robber calls this when they want to give us a bribe.
+ // Take an inventory item for ourselves, release all robbers.
+ //Pre: Item is passed as bribe
+ //Post: bribe is put into inventory, all robbers released. Robber not arrested as a result.
+ void takeBribe(T *bribe);
+
+};
+
+#include "cop.hpp"
+
+#endif
diff --git a/cop.hpp b/cop.hpp
new file mode 100644
index 0000000..f6f821d
--- /dev/null
+++ b/cop.hpp
@@ -0,0 +1,48 @@
+#include <typeinfo>
+#include "robber.h"
+
+// Programmer: Brett Weiland
+// Date: 4/30/23
+// File: cop.hpp
+// Assignment: SP-B-finalProject
+// Purpose: all the functions specific to how cops interact and move.
+
+template <class T> char cop<T>::getIcon() const { return 'p'; }
+template <class T> unsigned int cop<T>::get_drawPriority() const { return 1; }
+template <class T> unsigned int cop<T>::get_robbersCaught() const { return robbers_caught; }
+template <class T> void cop<T>::robbersReleased() { robbers_caught = 0; }
+
+template <class T> void cop<T>::move() {
+ this->location.stepDirection(this->parentCity->randomDirection(this->location));
+ for(gameObject *peer = this->parentCity->findObjsByLocation(this->location);
+ peer != NULL; peer = peer->get_top()) {
+
+ const std::type_info &peer_type = typeid(*peer);
+
+ if(peer_type == typeid(robber<T>)) {
+ robber<T> &rob = dynamic_cast<robber<T>&>(*peer);
+ if(rob.is_active()) arrest(rob);
+ }
+
+ if(peer_type == typeid(T)) {
+ this->inventory[this->inventory_qty] = dynamic_cast<T*>(peer);
+ this->inventory[this->inventory_qty++]->pickup();
+ }
+ }
+}
+
+template <class T> void cop<T>::arrest(robber<T> &offender) {
+ T **crinimal_stash = offender.getArrested();
+ size_t loot_i;
+ for(loot_i = 0; crinimal_stash[loot_i] != NULL; loot_i++) { //assumes robbers
+ this->inventory[this->inventory_qty + loot_i] = crinimal_stash[loot_i];
+ crinimal_stash[loot_i] = NULL;
+ }
+ this->inventory_qty += loot_i;
+ robbers_caught++;
+}
+
+template <class T> void cop<T>::takeBribe(T *bribe) {
+ this->inventory[this->inventory_qty++] = bribe;
+ this->parentCity->freeAllRobbers();
+}
diff --git a/gameObject.cpp b/gameObject.cpp
new file mode 100644
index 0000000..bfb7616
--- /dev/null
+++ b/gameObject.cpp
@@ -0,0 +1,29 @@
+#include "city.h"
+
+// Programmer: Brett Weiland
+// Date: 4/30/23
+// File: gameObject.h
+// Assignment: SP-B-finalProject
+// Purpose: member functions shared between all city participants.
+
+void gameObject::includeInMap(city *parent_city, coordinate starting_pos) {
+ parentCity = parent_city; //TODO change name
+ location = starting_pos;
+}
+
+gameObject *gameObject::get_top() const { return top_obj; }
+gameObject *gameObject::get_bottom() const { return bottom_obj; }
+void gameObject::set_top(gameObject *top) { top_obj = top; }
+void gameObject::set_bottom(gameObject *bottom) { bottom_obj = bottom; }
+bool gameObject::is_attached() const { return attached_to_map; }
+
+void gameObject::mapAttach() {
+ attached_to_map = true;
+ parentCity->addMapMarker(*this);
+}
+void gameObject::mapDetach() {
+ attached_to_map = false;
+ parentCity->delMapMarker(*this);
+}
+
+coordinate gameObject::getLocation() const { return location; }
diff --git a/gameObject.h b/gameObject.h
new file mode 100644
index 0000000..81a353b
--- /dev/null
+++ b/gameObject.h
@@ -0,0 +1,81 @@
+#ifndef GAMEOBJECT_H
+#define GAMEOBJECT_H
+
+// Programmer: Brett Weiland
+// Date: 4/30/23
+// File: gameObject.h
+// Assignment: SP-B-finalProject
+// Purpose: defines the object that all city participants are derived from.
+
+#include <cstddef>
+#include "coordinate.h"
+
+class city;
+
+
+//this is the class all objects are derived from when they want to participate in the city map.
+class gameObject {
+ public:
+ //Desc: gets the coordinate of this object.
+ //Pre: none
+ //Post: coordinate returned
+ coordinate getLocation() const;
+
+ //Desc: records the map we're a part of, as well as our initial position.
+ //Pre: a pointer to the city, as well as starting position passed.
+ //Post: object is set to active, initial position set, pointer to the map added
+ void includeInMap(city *parent_city, coordinate starting_pos);
+
+ //Desc: shall return the icon of the object as shown on the rendered map.
+ //Pre: none
+ //Post: returns single character for map tileset
+ virtual char getIcon() const = 0;
+
+ //Desc: gets priority of who should be drawn on rendered map if gameObjects are in same position.
+ // lower values mean they are more likely to be seen.
+ //Pre: none
+ //Post: must return a single character to resemble this object
+ virtual unsigned int get_drawPriority() const = 0;
+
+ //Desc: tells city if we are attached to the map, see descriptoin on attached_to_map
+ //Pre: none
+ //Post: item is no longer attached to map; see description
+ bool is_attached() const;
+
+ //getters and setters
+ gameObject *get_top() const;
+ gameObject *get_bottom() const;
+ void set_top(gameObject *top);
+ void set_bottom(gameObject *bottom);
+
+ protected:
+ city *parentCity; //city were a part of
+ coordinate location; //our location
+
+ //if this is false, the gameObject is assumed to be removed from the map,
+ //meaning the object can't be found by coordinates and is assumed invisible,
+ //and calls to move() will be skipped if derived class is NPC.
+ //used for jewl, figured I'd include it as part of the base class due to it's potential uses.
+ bool attached_to_map = true;
+
+ //these are used to keep track of who is over/under us on the same coordinates.
+ //I would have liked to make this part of the city class and never touch this,
+ //as that seems more polymorphic. However, I ran short on time.
+ //set to NULL if no object above/below.
+ gameObject *top_obj = NULL;
+ gameObject *bottom_obj = NULL;
+
+ //Desc: attaches or detaches us from city, notifies city of our existance.
+ // See is_attached for implications
+ //Pre: none
+ //Post: attached set to true, added to map
+ void mapAttach();
+
+ //Desc: detaches us from city, notifies city to remove us from map.
+ //Pre: none
+ //Post: removes from parent map, attached_to_map is false. We are still a part of the city
+ void mapDetach();
+};
+
+
+#endif
diff --git a/grade.md b/grade.md
new file mode 100644
index 0000000..0b68504
--- /dev/null
+++ b/grade.md
@@ -0,0 +1,10 @@
+## Score: 130
+
+## Notes:
+- Bonus. (+30)
+- Good job!
+
+## Contact:
+Name: Mateusz (Mat) Przezdziecki<br>
+Email: mppmdf@umsystem.edu<br>
+Discord: mateusz#0373 \ No newline at end of file
diff --git a/input_1.txt b/input_1.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/input_1.txt
diff --git a/jewl.cpp b/jewl.cpp
new file mode 100644
index 0000000..1be4d22
--- /dev/null
+++ b/jewl.cpp
@@ -0,0 +1,26 @@
+#include "jewl.h"
+#include "coordinate.h"
+#include "city.h"
+
+// Programmer: Brett Weiland
+// Date: 4/30/23
+// File: jewl.hpp
+// Assignment: SP-B-finalProject
+// Purpose: contains member functions for jewl; see jewl.h
+
+char jewl::getIcon() const { return 'j'; }
+
+unsigned int jewl::get_drawPriority() const { return 2; }
+
+unsigned int jewl::value() const { return location.get_x() + location.get_y(); }
+
+void jewl::drop() {
+ mapAttach();
+ parentCity->markJewlAvailable(*this);
+}
+
+unsigned int jewl::pickup() {
+ mapDetach();
+ parentCity->markJewlTaken(*this);
+ return value();
+}
diff --git a/jewl.h b/jewl.h
new file mode 100644
index 0000000..712c88e
--- /dev/null
+++ b/jewl.h
@@ -0,0 +1,35 @@
+#ifndef JEWL_H
+#define JEWL_H
+
+// Programmer: Brett Weiland
+// Date: 4/30/23
+// File: jewl.h
+// Assignment: SP-B-finalProject
+// Purpose: jewl gameObject. This class is what cops and robbers have in their inventory
+// (although this doesn't have to be the case, as they're both templeted).
+// if there were more types of inventory objects, i'd make this an abstract class.
+
+#include "gameObject.h"
+
+class jewl : public gameObject {
+ public:
+ //Desc: returns value of this
+ //Pre: valid gameObject location set
+ //Post: returns sum of coordinates
+ unsigned int value() const;
+
+ //Desc: attaches jewl to map, notifies city we are available
+ //Pre: valid coordinates are set
+ //Post: jewl attached to map, can be picked up by npc<jewl>
+ void drop();
+
+ //Desc: detaches jewl from map, notifies city we are no longer available
+ //Pre: none
+ //Post: jewl detached from map, can't be picked up until dropped
+ unsigned int pickup();
+
+ //overriden members, see respective base classes
+ char getIcon() const override; //gameObject.h
+ unsigned int get_drawPriority() const override; //gameObject.h
+};
+#endif
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..c40b007
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,38 @@
+#include <iostream>
+#include <string>
+#include <stdlib.h>
+#include "city.h"
+
+int main() {
+ const unsigned int ROBBER_WIN_VAL = 438;
+ const unsigned int MAX_TURNS = 30;
+ const unsigned int RAND_SEED = 85;
+ city::CITY_STATUS status = city::CITY_STATUS::CONTINUE;
+ city engine(ROBBER_WIN_VAL, MAX_TURNS);
+
+ srand(RAND_SEED);
+
+ while(status == city::CITY_STATUS::CONTINUE) {
+ status = engine.runTurn();
+ engine.printMap();
+ }
+ switch(status) {
+ case city::CITY_STATUS::COPS_WIN:
+ std::cout << "Cops win the case due to all robbers being arrested." << std::endl;
+ break;
+ case city::CITY_STATUS::ROBBERS_MAX_VAL:
+ std::cout << "Robbers win due to collectively obtaining more then $" << ROBBER_WIN_VAL << std::endl;
+ break;
+ case city::CITY_STATUS::ROUNDS_DEPLETED:
+ std::cout << "Robbers win because the maximum number of turns (" << MAX_TURNS << ") have been reached." << std::endl;
+ break;
+ case city::CITY_STATUS::CONTINUE: //prevent compiler warning
+ break;
+ }
+
+ std::cout << "Summary of chase: \n" << std::endl;
+ engine.summarize();
+
+ return 0;
+}
+
diff --git a/makefile b/makefile
new file mode 100644
index 0000000..667f693
--- /dev/null
+++ b/makefile
@@ -0,0 +1,23 @@
+CC := g++
+BUILD_DIR := build
+CCOPTS := -Wall -Wextra -ggdb -pedantic-errors
+SRC_DIR := ./
+OUTPUT := $(shell basename $(CURDIR)).elf
+
+SRCFILES := $(wildcard ./$(SRC_DIR)/*.cpp)
+OBJFILES := $(patsubst ./$(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(SRCFILES))
+
+make: BUILD_DIR $(OBJFILES)
+ $(CC) $(CCOPTS) -o $(OUTPUT) $(OBJFILES)
+
+debug:
+ gdb -x debug.gdb $(OUTPUT)
+
+$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
+ $(CC) $(CCOPTS) -c $< -o $@
+
+BUILD_DIR:
+ mkdir -p $(BUILD_DIR)
+
+clean:
+ rm -rf build/ $(OUTPUT)
diff --git a/npc.h b/npc.h
new file mode 100644
index 0000000..c45d971
--- /dev/null
+++ b/npc.h
@@ -0,0 +1,83 @@
+#ifndef NPC_H
+#define NPC_H
+
+// Programmer: Brett Weiland
+// Date: 4/30/23
+// File: npc.h
+// Assignment: SP-B-finalProject
+// Purpose: contains the abstract base class for npcs.
+// npcs are gameObjects that move, and consist of the cop and robber.
+
+#include <typeindex>
+#include <typeinfo>
+
+#include "gameObject.h"
+#include "coordinate.h"
+
+template <class T>
+class npc : public gameObject {
+ public:
+ //Desc: npc initilizer
+ //Pre: none
+ //Post: npc initilized, ID is set and static ID counter incrimented
+ npc();
+
+ //Desc: the move function for the NPC. Called once for every NPC each round
+ //Pre: none
+ //Post: NPC's actions for that round will be taken, unless another npc interacts with it
+ virtual void move() = 0;
+
+ //Desc: called when NPC is arrested. returns inventory pointer to caller,
+ // cop uses this to record items in their own stash.
+ //Pre: none
+ //Post: npc is no longer active (can't move), more behavior is defined by cop arrest() function
+ T **getArrested();
+
+ //Desc: gets value of all items in inventory
+ //Pre: inventory must have pointers to items with value() function or NULL where there are none
+ //Post: total value of al objects in inventory returned
+ unsigned int get_inventoryValue() const;
+
+ //getters and setters
+ int get_id() const;
+ bool is_active() const; //false if arrested
+ void free(); //sets active to true
+ unsigned int get_inventoryQty() const;
+ protected:
+ /**
+ IMPORTAINT
+ with the schools -pedantic-errors option, there seemed to be no way to declare
+ a static array of any size other then a static constant type, which requires initilizatoin
+ in the class at compile time.
+
+ I could use preprocessor directives,
+ but I figured I should stay away from for my grade them due to never seeing them in class.
+ I could have also used a dynamic array, but we have not been taught new/delete yet.
+
+ Dynmaic arrays are great, I would have allowed them, they aren't too difficult.
+ You would just need to learn destructors.
+ **/
+ static const std::size_t INVENTORY_SIZE = 47; // MUST BE SET TO CITY JEWL COUNT <---
+
+ //inventory size shold be set to jewl count to ensure any gameObject has enough inventory space.
+ T *inventory[INVENTORY_SIZE] = {NULL};
+
+ //number of items in inventory
+ unsigned int inventory_qty = 0;
+ int id;
+
+ //false if we should be on the map, but shouldn't be allowed to move.
+ //Used when robber is arrested
+ bool active = true;
+
+ private:
+ static int id_counter; //ensures the next constructed ID is one higher then ours
+};
+
+template <class T> int npc<T>::id_counter = 1;
+
+
+#include "npc.hpp"
+
+
+#endif
diff --git a/npc.hpp b/npc.hpp
new file mode 100644
index 0000000..0f0cba4
--- /dev/null
+++ b/npc.hpp
@@ -0,0 +1,21 @@
+// Programmer: Brett Weiland
+// Date: 4/30/23
+// File: npc.hpp
+// Assignment: SP-B-finalProject
+// Purpose: contains the functions shared between all npc derived objects
+
+template <class T> npc<T>::npc() { id = id_counter++; }
+template <class T> bool npc<T>::is_active() const { return active; }
+template <class T> int npc<T>::get_id() const { return id; }
+
+template <class T> unsigned int npc<T>::get_inventoryQty() const { return inventory_qty; }
+
+template <class T> unsigned int npc<T>::get_inventoryValue() const {
+ unsigned int value = 0;
+ for(size_t inventory_i = 0;
+ (inventory_i < inventory_qty) && (inventory[inventory_i] != NULL); inventory_i++) {
+ value += inventory[inventory_i]->value();
+ }
+ return value;
+}
+
diff --git a/output_1.txt b/output_1.txt
new file mode 100644
index 0000000..33ff210
--- /dev/null
+++ b/output_1.txt
@@ -0,0 +1,457 @@
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - J - J J J J J |
+| - J - J - - J J J J |
+| J - - - - - J - J J |
+| - J - J J - - J J J |
+| r - J J J J J r - - |
+| r - p - J - J J - - |
+| - J - r J J - - - J |
+| - J J - - - - J - J |
+-----------------------
+
+Turn 1:
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - J - J J J J J |
+| - J - J - - J J J J |
+| J - - - - - J - J J |
+| - J - J J - - J J J |
+| - - J J J J J - - - |
+| - R - r J - r J - - |
+| - p - - J J - - - J |
+| - J J - - - - J - J |
+-----------------------
+
+Turn 2:
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - J - J J J J J |
+| - J - J - - J J J J |
+| J - - - - - J - J J |
+| - J - J J - - J J J |
+| r - - J J J J r - - |
+| - - r - J - - J - - |
+| r - - - J J - - - J |
+| p J J - - - - J - J |
+-----------------------
+
+Turn 3:
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - J - J J J J J |
+| - J - J - - J J J J |
+| J - - - - - J - J J |
+| - J - J J - - J J J |
+| - r - J J J J - - - |
+| r - - - J - - J r - |
+| p r - - J J - - - J |
+| - J J - - - - J - J |
+-----------------------
+
+Turn 4:
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - J - J J J J J |
+| - J - J - - J J J J |
+| J - - - - - J - J J |
+| - J - J J - - J J J |
+| - - - J J J J - - - |
+| r r - - J - - J - - |
+| - r - - J J - - - r |
+| p J J - - - - J - J |
+-----------------------
+
+Turn 5:
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - J - J J J J J |
+| - J - J - - J J J J |
+| J - - - - - J - J J |
+| - J - J J - - J J J |
+| - r - J J J J - - - |
+| - - r - J - - J - - |
+| p - - - J J - - - - |
+| - J J - - - - J - J |
+-----------------------
+
+Turn 6:
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - J - J J J J J |
+| - J - J - - J J J J |
+| J - - - - - J - J J |
+| - J - J J - - J J J |
+| r - - J J J J - - - |
+| - - - - J - - J - - |
+| - p - r J J - - - - |
+| - J J - - - - J - J |
+-----------------------
+
+Turn 7:
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - J - J J J J J |
+| - J - J - - J J J J |
+| J r - - - - J - J J |
+| - - - J J - - J J J |
+| - - - J J J J - - - |
+| - - - - J - - J - - |
+| p - - - J J - - - - |
+| - J r - - - - J - J |
+-----------------------
+
+Turn 8:
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - J - J J J J J |
+| - J - J - - J J J J |
+| J - - - - - J - J J |
+| - r - J J - - J J J |
+| - - - J J J J - - - |
+| - p - - J - - J - - |
+| - - - - J J - - - - |
+| - r - - - - - J - J |
+-----------------------
+
+Turn 9:
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - J - J J J J J |
+| - J - J - - J J J J |
+| J r - - - - J - J J |
+| - - - J J - - J J J |
+| - - - J J J J - - - |
+| p - - - J - - J - - |
+| r - - - J J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 10:
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - J - J J J J J |
+| - J - J - - J J J J |
+| J - - - - - J - J J |
+| - - r J J - - J J J |
+| - - - J J J J - - - |
+| - - - - J - - J - - |
+| p - - - J J - - - - |
+| r - - - - - - J - J |
+-----------------------
+
+Turn 11:
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - J - J J J J J |
+| - J - J - - J J J J |
+| J - - r - - J - J J |
+| - - - J J - - J J J |
+| - - - J J J J - - - |
+| - p - - J - - J - - |
+| - - - - J J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 12:
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - J - J J J J J |
+| - J - J r - J J J J |
+| J - - - - - J - J J |
+| - - - J J - - J J J |
+| - p - J J J J - - - |
+| - - - - J - - J - - |
+| - - - - J J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 13:
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - J - J J J J J |
+| - J - J - - J J J J |
+| J - - r - - J - J J |
+| - - p J J - - J J J |
+| - - - J J J J - - - |
+| - - - - J - - J - - |
+| - - - - J J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 14:
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - J - J J J J J |
+| - J - J - - J J J J |
+| J - p - r - J - J J |
+| - - - J J - - J J J |
+| - - - J J J J - - - |
+| - - - - J - - J - - |
+| - - - - J J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 15:
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - J - J J J J J |
+| - J - J - - J J J J |
+| J - - p - - J - J J |
+| - - - J J r - J J J |
+| - - - J J J J - - - |
+| - - - - J - - J - - |
+| - - - - J J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 16:
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - J - J J J J J |
+| - J - p - - J J J J |
+| J - - - - - J - J J |
+| - - - J J - - J J J |
+| - - - J J r J - - - |
+| - - - - J - - J - - |
+| - - - - J J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 17:
+-----------------------
+| - - J - J J - - - J |
+| J - J J J - J - - - |
+| - - - p - J J J J J |
+| - J - - - - J J J J |
+| J - - - - - J - J J |
+| - - - J J - - J J J |
+| - - - J J - J - - - |
+| - - - - r - - J - - |
+| - - - - J J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 18:
+-----------------------
+| - - J - J J - - - J |
+| J - J p J - J - - - |
+| - - - - - J J J J J |
+| - J - - - - J J J J |
+| J - - - - - J - J J |
+| - - - J J - - J J J |
+| - - - J J - J - - - |
+| - - - - - - - J - - |
+| - - - r - J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 19:
+-----------------------
+| - - J - J J - - - J |
+| J - J - J - J - - - |
+| - - - - p J J J J J |
+| - J - - - - J J J J |
+| J - - - - - J - J J |
+| - - - J J - - J J J |
+| - - - J J - J - - - |
+| - - - - - - - J - - |
+| - - - - - J - - - - |
+| - - r - - - - J - J |
+-----------------------
+
+Turn 20:
+-----------------------
+| - - J - J J - - - J |
+| J - J - J - J - - - |
+| - - - - - J J J J J |
+| - J - p - - J J J J |
+| J - - - - - J - J J |
+| - - - J J - - J J J |
+| - - - J J - J - - - |
+| - - - - - - - J - - |
+| - - r - - J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 21:
+-----------------------
+| - - J - J J - - - J |
+| J - J - J - J - - - |
+| - - - - p J J J J J |
+| - J - - - - J J J J |
+| J - - - - - J - J J |
+| - - - J J - - J J J |
+| - - - J J - J - - - |
+| - - - - - - - J - - |
+| - - - - - J - - - - |
+| - r - - - - - J - J |
+-----------------------
+
+Turn 22:
+-----------------------
+| - - J - J J - - - J |
+| J - J - J - J - - - |
+| - - - p - J J J J J |
+| - J - - - - J J J J |
+| J - - - - - J - J J |
+| - - - J J - - J J J |
+| - - - J J - J - - - |
+| - - - - - - - J - - |
+| - r - - - J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 23:
+-----------------------
+| - - J - J J - - - J |
+| J - J - J - J - - - |
+| - - - - - J J J J J |
+| - J - - p - J J J J |
+| J - - - - - J - J J |
+| - - - J J - - J J J |
+| - - - J J - J - - - |
+| - r - - - - - J - - |
+| - - - - - J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 24:
+-----------------------
+| - - J - J J - - - J |
+| J - J - J - J - - - |
+| - - - - - p J J J J |
+| - J - - - - J J J J |
+| J - - - - - J - J J |
+| - - - J J - - J J J |
+| - - r J J - J - - - |
+| - - - - - - - J - - |
+| - - - - - J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 25:
+-----------------------
+| - - J - J J - - - J |
+| J - J - J - J - - - |
+| - - - - - - p J J J |
+| - J - - - - J J J J |
+| J - - - - - J - J J |
+| - - r J J - - J J J |
+| - - - J J - J - - - |
+| - - - - - - - J - - |
+| - - - - - J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 26:
+-----------------------
+| - - J - J J - - - J |
+| J - J - J - p - - - |
+| - - - - - - - J J J |
+| - J - - - - J J J J |
+| J - - - r - J - J J |
+| - - - - J - - J J J |
+| - - - J J - J - - - |
+| - - - - - - - J - - |
+| - - - - - J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 27:
+-----------------------
+| - - J - J J - - - J |
+| J - J - J - - - - - |
+| - - - - - - p J J J |
+| - J - - - - J J J J |
+| J - - - - - J - J J |
+| - - - - r - - J J J |
+| - - - J J - J - - - |
+| - - - - - - - J - - |
+| - - - - - J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 28:
+-----------------------
+| - - J - J J - - - J |
+| J - J - J - - - - - |
+| - - - - - - - J J J |
+| - J - - - p J J J J |
+| J - - - - - J - J J |
+| - - - r - - - J J J |
+| - - - J J - J - - - |
+| - - - - - - - J - - |
+| - - - - - J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 29:
+-----------------------
+| - - J - J J - - - J |
+| J - J - J - - - - - |
+| - - - - - p - J J J |
+| - J - - - - J J J J |
+| J - - - r - J - J J |
+| - - - - - - - J J J |
+| - - - J J - J - - - |
+| - - - - - - - J - - |
+| - - - - - J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Turn 30:
+-----------------------
+| - - J - J J - - - J |
+| J - J - p - - - - - |
+| - - - - - - - J J J |
+| - J - - - - J J J J |
+| J - - - - - J - J J |
+| - - - - - r - J J J |
+| - - - J J - J - - - |
+| - - - - - - - J - - |
+| - - - - - J - - - - |
+| - - - - - - - J - J |
+-----------------------
+
+Summary of the chase:
+ The robbers have won because the maximum amount
+ of turns (30) has been reached.
+
+ Police ID: 1
+ Confiscated Jewels Worth: $102
+ Final Number of Robbers Caught: 0
+
+ Ordinary Robber ID: 1
+ Number of Jewels Picked Up: 0
+ Total Jewel Worth: $0
+
+ Ordinary Robber ID: 2
+ Number of Jewels Picked Up: 0
+ Total Jewel Worth: $0
+
+ Greedy Robber ID: 3
+ Number of Jewels Picked Up: 7
+ Total Jewel Worth: $65
+
+ Greedy Robber ID: 4
+ Number of Jewels Picked Up: 0
+ Total Jewel Worth: $0
+
diff --git a/output_student_1.txt b/output_student_1.txt
new file mode 100644
index 0000000..a42f86e
--- /dev/null
+++ b/output_student_1.txt
@@ -0,0 +1,313 @@
+Initial positions
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * j j j j j
+j j * * * r p j * j
+* * * * j j * j j j
+j * * * * j * * * j
+* j r j * j j * j j
+* j j j * r j * j j
+* j * * j j * * * *
+* r j j j * * j * *
+
+ ROUND 1
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j r j j j j j
+j j * * * p * j * j
+* * * * j j * j j j
+j * * * * j * * * j
+* j r j * r j * j j
+* j j * * * j * j j
+r j * * j j * * * *
+* * j j j * * j * *
+
+ ROUND 2
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * r j j j j
+j j * * * * * j * j
+* * * * p j * j j j
+j * * * * j r * * j
+* j * j * * j * j j
+* * j * * * j * j j
+r j * * j j * * * *
+r * j j j * * j * *
+
+ ROUND 3
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j j j j
+j j * p r * * j * j
+* * * * * j * j j j
+j * * * * j * * * j
+* j * j * * j r j j
+* * j * * * j * j j
+r j * * j j * * * *
+r * j j j * * j * *
+
+ ROUND 4
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * r j j j j
+j j * * * * * j * j
+* * * * p j * j j j
+j * * * * j * * * j
+* j * j * * j * j j
+* * j * * * r * j j
+r j * * j j * * * *
+* r j j j * * j * *
+
+ ROUND 5
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j j j j
+j j * * * * r j * j
+* * * p * j * j j j
+j * * * * j * * * j
+* j * j * * j r j j
+* * j * * * * * j j
+* r * * j j * * * *
+r * j j j * * j * *
+
+ ROUND 6
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j r j j
+j j * * * * * j * j
+* * * * p j * j j j
+j * * * * j * * * j
+* j * j * * j * j j
+* * j * * * * * r j
+r * * * j j * * * *
+r * j j j * * j * *
+
+ ROUND 7
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * j j
+j j * * * p r j * j
+* * * * * j * j j j
+j * * * * j * * * j
+* j * j * * j r j j
+* * j * * * * * * j
+* r * * j j * * * *
+* r j j j * * j * *
+
+ ROUND 8
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * j j
+j j * * p * * j * j
+* * * * * j r j j j
+j * * * * j * * * j
+* j * j * * j * j j
+* * j * * * r * * j
+* r r * j j * * * *
+* * j j j * * j * *
+
+ ROUND 9
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * j j
+j j * * * * * * * j
+* * * * * p r j j j
+j * * * * j * * * j
+* j * j * r j * j j
+r * j * * * * * * j
+* * * * j j * * * *
+* * j * r * * j * *
+
+ ROUND 10
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * j j
+j j * * * * p r * j
+* * * * * * * j j j
+j * * * r j * * * j
+* j * j * * j * j j
+* r j * * * * * * j
+* * * * j j * * * *
+* * j * * r * j * *
+
+ ROUND 11
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * * j
+j j * * * * * r * j
+* * * * * * * p j j
+j * * * * j * * * j
+* j * j * r j * j j
+* * r * * * * * * j
+* * * * j r * * * *
+* * j * * * * j * *
+
+ ROUND 12
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * * j
+j j * * * * r p * j
+* * * * * * * * j j
+j * * * * j * * * j
+* j * j r * j * j j
+* * * r * * * * * j
+* * * * j * * * * *
+* * j * * r * j * *
+
+ ROUND 13
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * * j
+j j * * * * * * * j
+* * * * * * * r j j
+j * * * * * r * * j
+* j r j * * j * j j
+* * * * * * * * * j
+* * * * j r * * * *
+* * j * * * * j * *
+
+ ROUND 14
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * * j
+j j * * * * * * * j
+* * * * * * * r p j
+j * * r * j * * * j
+* j * j * * j * j j
+* * * * * * * * j j
+* * * * j * * * * *
+* * j * * * r j * *
+
+ ROUND 15
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * * j
+j j * * * * * * p j
+* * * * * * * r * j
+j * r * * j r * * j
+* j * j * * j * j j
+* * * * * * * * j j
+* * * * j * * * r *
+* * j * * * * * * *
+
+ ROUND 16
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * * j
+j j * * * * * * * j
+* * * * * * * r * j
+j * * * * * * * * j
+* r * j * * * * j j
+* * * * * * * r j j
+* * * * j * * * * *
+* * j * * * * * r *
+
+ ROUND 17
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * * j
+j j * * * * * * * j
+* * * * * * p r * j
+j * * * * * * * * j
+* * * j * * * r j j
+r * * * * * * * j j
+* * * * j * * r * *
+* * j * * * * * * *
+
+ ROUND 18
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * * j
+j j * * * * * p * j
+* * * * * * * r * j
+j * * * * * * * r j
+* * * j * * * * j j
+* * * * * * * * r j
+* r * * j * * * * *
+* * j * * * * * * *
+
+ ROUND 19
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * p j
+j j * * * * * * * j
+* * * * * * * r * j
+j * * * * * * r * j
+* * * j * * * * * j
+* * * * * * * r * *
+* * r * j * * * * *
+* * j * * * * * * *
+
+ ROUND 20
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * * j
+j j * * * * * * p j
+* * * * * * r r * j
+j * * * * * * * * j
+* * * j * * * * * j
+* * * * * * * * * *
+* * * * j * r * * *
+* r j * * * * * * *
+
+ ROUND 21
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * * j
+j j * * * * * r * j
+* * * * * * * r * j
+j * * * * * * * * j
+* * * j * * * * * j
+* * * * * r * * * *
+* * * * j * * * * *
+* * r * * * * * * *
+
+ ROUND 22
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * * j
+j j * * * * * r p j
+* * * * * * * r * j
+j * * * * * * * * j
+* * * j * * * * * j
+* * * * * * r * * *
+* * * * j * * * * *
+* * * r * * * * * *
+
+ ROUND 23
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * * j
+j j * * * * * r * j
+* * * * * * * r * j
+j * * * * * * * * j
+* * * j * * * * * j
+* * * * * r * * * *
+* * * * j * * * * *
+* * * * r * * * * *
+
+ ROUND 24
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * * j
+j j * * * * * r * j
+* * * * * * p r * j
+j * * * * * * * * j
+* * * j * * * * * j
+* * * * * * r * * *
+* * * * * * * * * *
+* * * * r * * * * *
+
+ ROUND 25
+* * * * * * j * j j
+j * j * * j * j j j
+j * * j * * j * * j
+j j * * * * * r * j
+* * * * * * * r * j
+j * * * * * p * * j
+* * * j * * * * * j
+* * * * * * * * * *
+* * * * * * * r * *
+* * * r * * * * * *
+
+ ROUND 26 \ No newline at end of file
diff --git a/robber.h b/robber.h
new file mode 100644
index 0000000..7193ae6
--- /dev/null
+++ b/robber.h
@@ -0,0 +1,70 @@
+#ifndef ROBBER_H
+#define ROBBER_H
+
+// Programmer: Brett Weiland
+// Date: 4/30/23
+// File: robber.h
+// Assignment: SP-B-finalProject
+// Purpose: contains robber class, an npc that steals money and runs away from cops.
+// has different characteristics based on greedy variable, wanted to use a single
+// object for both greedy and non-greedy robbers to ensure I was following the assignment.
+
+#include "npc.h"
+
+
+template <class T>
+class cop;
+
+template <class T>
+class robber : public npc<T> {
+ private:
+ //even while our inherited inventory is of inherited constant INVENTORY_SIZE,
+ //we can't pick up more then BAG_SIZE. INVENTORY_SIZE is used due to the fact we can't
+ //change the length of the array during construction; see npc.h for more info.
+ const unsigned int BAG_SIZE = 7;
+
+ //maximum amount of consecutive moves a robber can make if something allows them to make more
+ const unsigned int MAX_MOVES = 3;
+
+ //Desc: called to handle what happens when we run into a certain type of object.
+ //Pre: valid peer passed
+ //Post: interaction is carried out dependent on what type of gameObject we're dealing with
+ bool handleInteractable(gameObject &peer);
+
+ //Desc: finds all gameObjects we are located on and calls handleInteractable
+ //Pre: none
+ //Post: handleInteractable called for each gameObject we are stacked on
+ bool iterateInteractables();
+
+ //changes how the robber moves. If this is set to true,
+ //robber will always move twords a random jewl if available,
+ //and will bribe officer with one inventory item to release all robbers.
+ //if robber is greedy and runs into another rober, half of inventory is dropped.
+ //robber can move up to MAX_MOVES times in a round if they get an item with even value.
+ bool greedy;
+ static unsigned int total_loot_value;
+
+ public:
+ //Desc: called when robber is arrested. returns inventory pointer to caller,
+ // cop uses this to record items in their own stash.
+ //Pre: none
+ //Post: npc is no longer active (can't move), more behavior is defined by cop arrest() function
+ T **getArrested();
+
+ //overriden functions, see respective files
+ void move() override; //npc.h
+ char getIcon() const override; //gameObject.h
+ unsigned int get_drawPriority() const override; //gameObject.h
+
+ //getters and setters
+ void setGreedy(const bool greedy_value);
+ bool isGreedy() const;
+ void free(); //sets us to active
+ unsigned int get_totalRobberValue() const; //returns combined value of ALL robbers
+};
+
+template <class T> unsigned int robber<T>::total_loot_value = 0;
+
+#include "robber.hpp"
+
+#endif
diff --git a/robber.hpp b/robber.hpp
new file mode 100644
index 0000000..9c2c81e
--- /dev/null
+++ b/robber.hpp
@@ -0,0 +1,91 @@
+#include <math.h>
+#include <typeinfo>
+
+// Programmer: Brett Weiland
+// Date: 4/30/23
+// File: cop.hpp
+// Assignment: SP-B-finalProject
+// Purpose: contains member functions for robber class; see robber.h
+
+#include "cop.h"
+
+template <class T> void robber<T>::setGreedy(const bool greedy_value) { greedy = greedy_value; }
+template <class T> unsigned int robber<T>::get_drawPriority() const { return 0; }
+template <class T> void robber<T>::free() { this->active = true; }
+template <class T> bool robber<T>::isGreedy() const { return greedy; }
+
+template <class T> bool robber<T>::iterateInteractables() {
+ for(gameObject *peer = this->parentCity->findObjsByLocation(this->location);
+ peer != NULL; peer = peer->get_top()) {
+ return handleInteractable(*peer);
+ }
+ return false;
+}
+
+template <class T> bool robber<T>::handleInteractable(gameObject &peer) {
+ const std::type_info &peer_type = typeid(peer);
+ if(peer_type == typeid(robber<T>)) {
+ if(!greedy) return false;
+ this->inventory_qty /= 2;
+ for(size_t loot_i = this->inventory_qty;
+ (loot_i < BAG_SIZE) && (this->inventory[loot_i] != NULL); loot_i++) {
+ total_loot_value -= this->inventory[loot_i]->value();
+ this->inventory[loot_i]->drop();
+ this->inventory[loot_i] = NULL;
+ }
+ }
+
+ if(peer_type == typeid(cop<T>)) {
+ cop<T> &popo = dynamic_cast<cop<T>&>(peer);
+ if(greedy && (this->inventory_qty >= BAG_SIZE)) {
+ this->inventory_qty--;
+ popo.takeBribe(this->inventory[this->inventory_qty]);
+ total_loot_value -= this->inventory[this->inventory_qty]->value();
+ this->inventory[this->inventory_qty] = NULL;
+ } else { popo.arrest(*this); }
+ return false;
+ }
+
+ if(peer_type == typeid(T)) {
+ if(this->inventory_qty >= BAG_SIZE) return false;
+ this->inventory[this->inventory_qty] = dynamic_cast<T*>(&peer);
+ this->inventory[this->inventory_qty]->pickup();
+ total_loot_value += this->inventory[this->inventory_qty]->value();
+ if(!(this->inventory[this->inventory_qty++]->value() % 2)) return true;
+ }
+ return false;
+}
+
+
+template <class T> void robber<T>::move() {
+ for(unsigned int moves = 0; moves < MAX_MOVES; moves++) {
+ if(greedy) {
+ if(this->inventory_qty >= BAG_SIZE)
+ this->location.stepDirection(this->parentCity->nearestCopDirection(this->location));
+ else
+ this->location.stepDirection(this->parentCity->directionToAnyJewl(this->location));
+ }
+ else {
+ this->location.stepDirection(this->parentCity->randomDirection(this->location));
+ }
+ if(!iterateInteractables()) break;
+ }
+}
+
+
+template <class T> T **robber<T>::getArrested() {
+ this->active = false;
+ total_loot_value -= this->get_inventoryValue();
+ this->inventory_qty = 0;
+ return this->inventory;
+}
+
+template <class T> char robber<T>::getIcon() const {
+ if(this->bottom_obj == NULL) return 'r';
+ if((typeid(*this->bottom_obj) == typeid(robber<T>)) && (dynamic_cast<robber<T>*>(this->bottom_obj)->active)) {
+ return 'R';
+ }
+ return 'r';
+}
+
+template <class T> unsigned int robber<T>::get_totalRobberValue() const { return total_loot_value; }