#include "std_lib_inc.h" // Ein Programm, welches dir erlaubt ein Labyrinth zu erkunden mit 'w', 'a', 's', und 'd'. // ** KONSTANTEN ** // const vector allowed_symbols_in_maze = {'Z', '.', '#', 'A', 'K', 'T'}; class UnknownAction{}; class MalformedMaze{}; class ExitGame{}; class MovementNotPossible{}; class PositionVector { public: int vec_x; int vec_y; PositionVector(const int x, const int y) { vec_x = x; vec_y = y; } }; class Maze { public: vector> the_maze_vector = {{}}; PositionVector the_player_start_position = {0, 0}; Maze(vector> field, PositionVector player_start_position) { the_maze_vector = field; the_player_start_position = player_start_position; } }; class Player { public: PositionVector the_pos = {0, 1}; int keys = 0; Player(PositionVector pos) { the_pos = pos; keys = 0; } }; class GameState { public: Maze the_maze = {{},{{},{}}}; Player the_player = {{{}, {}}}; GameState(Maze maze, Player player) { the_maze = maze; the_player = player; } }; /// Kontrolliere, ob der Spieler an einem Geist sterben sollte /// @param gs Der Zustand des Spiels /// @return Ob der Spieler sich auf einem Feld mit einem Geist befindet bool was_player_killed_by_ghost(const GameState& gs) { return gs.the_maze.the_maze_vector[gs.the_player.the_pos.vec_y][gs.the_player.the_pos.vec_x] == 'A'; } /// Kontrolliere, ob der Spieler das Ziel erreicht hat /// @param gs Der Zustand des Spiels /// @return Ob der Spieler das Ziel erreicht hat bool has_player_reached_goal(const GameState& gs) { return gs.the_maze.the_maze_vector[gs.the_player.the_pos.vec_y][gs.the_player.the_pos.vec_x] == 'Z'; } /// Zeige dem Nutzer das Spielfeld /// @param gs Der Zustand des Spiels void render_maze(const GameState& gs) { for (int y = 0; y < gs.the_maze.the_maze_vector.size(); ++y) { for (int x = 0; x < gs.the_maze.the_maze_vector[y].size(); ++x) { if (y == gs.the_player.the_pos.vec_y && x == gs.the_player.the_pos.vec_x) cout << "S"; else cout << gs.the_maze.the_maze_vector[y][x]; cout << " "; } cout << "\n"; } } /// Kontrolliere, ob der Spieler eine Position gehen kann /// @param mz Das Labyrinth /// @param pv Die zu überprüfende Position /// @param does_player_have_key Ob der Spieler einen Schlüssel besitzt /// @return Ob der Spieler die Position begehen kann bool is_position_free(const Maze& mz, const PositionVector& pv, const bool& does_player_have_key) { if (pv.vec_x < 0 || pv.vec_y < 0 || pv.vec_y > mz.the_maze_vector.size() - 1 || pv.vec_x > mz.the_maze_vector[pv.vec_y].size() - 1) return false; if (mz.the_maze_vector[pv.vec_y][pv.vec_x] == '#') return false; if (mz.the_maze_vector[pv.vec_y][pv.vec_x] == 'T') return does_player_have_key; return true; } /// Kontrolliere, ob ein gegebenes Symbol im Labyrinth vorkommen darf /// @param symbol Das zu überprüfende Zeichen /// @return Ob das gegebene Symbol in einem Labyrinth vorkommen darf bool is_symbol_valid_maze_element(const char& symbol) { for (char c : allowed_symbols_in_maze) if (c == symbol) return true; return false; } /// Lese beliebig viele Nummern aus der Konsolenausgabe aus /// @param amount_of_numbers_to_read Wie viele Nummern eingelesen werden sollen /// @return Die eingelesenen Nummern /// @throws MalformedMaze Wenn der Nutzer etwas anderes als Zahlen eingibt vector get_numbers_from_user(const int& amount_of_numbers_to_read) { int input; vector numbers_provided_by_user; for (int i = 0; i < amount_of_numbers_to_read; ++i) { cin >> input; if (!cin) throw MalformedMaze(); numbers_provided_by_user.push_back(input); } return numbers_provided_by_user; } /// Lese ein Labyrinth aus /// @param rows Wie viele Reihen das Labyrinth haben soll /// @param columns Wie viele Zeilen das Labyrinth haben soll /// @return Das fertige Labyrinth /// @throw MalformedMaze Wenn ein eingegebenes Symbol kein char ist, oder ein Symbol eingegeben wird, welches nicht in einem Labyrinth erlaubt ist, oder die Dimension des Mazes falsch ist. /// @throw ExitGame Wenn 'q' eingegeben wird vector> get_field_from_user(const int& rows, const int& columns) { if ((rows <= 0 || rows > 20) || (columns <= 0 || columns > 20)) throw MalformedMaze(); char input; vector> maze; for (int current_row = 0; current_row < rows; ++current_row) { vector current_column; for (int element_of_column = 0; element_of_column < columns; ++element_of_column) { cin >> input; if (!cin) throw MalformedMaze(); if (input == 'q') throw ExitGame(); if (!is_symbol_valid_maze_element(input)) throw MalformedMaze(); current_column.push_back(input); } maze.push_back(current_column); } return maze; } /// Lasse den Spieler ein Labyrinth eingeben /// @return Ein vom Spieler eingegebenes Labyrinth Maze get_complete_maze_from_user() { vector maze_dimensions = get_numbers_from_user(2); vector> field = get_field_from_user(maze_dimensions[0], maze_dimensions[1]); vector player_start_position = get_numbers_from_user(2); return Maze(field, PositionVector(player_start_position[1], player_start_position[0])); } /// Lese aus der Eingabe des Spielers, was er machen möchte /// @param input Die Eingabe des Nutzers /// @return Die gewollte Bewegung des Spielers /// @throw ExitGame Wenn der Nutzer 'q' eingegeben hat und das Spiel verlassen möchte /// @throw UnknownAction Wenn der Nutzer einen Befehl eingibt, den das Programm nicht kennt PositionVector handle_user_input(const char& input) { PositionVector movement_vector = PositionVector(0, 0); switch (input) { case 'w': movement_vector.vec_y = -1; break; case 'a': movement_vector.vec_x = -1; break; case 's': movement_vector.vec_y = 1; break; case 'd': movement_vector.vec_x = 1; break; case 'q': throw ExitGame(); case 'h': cout << "Du wurdest von einem Zauberer in ein Labyrinth gesperrt, nachdem du seine Künste beleidigt hast.\n" << "Er laesst dich leben, wenn du es schaffst den Ausgang (Z) zu finden. Solltest du keinen Erfolg haben, laesst er dich verhungern.\n" << "Auf deinem Abenteuer wirst du dabei boesen Geistern (A) begegnen und mit Schluesseln (K) Tueren (T) aufschliessen.\n" << "Bewege dich mit 'w', 'a', 's' und 'd'.\n"; break; default: throw UnknownAction(); } return movement_vector; } /// Bewege den Spieler um den gegebenen Vektor /// @param gs Der Spielzustand /// @param requested_movement Die gewollte Bewegung /// @returns The new GameState /// @throw MovementNotPossible Wenn die Bewegung aus irgendeinem Grund nicht möglich ist GameState move_player(GameState gs, PositionVector requested_movement) { const PositionVector target_position = PositionVector(gs.the_player.the_pos.vec_x + requested_movement.vec_x, gs.the_player.the_pos.vec_y + requested_movement.vec_y); if (is_position_free(gs.the_maze, target_position, gs.the_player.keys > 0)) { gs.the_player.the_pos = target_position; switch (gs.the_maze.the_maze_vector[target_position.vec_y][target_position.vec_x]) { case 'K': ++gs.the_player.keys; gs.the_maze.the_maze_vector[target_position.vec_y][target_position.vec_x] = '.'; break; case 'T': --gs.the_player.keys; gs.the_maze.the_maze_vector[target_position.vec_y][target_position.vec_x] = '.'; break; default: ; } } else throw MovementNotPossible(); return gs; } /// Die Hauptschleife des Spiels. Hier findet die Logik statt /// @param gs Der Spielzustand void game_loop(GameState& gs) { char game_input; while (true) { if (was_player_killed_by_ghost(gs)) { cout << "Sie haben einen Geist getroffen! Game Over!\n"; break; } render_maze(gs); if (has_player_reached_goal(gs)) { cout << "Ziel erreicht! Herzlichen Glueckwunsch!\n"; break; } cin >> game_input; PositionVector movement_vector = PositionVector(0, 0); try { movement_vector = handle_user_input(game_input); gs = move_player(gs, movement_vector); } catch (UnknownAction& _) { cout << "Diese Eingabe kenne ich nicht. Gib 'h' ein, um eine Hilfe zu erhalten." << "\n"; } catch (MovementNotPossible& _) { cout << "Bewegung nicht moeglich!" << "\n"; } } } int main() { try { Maze mz = get_complete_maze_from_user(); Player pl = Player(mz.the_player_start_position); GameState gs = GameState(mz, pl); game_loop(gs); } catch (MalformedMaze& _) { cout << "Fehler beim Einlesen des Labyrinths.\n"; } catch (ExitGame& _) { cout << "Schoenen Tag noch!" << "\n"; } return 0; }