From afa02f645056c5823b0d8a29d37c1ff10aedce7a Mon Sep 17 00:00:00 2001 From: root Date: Tue, 27 Feb 2024 21:53:44 -0600 Subject: init --- .gitignore | 9 + README.md | 2 + city.cpp | 227 +++++++++++++++++++++++++ city.h | 164 ++++++++++++++++++ coordinate.cpp | 45 +++++ coordinate.h | 70 ++++++++ cop.h | 48 ++++++ cop.hpp | 48 ++++++ gameObject.cpp | 29 ++++ gameObject.h | 81 +++++++++ grade.md | 10 ++ input_1.txt | 0 jewl.cpp | 26 +++ jewl.h | 35 ++++ main.cpp | 38 +++++ makefile | 23 +++ npc.h | 83 ++++++++++ npc.hpp | 21 +++ output_1.txt | 457 +++++++++++++++++++++++++++++++++++++++++++++++++++ output_student_1.txt | 313 +++++++++++++++++++++++++++++++++++ robber.h | 70 ++++++++ robber.hpp | 91 ++++++++++ 22 files changed, 1890 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 city.cpp create mode 100644 city.h create mode 100644 coordinate.cpp create mode 100644 coordinate.h create mode 100644 cop.h create mode 100644 cop.hpp create mode 100644 gameObject.cpp create mode 100644 gameObject.h create mode 100644 grade.md create mode 100644 input_1.txt create mode 100644 jewl.cpp create mode 100644 jewl.h create mode 100644 main.cpp create mode 100644 makefile create mode 100644 npc.h create mode 100644 npc.hpp create mode 100644 output_1.txt create mode 100644 output_student_1.txt create mode 100644 robber.h create mode 100644 robber.hpp 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 +#include +#include + +// 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 *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 &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 +#include +#include + +#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 cops[COPS_COUNT]; + robber 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 &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 +#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 + +//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 robber; + +template +class cop : public npc { + 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 &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 +#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 char cop::getIcon() const { return 'p'; } +template unsigned int cop::get_drawPriority() const { return 1; } +template unsigned int cop::get_robbersCaught() const { return robbers_caught; } +template void cop::robbersReleased() { robbers_caught = 0; } + +template void cop::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)) { + robber &rob = dynamic_cast&>(*peer); + if(rob.is_active()) arrest(rob); + } + + if(peer_type == typeid(T)) { + this->inventory[this->inventory_qty] = dynamic_cast(peer); + this->inventory[this->inventory_qty++]->pickup(); + } + } +} + +template void cop::arrest(robber &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 void cop::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 +#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
+Email: mppmdf@umsystem.edu
+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 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 + 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 +#include +#include +#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 +#include + +#include "gameObject.h" +#include "coordinate.h" + +template +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 int npc::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 npc::npc() { id = id_counter++; } +template bool npc::is_active() const { return active; } +template int npc::get_id() const { return id; } + +template unsigned int npc::get_inventoryQty() const { return inventory_qty; } + +template unsigned int npc::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 cop; + +template +class robber : public npc { + 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 unsigned int robber::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 +#include + +// 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 void robber::setGreedy(const bool greedy_value) { greedy = greedy_value; } +template unsigned int robber::get_drawPriority() const { return 0; } +template void robber::free() { this->active = true; } +template bool robber::isGreedy() const { return greedy; } + +template bool robber::iterateInteractables() { + for(gameObject *peer = this->parentCity->findObjsByLocation(this->location); + peer != NULL; peer = peer->get_top()) { + return handleInteractable(*peer); + } + return false; +} + +template bool robber::handleInteractable(gameObject &peer) { + const std::type_info &peer_type = typeid(peer); + if(peer_type == typeid(robber)) { + 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)) { + cop &popo = dynamic_cast&>(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(&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 void robber::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 T **robber::getArrested() { + this->active = false; + total_loot_value -= this->get_inventoryValue(); + this->inventory_qty = 0; + return this->inventory; +} + +template char robber::getIcon() const { + if(this->bottom_obj == NULL) return 'r'; + if((typeid(*this->bottom_obj) == typeid(robber)) && (dynamic_cast*>(this->bottom_obj)->active)) { + return 'R'; + } + return 'r'; +} + +template unsigned int robber::get_totalRobberValue() const { return total_loot_value; } -- cgit v1.2.3