#include "Maze.h" #include "Entity.h" #include "Player.h" #include "MalformedMaze.h" using game_exceptions::MalformedMaze; 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) { 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 { return this->field[player.get_pos().y][player.get_pos().x] == 'A'; } 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 { 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] == '#') return false; if (field[pos.y][pos.x] == 'T') return player_has_key; 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) { 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) if (e.is_at_position({x, y})) { an_enemy_is_at_this_position = true; cout << e.get_display_character(); } if (!an_enemy_is_at_this_position) cout << field[y][x]; } cout << " "; } 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"; } cout << "\n"; } } 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; } Vector2d Maze::get_player_start_position() const { return this->player_start_position; } 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) { if (!this->is_pos_free(position, false)) return 999; if (this->get_field(position) == 'Z') return 0; if (steps <= 0) return 999; return 1 + std::min({this->calculate_steps_until_win(position.get_new_updated(0, -1), steps - 1), this->calculate_steps_until_win(position.get_new_updated(0, 1), steps - 1), this->calculate_steps_until_win(position.get_new_updated(1, 0), steps - 1), this->calculate_steps_until_win(position.get_new_updated(-1, 0), steps - 1)}); } 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; } 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