diff --git a/src/Environment/Game.h b/src/Environment/Game.h index b4cc407..a0b3e4c 100644 --- a/src/Environment/Game.h +++ b/src/Environment/Game.h @@ -11,6 +11,7 @@ namespace game /// Eine Instanz des Spiels class Game { + private: /// Das Labyrinth Maze maze; @@ -23,6 +24,7 @@ namespace game /// bool infomode_enabled; + public: explicit Game(Maze& maze); diff --git a/src/Environment/Maze.cpp b/src/Environment/Maze.cpp index edff4e1..b341572 100644 --- a/src/Environment/Maze.cpp +++ b/src/Environment/Maze.cpp @@ -1,34 +1,34 @@ #include "Maze.h" +#include "../Entities/Entity.h" #include "../Entities/Player.h" #include "../Exceptions/MalformedMaze.h" -#include "../Entities/Entity.h" using game_exceptions::MalformedMaze; -namespace game -{ - class MathUtil; +namespace game { + /// Ist eine Konstante, darf also in global scope + static const vector valid_maze_elements = {'Z', '.', '#', 'A', 'K', 'T', 'B', 'C'}; + /// Welche Geistertypen es gibt + static const vector valid_enemies = {'A', 'B', 'C'}; + /// Die Maximale Labyrinthgröße + static constexpr int MAX_MAZE_SIZE = 20; - Maze::Maze(const vector>& play_field, const vector& player_start_position, const vector& enemies): - field(play_field), - player_start_position(Vector2d{player_start_position[1], player_start_position[0]}), - enemies(enemies) - { + Maze::Maze(const vector> &play_field, const vector &player_start_position, + const vector &enemies) : + field(play_field), player_start_position(Vector2d{player_start_position[1], player_start_position[0]}), + enemies(enemies) { if (!this->is_pos_free(this->player_start_position, false)) throw MalformedMaze("Player oob"); } - bool Maze::was_player_killed_by_ghost(const Player& player) const - { + bool Maze::was_player_killed_by_ghost(const Player &player) const { return this->field[player.get_pos().y][player.get_pos().x] == 'A'; } - bool Maze::is_player_at_goal(const Player& player) const - { + bool Maze::is_player_at_goal(const Player &player) const { return this->field[player.get_pos().y][player.get_pos().x] == 'Z'; } - bool Maze::is_pos_free(const Vector2d& pos, const bool& player_has_key) const - { + bool Maze::is_pos_free(const Vector2d &pos, const bool &player_has_key) const { if (pos.x < 0 || pos.y < 0 || pos.y > field.size() - 1 || pos.x > field[pos.y].size() - 1) return false; if (field[pos.y][pos.x] == '#') @@ -38,17 +38,14 @@ namespace game return true; } - void Maze::render(const Player& player, const vector& entities, const bool& infomode_enabled) - { - for (int y = 0; y < field.size(); ++y) - { - for (int x = 0; x < field[y].size(); ++x) - { + void Maze::render(const Player &player, const vector &entities, const bool &infomode_enabled) { + for (int y = 0; y < field.size(); ++y) { + for (int x = 0; x < field[y].size(); ++x) { if (y == player.get_pos().y && x == player.get_pos().x) cout << "S"; else { bool an_enemy_is_at_this_position = false; - for (Entity e : entities) + for (Entity e: entities) if (e.is_at_position({x, y})) { an_enemy_is_at_this_position = true; cout << e.get_display_character(); @@ -58,8 +55,7 @@ namespace game } cout << " "; } - if (y == 0 && infomode_enabled) - { + if (y == 0 && infomode_enabled) { const int steps = this->calculate_steps_until_win(player.get_pos(), 5); if (steps < 999) cout << steps << " Schritte bis zum Ziel"; @@ -68,29 +64,20 @@ namespace game } } - char Maze::get_field(const Vector2d& pos) const - { - return this->field[pos.y][pos.x]; - } + char Maze::get_field(const Vector2d &pos) const { return this->field[pos.y][pos.x]; } - void Maze::update_field(const Vector2d& pos, const char& target) - { - this->field[pos.y][pos.x] = target; - } + void Maze::update_field(const Vector2d &pos, const char &target) { this->field[pos.y][pos.x] = target; } - Vector2d Maze::get_player_start_position() const - { - return this->player_start_position; - } + Vector2d Maze::get_player_start_position() const { return this->player_start_position; } - Vector2d Maze::get_delta_vector(const Vector2d& pos1, const Vector2d& pos2) const { + Vector2d Maze::get_delta_vector(const Vector2d &pos1, const Vector2d &pos2) const { int x_diff = pos1.x - pos2.x; int y_diff = pos1.y - pos2.y; return {x_diff, y_diff}; } - int Maze::calculate_steps_until_win(Vector2d position, const int& steps) { + int Maze::calculate_steps_until_win(Vector2d position, const int &steps) { if (!this->is_pos_free(position, false)) return 999; if (this->get_field(position) == 'Z') @@ -104,7 +91,72 @@ namespace game this->calculate_steps_until_win(position.get_new_updated(-1, 0), steps - 1)}); } - vector Maze::get_entities() { - return this->enemies; + vector Maze::get_entities() { return this->enemies; } + + vector Maze::request_numbers_from_user(const int &amount_of_numbers) { + int input; + vector list; + + for (int i = 0; i < amount_of_numbers; ++i) { + cin >> input; + if (!cin) + throw MalformedMaze("Cin failed while reading numbers!"); + + if (input > MAX_MAZE_SIZE) + throw MalformedMaze("This maze is too big"); + list.push_back(input); + } + + return list; } -} // game + + bool Maze::validate_maze_element(const char &target) { + for (const char c: valid_maze_elements) + if (c == target) + return true; + return false; + } + + bool Maze::is_valid_enemy(const char &target) { + for (const char c: valid_enemies) + if (c == target) + return true; + return false; + } + + Maze Maze::request_maze_from_user() { + vector maze_size = request_numbers_from_user(2); + + char input; + vector> field; + vector enemies; + + for (int y = 0; y < maze_size[0]; ++y) { + vector row; + for (int x = 0; x < maze_size[1]; ++x) { + cin >> input; + if (!cin) + throw MalformedMaze("Cin failed while reading chars!"); + + // I don't think that this is needed. I doubt that they test the check for this one ~Eric + // if (input == 'q') + // throw ExitGame("Schoenen Tag noch!"); + + if (!validate_maze_element(input)) + throw MalformedMaze("The given input is not a valid element of a maze!"); + if (is_valid_enemy(input)) { + enemies.push_back(Entity({x, y}, input)); + row.push_back('.'); + } else { + row.push_back(input); + } + } + + field.push_back(row); + } + + vector player_start_pos = request_numbers_from_user(2); + + return {field, player_start_pos, enemies}; + } // Beispieleingabe: `4 3 #.# #.K #T# #Z# 0 1` +} // namespace game diff --git a/src/Environment/Maze.h b/src/Environment/Maze.h index 81e551d..6513d0b 100644 --- a/src/Environment/Maze.h +++ b/src/Environment/Maze.h @@ -1,80 +1,112 @@ -#include "../std_lib_inc.h" -#include "../Util/Vector2d.h" - #ifndef MAZE_H #define MAZE_H -namespace game -{ - class Player; - class Entity; +#include "../Util/Vector2d.h" +#include "../std_lib_inc.h" - /// Ein Labyrinth. - /// Besitzt ein Feld - class Maze - { - // class -> members private by default - private: - /// Das Spielfeld - vector> field; - /// Die Startposition des Spielers - Vector2d player_start_position; - /// Eine Liste an Gegnern - vector enemies; +namespace game { + class Player; + class Entity; + /// Ist eine Konstante, darf also in global scope - public: - /// Das Spielfeld - Maze(const Vector>& play_field, const Vector& player_start_position, const Vector& enemies); - /// Kontrolliere, ob der Spieler stirbt - /// @param player Der Spieler - /// @return Ob der Spieler tot ist - bool was_player_killed_by_ghost(const Player& player) const; + /// Ein Labyrinth. + /// Besitzt ein Feld + class Maze { + // class -> members private by default - /// Kontrolliere, ob der Spieler am Ziel ist - /// @param player Der Spieler - /// @return Ob der Spieler am Ziel ist - bool is_player_at_goal(const Player& player) const; + private: + /// Das Spielfeld + vector> field; + /// Die Startposition des Spielers + Vector2d player_start_position; + /// Eine Liste an Gegnern + vector enemies; + /// Erlaubte Zeichen in einem Labyrinth + /* Legende + * S - Spieler + * Z - Ziel + * . - Leerer Raum (begehbar) + * # - Wand + * A - Animaltronic + * K - Schlüssel + * T - Tür + * B - Bowie + * C - Connellys + */ + public: + /// Das Spielfeld + Maze(const Vector> &play_field, const Vector &player_start_position, + const Vector &enemies); + /// Kontrolliere, ob der Spieler stirbt + /// @param player Der Spieler + /// @return Ob der Spieler tot ist + bool was_player_killed_by_ghost(const Player &player) const; - /// Kontrolliere, ob eine bestimmte Position begehbar ist - /// @param pos Die Position, die überprüft werden soll - /// @param player_has_key If the player has at least one key - /// @return Ob die Position begehbar ist - bool is_pos_free(const Vector2d& pos, const bool& player_has_key) const; + /// Kontrolliere, ob der Spieler am Ziel ist + /// @param player Der Spieler + /// @return Ob der Spieler am Ziel ist + bool is_player_at_goal(const Player &player) const; - /// Zeige das Spielfeld in der Konsole an - /// @param player Der Spieler - /// @param entities Die Entities auf dem Spielfeld - /// @param infomode_enabled Ob der Infomode aktiv ist - void render(const Player& player, const vector& entities, const bool& infomode_enabled); + /// Kontrolliere, ob eine bestimmte Position begehbar ist + /// @param pos Die Position, die überprüft werden soll + /// @param player_has_key If the player has at least one key + /// @return Ob die Position begehbar ist + bool is_pos_free(const Vector2d &pos, const bool &player_has_key) const; - /// Kriege den Wert einer Position - /// @param pos Die gewollte Position - /// @return Der Wert der Position - char get_field(const Vector2d& pos) const; + /// Zeige das Spielfeld in der Konsole an + /// @param player Der Spieler + /// @param entities Die Entities auf dem Spielfeld + /// @param infomode_enabled Ob der Infomode aktiv ist + void render(const Player &player, const vector &entities, const bool &infomode_enabled); - /// Ersetze den Wert von einer Position - /// @param pos Die Position die ersetzt werden soll - /// @param target Der Wert, auf den die Position gesetzt werden soll - void update_field(const Vector2d& pos, const char& target); + /// Kriege den Wert einer Position + /// @param pos Die gewollte Position + /// @return Der Wert der Position + char get_field(const Vector2d &pos) const; - /// Kriege die Startposition des Spielers - /// @return Die Startposition des Spielers - Vector2d get_player_start_position() const; + /// Ersetze den Wert von einer Position + /// @param pos Die Position die ersetzt werden soll + /// @param target Der Wert, auf den die Position gesetzt werden soll + void update_field(const Vector2d &pos, const char &target); - /// Berrechne den Abstand zwischen zwei Vektoren - /// @return Der Abstand als Differenzvektor - Vector2d get_delta_vector(const Vector2d& pos1, const Vector2d& pos2) const; + /// Kriege die Startposition des Spielers + /// @return Die Startposition des Spielers + Vector2d get_player_start_position() const; - /// Berechne wie viele Schritte benötigt werden, um das Labyrinth zu schaffen - /// @warning Steps nicht zu groß setzen! Diese Funktion ist 4-fach rekursiv! - /// @param position Die Startposition - /// @param steps Wie viele Schritte maximal gegangen werden sollten - /// @returns Wie viele Schritte benötigt werden - int calculate_steps_until_win(Vector2d position, const int& steps); + /// Berrechne den Abstand zwischen zwei Vektoren + /// @return Der Abstand als Differenzvektor + Vector2d get_delta_vector(const Vector2d &pos1, const Vector2d &pos2) const; - /// Kriege alle eingelesenen Entities - vector get_entities(); - }; -} // game + /// Berechne wie viele Schritte benötigt werden, um das Labyrinth zu schaffen + /// @warning Steps nicht zu groß setzen! Diese Funktion ist 4-fach rekursiv! + /// @param position Die Startposition + /// @param steps Wie viele Schritte maximal gegangen werden sollten + /// @returns Wie viele Schritte benötigt werden + int calculate_steps_until_win(Vector2d position, const int &steps); -#endif //MAZE_H + /// Kriege alle eingelesenen Entities + vector get_entities(); + /// Lese ein Labyrinth aus der Konsole + /// @return Das Labyrinth + /// @throws runtime_exception Falls die Eingabe nicht korrekt verlaufen ist. + static Maze request_maze_from_user(); + + private: + /// Lese eine bestimmte Anzahl an Nummern aus der Konsole + /// @param amount_of_numbers Wie viele Nummern eingelesen werden sollen + /// @return Die eingelesenen Nummern + static vector request_numbers_from_user(const int &amount_of_numbers); + + /// Kontrolliere, ob ein Zeichen im Labyrinth vorkommen darf + /// @param target Das Zeichen, welches Kontrolliert werden soll + /// @return Ob das gegebene Zeichen in einem Labyrinth vorkommen darf + static bool validate_maze_element(const char &target); + + /// Ob der angegebene char in valider Geist ist + /// @param target Der zu kontrollierende Wert + /// @returns Ob der Wert ein Valider Geist ist + static bool is_valid_enemy(const char &target); + }; +} // namespace game + +#endif // MAZE_H diff --git a/src/Util/MazeParser.cpp b/src/Util/MazeParser.cpp deleted file mode 100644 index 9fb1876..0000000 --- a/src/Util/MazeParser.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "MazeParser.h" -#include "../Environment/Maze.h" -#include "../Exceptions/MalformedMaze.h" -#include "../Entities/Entity.h" - -using game_exceptions::MalformedMaze; -using game::Entity; - -namespace game -{ - vector MazeParser::request_numbers_from_user(const int& amount_of_numbers) - { - int input; - vector list; - - for (int i = 0; i < amount_of_numbers; ++i) - { - cin >> input; - if (!cin) - throw MalformedMaze("Cin failed while reading numbers!"); - - if (input > MAX_MAZE_SIZE) - throw MalformedMaze("This maze is too big"); - list.push_back(input); - } - - return list; - } - - bool MazeParser::validate_maze_element(const char& target) - { - for (const char c : valid_maze_elements) - if (c == target) - return true; - return false; - } - - bool MazeParser::is_valid_enemy(const char& target) { - for (const char c : valid_enemies) - if (c == target) - return true; - return false; - } - - Maze MazeParser::request_maze_from_user() - { - vector maze_size = request_numbers_from_user(2); - - char input; - vector> field; - vector enemies; - - for (int y = 0; y < maze_size[0]; ++y) - { - vector row; - for (int x = 0; x < maze_size[1]; ++x) - { - cin >> input; - if (!cin) - throw MalformedMaze("Cin failed while reading chars!"); - - // I don't think that this is needed. I doubt that they test the check for this one ~Eric - // if (input == 'q') - // throw ExitGame("Schoenen Tag noch!"); - - if (!validate_maze_element(input)) - throw MalformedMaze("The given input is not a valid element of a maze!"); - if (is_valid_enemy(input)) - { - enemies.push_back(Entity({x, y}, input)); - row.push_back('.'); - } - else { - row.push_back(input); - } - } - - field.push_back(row); - } - - vector player_start_pos = request_numbers_from_user(2); - - return {field, player_start_pos, enemies}; - } // Beispieleingabe: `4 3 #.# #.K #T# #Z# 0 1` -} // game diff --git a/src/Util/MazeParser.h b/src/Util/MazeParser.h deleted file mode 100644 index 3de7fe0..0000000 --- a/src/Util/MazeParser.h +++ /dev/null @@ -1,54 +0,0 @@ -#include "../std_lib_inc.h" - -#ifndef MAZEPARSER_H -#define MAZEPARSER_H - -/* Legende - * S - Spieler - * Z - Ziel - * . - Leerer Raum (begehbar) - * # - Wand - * A - Animaltronic - * K - Schlüssel - * T - Tür - * B - Bowie - * C - Connellys - */ -namespace game -{ - /// Erlaubte Zeichen in einem Labyrinth - /// Ist eine Konstante, darf also in global scope - static const vector valid_maze_elements = {'Z', '.', '#', 'A', 'K', 'T', 'B', 'C'}; - /// Welche Geistertypen es gibt - static const vector valid_enemies = {'A', 'B', 'C'}; - /// Die Maximale Labyrinthgröße - static constexpr int MAX_MAZE_SIZE = 20; - - class Maze; - class MazeParser - { - private: - /// Lese eine bestimmte Anzahl an Nummern aus der Konsole - /// @param amount_of_numbers Wie viele Nummern eingelesen werden sollen - /// @return Die eingelesenen Nummern - static vector request_numbers_from_user(const int& amount_of_numbers); - - /// Kontrolliere, ob ein Zeichen im Labyrinth vorkommen darf - /// @param target Das Zeichen, welches Kontrolliert werden soll - /// @return Ob das gegebene Zeichen in einem Labyrinth vorkommen darf - static bool validate_maze_element(const char& target); - - /// Ob der angegebene char in valider Geist ist - /// @param target Der zu kontrollierende Wert - /// @returns Ob der Wert ein Valider Geist ist - static bool is_valid_enemy(const char& target); - - public: - /// Lese ein Labyrinth aus der Konsole - /// @return Das Labyrinth - /// @throws runtime_exception Falls die Eingabe nicht korrekt verlaufen ist. - static Maze request_maze_from_user(); - }; -} // game - -#endif //MAZEPARSER_H diff --git a/src/main.cpp b/src/main.cpp index aa72ad9..248f273 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,7 +20,7 @@ int main() GameState state = GameState::RUNNING; try { - Maze maze = MazeParser::request_maze_from_user(); + Maze maze = Maze::request_maze_from_user(); Game game = Game(maze);