diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..9b49b44 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,33 @@ +# Universal makefile for single C++ program +# +# Use gcc flag -MMD (user) or -MD (user/system) to generate dependencies among source files. +# Use make default rules for commonly used file-name suffixes and make variables names. +# +# % make [ a.out ] + +########## Variables ########## + +CXX = g++ # compiler +CXXFLAGS = -std=c++20 -g -Wall -MMD -lncurses # compiler flags +MAKEFILE_NAME = ${firstword ${MAKEFILE_LIST}} # makefile name + +SOURCES = $(wildcard *.cc) # source files (*.cc) +OBJECTS = ${SOURCES:.cc=.o} # object files forming executable +DEPENDS = ${OBJECTS:.o=.d} # substitute ".o" with ".d" +EXEC = cc3k # executable name + +########## Targets ########## + +.PHONY : clean # not file names + +${EXEC} : ${OBJECTS} # link step + ${CXX} ${CXXFLAGS} $^ -o $@ # additional object files before $^ + +${OBJECTS} : ${MAKEFILE_NAME} # OPTIONAL : changes to this file => recompile + +# make implicitly generates rules to compile C++ files that generate .o files + +-include ${DEPENDS} # include *.d files containing program dependences + +clean : # remove files that can be regenerated + rm -f ${DEPENDS} ${OBJECTS} ${EXEC} diff --git a/src/cc3k b/src/cc3k new file mode 100755 index 0000000..36ef6ea Binary files /dev/null and b/src/cc3k differ diff --git a/src/characters.cc b/src/characters.cc new file mode 100644 index 0000000..5cbb57e --- /dev/null +++ b/src/characters.cc @@ -0,0 +1,152 @@ +#include "characters.h" + +#include + +character::character(const enum race &nrace): + race{nrace}, HP{STARTING_HP[race]}, + ATK{STARTING_ATK[race]}, DEF{STARTING_DEF[race]} {} + +character::~character() {} + +enum race character::get_race() const { + return race; +} + +position character::get_position() const { + return pos; +} + +int character::get_HP() const { + return HP; +} + +int character::get_ATK() const { + return ATK; +} + +int character::get_DEF() const { + return DEF; +} + +int character::get_gold() const { + return gold; +} + +float character::get_hitrate() const { + return base_hitrate; +} + +bool character::is_hostile() const { + return hostile; +} + +void character::set_position(const position &npos) { + pos = npos; +} + +void character::set_HP(const int nHP) { + HP = nHP; +} + +void character::set_ATK(const int nATK) { + ATK = nATK; +} + +void character::set_DEF(const int nDEF) { + DEF = nDEF; +} + +void character::set_gold(const int ngold) { + gold = ngold; +} + +void character::set_hitrate(const float nhitrate) { + base_hitrate = nhitrate; +} + +void character::set_hostile(const bool is_hostile) { + hostile = is_hostile; +} + +void character::apply_buff(const stat_name statn, const int amount) { + switch (statn) { + case stat_name::HP: + HP += amount; + break; + + case stat_name::ATK: + ATK += amount; + break; + + case stat_name::DEF: + DEF += amount; + break; + + case stat_name::hostile: { + if (amount > 0) + hostile = true; + else + hostile = false; + + break; + } + } +} + +character_list::character_list(): + layer{layer_num::characters} {} + +void character_list::print() const { + // TODO: implement it using ncurses +} + +void character_list::print(display &display) const { + for (auto &ch : characters) + display.print_position(ch->get_position(), + CHARACTER_REP[ch->get_race()]); +} + +std::vector>::const_iterator character_list::begin() +const { + return characters.begin(); +} + +std::vector>::const_iterator character_list::end() +const { + return characters.end(); +} + +direction_list character::moveable(const position_list &available_positions) +const { + direction_list result; + + for (int i = 0; i < DIRECTION_CNT; ++i) + if (find(available_positions, pos + MOVE[i]) + != available_positions.size()) + result.push_back((direction)i); + + return result; +} + +result character::apply(direction &dir, const potion_list &potions) { + // TODO: implement this after implementing potions + return result::fine; +} + +position_list remove_from_list(const position_list &sorted_positions, + position_list excluded) { + std::sort(excluded.begin(), excluded.end()); + + position_list result{sorted_positions.size() - excluded.size()}; + + auto exc = excluded.begin(); + + for (auto src : sorted_positions) { + if (exc != excluded.end() && src == *exc) + ++exc; + else + result.push_back(src); + } + + return result; +} diff --git a/src/characters.d b/src/characters.d new file mode 100644 index 0000000..7c752ae --- /dev/null +++ b/src/characters.d @@ -0,0 +1,2 @@ +characters.o: characters.cc characters.h constants.h position.h layer.h \ + display.h objects.h rng.h diff --git a/src/characters.h b/src/characters.h new file mode 100644 index 0000000..5be2c96 --- /dev/null +++ b/src/characters.h @@ -0,0 +1,99 @@ +/* + * CS 246 Final Project + * File: map.h + * Purpose: handles all characters + */ + +#ifndef __CHARACTERS_H__ +#define __CHARACTERS_H__ +#include +#include +#include +#include "constants.h" +#include "position.h" +#include "layer.h" +#include "objects.h" +#include "rng.h" +// #include "inventory.h" // Reserved for later + +class character; // forward declaration +extern RNG rng; + +// Note: player should not be in the character list +class character_list final: public layer { +private: + std::vector> characters; +public: + character_list(); + void print() const; + void print(display &display) const; + + std::vector>::const_iterator begin() const; + std::vector>::const_iterator end() const; +}; + +class character { +public: + character(const race &nrace); // fills out the starting stats + + ~character(); // placeholder + + // usually I wouldn't do this but considering that the map has + // a super small size an O(n) solution is acceptable + // IMPORTANT: available_positions do NOT have characters in them + direction_list moveable(const position_list &available_positions) const; + virtual result move(const direction dir, + const position_list &available_positions) = 0; + virtual result attack(const direction dir, + const character_list &chlist) = 0; + virtual result move_or_attack(const direction dir, + const position_list &available_positions, + const character_list &chlist) = 0; + virtual result apply(direction &dir, + const potion_list &potions); + virtual result get_hit(const enum race &race, const int atk, + const float hitrate) = 0; + enum race get_race() const; + position get_position() const; + int get_HP() const; + int get_ATK() const; + int get_DEF() const; + int get_gold() const; + float get_hitrate() const; + bool is_hostile() const; + + void set_position(const position &npos); + void set_HP(const int nHP); + void set_ATK(const int nATK); + void set_DEF(const int nDEF); + void set_gold(const int ngold); + void set_hitrate(const float nhitrate); + void set_hostile(const bool is_hostile); + + // if stat is hostile, positive to set it to hostile, + // negative to set it to peaceful + void apply_buff(const stat_name statn, const int amount); + // void apply_buff(const stat_name statn, const float mul); + // reserved for later +protected: + const enum race race; + + int HP; + int ATK; + int DEF; + + position pos; + + int gold; // characters spawn with gold + // inventory inventory; // Reserved + + float base_hitrate; // requires: between [0,1] + + bool hostile; +}; + +// requires: all elements of excluded are in sorted_positions +position_list remove_from_list(const position_list &sorted_positions, + position_list excluded); + +#endif diff --git a/src/characters.o b/src/characters.o new file mode 100644 index 0000000..3d3cfaa Binary files /dev/null and b/src/characters.o differ diff --git a/src/constants.h b/src/constants.h new file mode 100644 index 0000000..5ec97ec --- /dev/null +++ b/src/constants.h @@ -0,0 +1,67 @@ +// TODO: Consider moving the contents of this header to their relevant +// headers + +#ifndef __CONSTANTS_H__ +#define __CONSTANTS_H__ +#include +#include "position.h" + +// IMPORTANT: added END to the end of all valued enums so that you can +// iterate over them + +enum error {none}; + +// TODO: update result to include subject +enum result {fine, died, go_down, hit, moved}; + +enum stat_name {HP, ATK, DEF, hostile}; + +const int LAYER_CNT = 4; // TODO: update as you go +enum layer_num {map = 0, objects, characters, shop}; + +const int RACE_CNT = 2; // TODO: update as you go + +enum race {unknown = 0, rshade /* TODO: fill out the other races (including enemies) */}; + +// TODO: fill out the other races (including enemies) +const int MAX_HP[RACE_CNT] = {0, 125}; +const int STARTING_HP[RACE_CNT] = {0, 125}; +const int STARTING_ATK[RACE_CNT] = {0, 25}; +const int STARTING_DEF[RACE_CNT] = {0, 25}; +const char CHARACTER_REP[RACE_CNT] = {'@', 'S'}; + +const int DIRECTION_CNT = 8; +// IMPORTANT: east is positive for x and SOUTH is positive for y +// initializes all directions to an int +enum direction {east = 0, west, north, south, northeast, + northwest, southeast, southest + }; + +const position MOVE[DIRECTION_CNT] = { + {1, 0}, {-1, 0}, {0, -1}, {0, 1}, + {1, -1}, {-1, -1}, {1, 1}, {-1, 1} +}; + +const int MAP_HEIGHT = 25; +const int MAP_WIDTH = 79; +const int DISPLAY_HEIGHT = 30; +const int DISPLAY_WIDTH = 79; + +// TODO: list all extra features +// using constants to keep track of features +// method: features: FEATURE_XXX | FEATURE_YYY +// That is: use bit manipulation +// check if feature is enabled: +// features & FEATURE_XXX +typedef unsigned int feature; // can extend to unsigned long (long) if needed +const feature FEATURE_NCURSES = 1 << 0; +const feature FEATURE_RAND_MAP = 1 << 1; +const feature FEATURE_ENEMIES_CHASE = 1 << 2; +const feature FEATURE_INVENTORY = 1 << 3; +const feature FEATURE_THROW = 1 << 4; +const feature FEATURE_REVISIT = 1 << 5; + +typedef std::vector position_list; +typedef std::vector direction_list; + +#endif diff --git a/src/display.cc b/src/display.cc new file mode 100644 index 0000000..cc1d450 --- /dev/null +++ b/src/display.cc @@ -0,0 +1,21 @@ +#include "display.h" + +display::display(): contents{DISPLAY_HEIGHT} {} + +void display::clear() { + for (auto line : contents) + line.clear(); +} + +void display::print(std::ostream &out) const { + for (auto line : contents) + out << line << std::endl; +} + +void display::print_line(const std::string &line, const int linenum) { + contents[linenum] = line; +} + +void display::print_position(const position &pos, const char ch) { + contents[pos.y][pos.x] = ch; +} diff --git a/src/display.d b/src/display.d new file mode 100644 index 0000000..56adad5 --- /dev/null +++ b/src/display.d @@ -0,0 +1 @@ +display.o: display.cc display.h position.h constants.h diff --git a/src/display.h b/src/display.h new file mode 100644 index 0000000..8d9d36f --- /dev/null +++ b/src/display.h @@ -0,0 +1,30 @@ +/* + * CS 246 Final Project + * File: display.h + * Purpose: handles map functionality + */ + +#ifndef __DISPLAY_H__ +#define __DISPLAY_H__ +#include +#include +#include +#include "position.h" +#include "constants.h" + +class display final { +private: + std::vector contents; +public: + display(); + + void clear(); + // use this instead of overloading for clarity + void print(std::ostream &out) const; + void print_line(const std::string &line, const int linenum); + + // will override any character that was there + void print_position(const position &pos, const char ch); +}; + +#endif diff --git a/src/display.o b/src/display.o new file mode 100644 index 0000000..8eed1d1 Binary files /dev/null and b/src/display.o differ diff --git a/src/layer.h b/src/layer.h new file mode 100644 index 0000000..15ddb7d --- /dev/null +++ b/src/layer.h @@ -0,0 +1,22 @@ +/* + * CS 246 Final Project + * File: map.h + * Purpose: handles map functionality + */ + +#ifndef __LAYER_H__ +#define __LAYER_H__ +#include "constants.h" +#include "display.h" + +class layer { +public: + const layer_num num; + + layer(const layer_num ln): num{ln} {} + + virtual void print() const = 0; + virtual void print(display &display) const = 0; +}; + +#endif diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 0000000..cd78a22 --- /dev/null +++ b/src/main.cc @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include +#include +#include "map.h" +#include "races.h" +#include "display.h" +#include "rng.h" + +using namespace std; + +RNG rng;//{(unsigned int)time(0)}; + +int main() { + display display; + unique_ptr mmap(new game_map{default_map, 0}); + unique_ptr + player(new shade{mmap->get_available_positions()}); + + for (char ch = ' '; ch != 'q'; ch = getchar()) { + display.clear(); + mmap->print(display); + display.print_position(player->get_position(), '@'); + + auto available_positions = mmap->get_available_positions(); + + switch (ch) { + case 'j': + player->move(direction::south, available_positions); + break; + + case 'k': + player->move(direction::north, available_positions); + break; + + case 'h': + player->move(direction::west, available_positions); + break; + + case 'l': + player->move(direction::east, available_positions); + break; + } + } +} diff --git a/src/main.d b/src/main.d new file mode 100644 index 0000000..f7d3c92 --- /dev/null +++ b/src/main.d @@ -0,0 +1,2 @@ +main.o: main.cc map.h objects.h layer.h constants.h position.h display.h \ + characters.h rng.h races.h diff --git a/src/main.o b/src/main.o new file mode 100644 index 0000000..7573f56 Binary files /dev/null and b/src/main.o differ diff --git a/src/map.cc b/src/map.cc new file mode 100644 index 0000000..437202d --- /dev/null +++ b/src/map.cc @@ -0,0 +1,65 @@ +#include "map.h" + +#include +#include +#include + +game_map::game_map(int lvl): + layer{layer_num::map}, map{MAP_HEIGHT}, level{lvl} { + // TODO: randomly generate a map +} + +game_map::game_map(const std::string &map_data, int lvl): + layer{layer_num::map}, map{MAP_HEIGHT}, level{lvl} { + std::istringstream iss{map_data}; + + std::string line; + + for (int i = 0; i < MAP_HEIGHT; ++i) { + getline(iss, line); + map.push_back(line); + } +} + +game_map::~game_map() {} + +int game_map::get_level() const { + return this->level; +} + +std::vector game_map::get_available_positions() const { + std::vector result; + + for (int line = 0; line < MAP_HEIGHT; ++line) + for (int x = 0; x < MAP_WIDTH; ++x) + if (map[line][x] == '.') + result.push_back(position{x, line}); + return result; +} + +void game_map::print() const { + + // TODO: write a print function using ncurses +} + +void game_map::print(display &display) const { + for (int i = 0; i < MAP_HEIGHT; ++i) + display.print_line(map[i] + "\n", i); +} + +void game_map::apply_potion(character *who, const stat_name statn, + const int amount) { + effects.push_back(effect{who, statn, amount}); + who->apply_buff(statn, amount); +} + +void game_map::enter_level(character *who) { + for (auto eff : effects) + if (eff.who == who) + who->apply_buff(eff.statn, eff.amount); +} + +void game_map::leave_level(character *who) { + who->set_ATK(STARTING_ATK[who->get_race()]); + who->set_DEF(STARTING_DEF[who->get_race()]); +} diff --git a/src/map.d b/src/map.d new file mode 100644 index 0000000..8ea14c0 --- /dev/null +++ b/src/map.d @@ -0,0 +1,2 @@ +map.o: map.cc map.h objects.h layer.h constants.h position.h display.h \ + characters.h rng.h diff --git a/src/map.h b/src/map.h new file mode 100644 index 0000000..492a4b0 --- /dev/null +++ b/src/map.h @@ -0,0 +1,87 @@ +/* + * CS 246 Final Project + * File: map.h + * Purpose: handles map functionality + */ + +#ifndef __MAP_H__ +#define __MAP_H__ +#include +#include +#include "objects.h" +#include "constants.h" +#include "display.h" +#include "position.h" +#include "layer.h" +#include "characters.h" + +class game_map final: public layer { +public: + game_map(int lvl = 0); // randomly generate one + // initialize using stored data + game_map(const std::string &map_data, int lvl); + ~game_map(); // placeholder + + int get_level() const; + + position_list get_available_positions() const; + + // IMPORTANT: always print a map before anything else + + // prints using ncurses + void print() const; + + // prints to a string + void print(display &display) const; + + // This is implemented this way to do two things: + // 1. avoid directly accessing heap memory (bonus points) + // 2. make a level revisitable + void apply_potion(character *who, const stat_name statn, const int amount); + + // just in case you want to retain the potion effects + void enter_level(character *who); + void leave_level(character *who); +private: + struct effect { + character *who; + stat_name statn; + int amount; + }; + + std::vector map; + int level; + + // use this to remember every applied potion + std::vector effects; +}; + +const std::string default_map = + "|-----------------------------------------------------------------------------|\ +| |\ +| |--------------------------| |-----------------------| |\ +| |..........................| |.......................| |\ +| |..........................+########+.......................|-------| |\ +| |..........................| # |...............................|--| |\ +| |..........................| # |..................................|--| |\ +| |----------+---------------| # |----+----------------|...............| |\ +| # ############# |...............| |\ +| # # |-----+------| |...............| |\ +| # # |............| |...............| |\ +| ################### |............| ######+...............| |\ +| # # |............| # |...............| |\ +| # # |-----+------| # |--------+------| |\ +| |---------+-----------| # # # # |\ +| |.....................| # # # |----+------| |\ +| |.....................| ######################## |...........| |\ +| |.....................| # # |...........| |\ +| |.....................| # |------+--------------------|...........| |\ +| |.....................| # |.......................................| |\ +| |.....................+##########+.......................................| |\ +| |.....................| |.......................................| |\ +| |---------------------| |---------------------------------------| |\ +| |\ +|-----------------------------------------------------------------------------|\ +"; + +#endif diff --git a/src/map.o b/src/map.o new file mode 100644 index 0000000..cfa85f4 Binary files /dev/null and b/src/map.o differ diff --git a/src/objects.h b/src/objects.h new file mode 100644 index 0000000..e4ae59b --- /dev/null +++ b/src/objects.h @@ -0,0 +1,33 @@ +/* + * CS 246 Final Project + * File: map.h + * Purpose: handles map functionality + */ + +#ifndef __OBJECTS_H__ +#define __OBJECTS_H__ +#include +#include +#include "layer.h" +#include "display.h" + +class object { + // TODO: design the entire class +public: + void print() {} // use ncurses + void print(display &display) {} +}; + +// TODO: throw potion into another header + +class potion final: public object { + // TODO: design the entire class +}; + +class potion_list final: public layer { +private: + std::vector> potions; + // TODO: design the entire class +}; + +#endif diff --git a/src/position.cc b/src/position.cc new file mode 100644 index 0000000..b4f2cdc --- /dev/null +++ b/src/position.cc @@ -0,0 +1,52 @@ +#include "position.h" + +position::position(): x{0}, y{0} {} + +position::position(int nx, int ny): x{nx}, y{ny} {} + +position position::operator+(const position &other) const { + position result{x + other.x, y + other.y}; + return result; +} + +position &position::operator=(const position &other) { + x = other.x; + y = other.y; + return *this; +} + +position &position::operator+=(const position &other) { + return *this = *this + other; +} + +bool position::operator==(const position &other) const { + return x == other.x && y == other.y; +} + +bool position::operator!=(const position &other) const { + return x != other.x || y != other.y; +} + +bool position::operator<(const position &other) const { + return y < other.y || x < other.x; +} + +size_t find(const std::vector &sorted_list, + const position &target) { + int l = 0; + int r = sorted_list.size() - 1; + + while (l <= r) { + int mid = l + (l + r) / 2; + + if (target == sorted_list[mid]) + return mid; + + if (target < sorted_list[mid]) + l = mid + 1; + else + r = mid - 1; + } + + return sorted_list.size(); +} diff --git a/src/position.d b/src/position.d new file mode 100644 index 0000000..39d54bd --- /dev/null +++ b/src/position.d @@ -0,0 +1 @@ +position.o: position.cc position.h diff --git a/src/position.h b/src/position.h new file mode 100644 index 0000000..9a65a45 --- /dev/null +++ b/src/position.h @@ -0,0 +1,29 @@ +/* + * CS 246 Final Project + * File: map.h + * Purpose: handles map functionality + */ + +#ifndef __POSITION_H__ +#define __POSITION_H__ +#include + +typedef struct position { + int x; + int y; + + position(); + position(int nx, int ny); + + position operator+(const position &other) const; + position &operator=(const position &other); + position &operator+=(const position &other); + bool operator==(const position &other) const; + bool operator!=(const position &other) const; + bool operator<(const position &other) const; +} position; + +size_t find(const std::vector &sorted_list, + const position &target); + +#endif diff --git a/src/position.o b/src/position.o new file mode 100644 index 0000000..83ec9de Binary files /dev/null and b/src/position.o differ diff --git a/src/races.cc b/src/races.cc new file mode 100644 index 0000000..882afbe --- /dev/null +++ b/src/races.cc @@ -0,0 +1,68 @@ +#include "races.h" + +#include +#include + +shade::shade(const position_list &available_positions): + character{race::rshade} { + pos = available_positions[rng.rand_under(available_positions.size())]; + gold = 0; + hostile = true; +} + +// IMPORTANT: remember to check if player is on the stairs +result shade::move(const direction dir, + const position_list &available_positions) { + if (find(available_positions, pos + MOVE[dir]) + != available_positions.size()) { + pos += MOVE[dir]; + return result::moved; + } + + return result::fine; +} + +result shade::attack(const direction dir, const character_list &chlist) { + position tmp{pos + MOVE[dir]}; + + for (auto &ch : chlist) + if (tmp == ch->get_position()) { + return ch->get_hit(race, ATK, base_hitrate); + } + + return result::fine; +} + +result shade::move_or_attack(const direction dir, + const position_list &available_positions, + const character_list &chlist) { + position tmp{pos + MOVE[dir]}; + + if (find(available_positions, tmp) + != available_positions.size()) { + pos = tmp; + return result::moved; + } + + for (auto &ch : chlist) + if (tmp == ch->get_position()) { + return ch->get_hit(race, ATK, base_hitrate); + } + + return result::fine; +} + +int calc_dmg(const int ATK, const int DEF) { + return ceil((100 / (100 + DEF)) * ATK); +} + +result shade::get_hit(const enum race &race, const int atk, + const float hitrate) { + if (rng.rand_num() <= hitrate * (float)RAND_MAX) // This is a hit! + HP = std::max(HP - calc_dmg(atk, DEF), 0); + + if (HP == 0) + return result::died; + + return result::hit; +} diff --git a/src/races.d b/src/races.d new file mode 100644 index 0000000..9efc3da --- /dev/null +++ b/src/races.d @@ -0,0 +1,2 @@ +races.o: races.cc races.h characters.h constants.h position.h layer.h \ + display.h objects.h rng.h diff --git a/src/races.h b/src/races.h new file mode 100644 index 0000000..079955d --- /dev/null +++ b/src/races.h @@ -0,0 +1,30 @@ +/* + * CS 246 Final Project + * File: map.h + * Purpose: handles map functionality + */ + +#ifndef __RACES_H__ +#define __RACES_H__ +#include "characters.h" + +// IMPORTANT: assumes all available positions have excluded chlist + +class shade final: public character { +public: + shade(const position_list &available_positions); // spawn at a random place + virtual result move(const direction dir, + const position_list &available_positions) override; + virtual result attack(const direction dir, + const character_list &chlist) override; + virtual result move_or_attack(const direction dir, + const position_list &available_positions, + const character_list &chlist) override; + virtual result get_hit(const enum race &race, const int atk, + const float hitrate) override; +}; + +// TODO: fill out the other races +// TODO: implement enemie movement + +#endif diff --git a/src/races.o b/src/races.o new file mode 100644 index 0000000..199e53c Binary files /dev/null and b/src/races.o differ diff --git a/src/rng.cc b/src/rng.cc new file mode 100644 index 0000000..4f204e6 --- /dev/null +++ b/src/rng.cc @@ -0,0 +1,39 @@ +#include "rng.h" + +RNG::RNG(): init_seed(time(0)), curr_rand_num(0) { + srand(init_seed); +} + +RNG::RNG(const unsigned int seed): init_seed(seed), curr_rand_num(0) { + srand(init_seed); +} + +int RNG::rand_num() { + return curr_rand_num = rand(); +} + +int RNG::rand_between(const int lower_bound, const int upper_bound) { + curr_rand_num = rand(); + + return lower_bound + (curr_rand_num % (upper_bound - lower_bound)); +} + +int RNG::rand_under(const int upper_bound) { + curr_rand_num = rand(); + + return curr_rand_num % upper_bound; +} + +unsigned int RNG::get_init_seed() const { + return init_seed; +} + +int RNG::get_curr_rand_num() const { + return curr_rand_num; +} + +template T &RNG::get_rand_in_vector(const std::vector &vec) { + curr_rand_num = rand(); + + return vec[curr_rand_num % vec.size()]; +} diff --git a/src/rng.d b/src/rng.d new file mode 100644 index 0000000..c30e4c2 --- /dev/null +++ b/src/rng.d @@ -0,0 +1 @@ +rng.o: rng.cc rng.h diff --git a/src/rng.h b/src/rng.h new file mode 100644 index 0000000..4fd8bcf --- /dev/null +++ b/src/rng.h @@ -0,0 +1,30 @@ +#ifndef __RNG_H__ +#define __RNG_H__ + +#include +#include +#include + +// Technically, you should ONLY define one rng for the entire program +// IMPORTANT: pass all RNG objects as references +class RNG final { +private: + const unsigned int init_seed; + int curr_rand_num; +public: + RNG(); // use time(0) as the seed + RNG(const unsigned int seed); // use a seed + + int rand_num(); // returns a random number between 0 and RAND_MAX + + // IMPORTANT: all upper bounds are not included, all lower bounds are + int rand_between(const int lower_bound, const int upper_bound); + // returns a random number between 0 and upper_bound + int rand_under(const int upper_bound); + unsigned int get_init_seed() const; + int get_curr_rand_num() const; + + template T &get_rand_in_vector(const std::vector &vec); +}; + +#endif diff --git a/src/rng.o b/src/rng.o new file mode 100644 index 0000000..fcea155 Binary files /dev/null and b/src/rng.o differ