diff options
author | root <root@bpcserver.bpcserver> | 2024-02-27 21:53:44 -0600 |
---|---|---|
committer | root <root@bpcserver.bpcserver> | 2024-02-27 21:53:44 -0600 |
commit | afa02f645056c5823b0d8a29d37c1ff10aedce7a (patch) | |
tree | 0bc89e7909c17d8f33538ac9f31a641872b89f40 |
-rw-r--r-- | .gitignore | 9 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | city.cpp | 227 | ||||
-rw-r--r-- | city.h | 164 | ||||
-rw-r--r-- | coordinate.cpp | 45 | ||||
-rw-r--r-- | coordinate.h | 70 | ||||
-rw-r--r-- | cop.h | 48 | ||||
-rw-r--r-- | cop.hpp | 48 | ||||
-rw-r--r-- | gameObject.cpp | 29 | ||||
-rw-r--r-- | gameObject.h | 81 | ||||
-rw-r--r-- | grade.md | 10 | ||||
-rw-r--r-- | input_1.txt | 0 | ||||
-rw-r--r-- | jewl.cpp | 26 | ||||
-rw-r--r-- | jewl.h | 35 | ||||
-rw-r--r-- | main.cpp | 38 | ||||
-rw-r--r-- | makefile | 23 | ||||
-rw-r--r-- | npc.h | 83 | ||||
-rw-r--r-- | npc.hpp | 21 | ||||
-rw-r--r-- | output_1.txt | 457 | ||||
-rw-r--r-- | output_student_1.txt | 313 | ||||
-rw-r--r-- | robber.h | 70 | ||||
-rw-r--r-- | robber.hpp | 91 |
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; +} @@ -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 @@ -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 @@ -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(); +} @@ -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) @@ -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 @@ -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; } |