feat: added exception types and game object for handing game state

This commit is contained in:
moonleay 2024-12-17 14:22:03 +01:00
parent 884e72d7b5
commit eda62c7c6d
Signed by: moonleay
GPG key ID: 82667543CCD715FB
10 changed files with 266 additions and 96 deletions

View file

@ -7,13 +7,18 @@ include_directories(.)
add_executable(epr24pr3_ojanssen2 add_executable(epr24pr3_ojanssen2
main.cpp main.cpp
std_lib_inc.h
Player.cpp Player.cpp
Player.h Player.h
PositionVector.cpp PositionVector.cpp
PositionVector.h PositionVector.h
std_lib_inc.h
Maze.h Maze.h
Maze.cpp Maze.cpp
MazeParser.h MazeParser.h
MazeParser.cpp MazeParser.cpp
Game.h
Game.cpp
Exceptions/MovementNotPossible.h
Exceptions/MalformedMaze.h
Exceptions/UnkownAction.h
) )

View file

@ -0,0 +1,26 @@
//
// Created by moonleay on 12/17/24.
//
#ifndef MALFORMEDMAZE_H
#define MALFORMEDMAZE_H
namespace game_exceptions
{
class MalformedMaze
{
string why;
public:
MalformedMaze(string why): why(why)
{
}
string what()
{
return this->why;
}
};
} // game_exceptions
#endif //MALFORMEDMAZE_H

View file

@ -0,0 +1,26 @@
//
// Created by moonleay on 12/17/24.
//
#ifndef MOVEMENTNOTPOSSIBLE_H
#define MOVEMENTNOTPOSSIBLE_H
namespace game_exceptions
{
class MovementNotPossible
{
string why;
public:
MovementNotPossible(string why): why(why)
{
}
string what()
{
return this->why;
}
};
} // game_exceptions
#endif //MOVEMENTNOTPOSSIBLE_H

26
Exceptions/UnkownAction.h Normal file
View file

@ -0,0 +1,26 @@
//
// Created by moonleay on 12/17/24.
//
#ifndef UNKOWNACTION_H
#define UNKOWNACTION_H
namespace game_exceptions
{
class UnkownAction
{
string why;
public:
UnkownAction(string why): why(why)
{
}
string what()
{
return this->why;
}
};
} // game_exceptions
#endif //UNKOWNACTION_H

122
Game.cpp Normal file
View file

@ -0,0 +1,122 @@
//
// Created by moonleay on 12/17/24.
//
#include "Game.h"
#include "MazeParser.h"
#include "Player.h"
#include "Maze.h"
#include "Exceptions/MovementNotPossible.h"
#include "Exceptions/UnkownAction.h"
using game::Player;
using game::Maze;
using game_exceptions::UnkownAction;
using game_exceptions::MovementNotPossible;
namespace game // Namespace = Scope with name and no features
{
Game::Game(): maze({}, {}), player(0, 0)
{
// Lese das Labyrinth ein
maze = MazeParser::request_maze_from_user();
// Lese die Startpositon des Spielers aus dem eingelesenen Labyrinth aus
vector<int> player_start_position = maze.get_player_start_position();
// Überschreibe den Spieler mit der gegebenen Startposition
this->player = Player(player_start_position[1], player_start_position[0]);
}
PositionVector Game::handle_user_input(char input)
{
// Erstelle einen Vector mit einer Bewegung von 0 und 0
PositionVector movement_vector = PositionVector(0, 0);
// Kontrolliere, was der Spieler machen möchte. Speichere die erforderte Bewegung im Bewegungsvektor.
// Schreibe nachrichten in die Konsole,
// wenn nach Hilfe gefragt wird oder eine unbekannte Eingabe eingegeben wurde
switch (input)
{
case 'w':
movement_vector.update(0, -1);
break;
case 'a':
movement_vector.update(-1, 0);
break;
case 's':
movement_vector.update(0, 1);
break;
case 'd':
movement_vector.update(1, 0);
break;
case 'h':
// Schreibe hilfsreiche Tipps in die Konsole
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:
// Die gewollte Aktion kenne ich nicht. Melde Fehler dem Nutzer
throw UnkownAction("Diese Eingabe kenne ich nicht. Gib 'h' ein, um eine Hilfe zu erhalten.");
}
return movement_vector;
}
void Game::run_game()
{
// Erstelle eine Variable für den Input
char game_input;
// Durchlaufe die Hauptschleife des Spiels
while (true)
{
// Zeige dem Spieler das Spielfeld
maze.render(player);
// Kontrolliere, ob der Spieler an einem Geist gestorben ist
if (maze.was_player_killed_by_ghost(player))
{
cout << "Sie haben einen Geist getroffen! Game Over!\n";
break;
}
// Kontrolliere, ob der Spieler schon das Ziel erreicht hat
if (maze.is_player_at_goal(player))
{
// Ziel erreicht! Herzlichen Glückwunsch!
cout << "Ziel erreicht! Herzlichen Glueckwunsch!\n";
break;
}
// Lese Eingabe des Spielers
cin >> game_input;
PositionVector movement_vector = PositionVector(0, 0);
try
{
movement_vector = handle_user_input(game_input);
} catch (UnkownAction& err)
{
cout << err.what() << "\n";
}
// Kontrolliere gewollte Bewegung und setze sie um.
try
{
maze = player.move(maze, movement_vector);
}
catch (MovementNotPossible& err)
{
// Diese Bewegung ist nicht möglich!
// Gebe aus, warum.
cout << err.what() << "\n";
}
}
}
} // game

33
Game.h Normal file
View file

@ -0,0 +1,33 @@
//
// Created by moonleay on 12/17/24.
//
#include "Maze.h"
#include "Player.h"
#ifndef GAME_H
#define GAME_H
namespace game
{
/// Eine Instanz des Spiels
class Game
{
private:
Maze maze;
Player player;
public:
Game();
/// Bearbeite die Eingabe des Spielers
/// @param input Die Eingabe des Nutzers
/// @return Der Bewegungsvektor, um den sich den Spieler bewegen möchte
/// @throws UnkownAction Wenn die Eingabe des Spielers unbekannt ist
static PositionVector handle_user_input(char input);
/// Starte das Spiel
void run_game();
};
} // game
#endif //GAME_H

4
Maze.h
View file

@ -25,10 +25,6 @@ namespace game
/// Das Spielfeld /// Das Spielfeld
Maze(vector<vector<char>> play_field, vector<int> player_start_position); Maze(vector<vector<char>> play_field, vector<int> player_start_position);
/// Ein Standard Konstruktor
/// Variablen innerhalb der Klasse bleiben leer
Maze() = default;
/// Kontrolliere, ob der Spieler stirbt /// Kontrolliere, ob der Spieler stirbt
/// @param player Der Spieler /// @param player Der Spieler
/// @return Ob der Spieler tot ist /// @return Ob der Spieler tot ist

View file

@ -4,6 +4,10 @@
#include "MazeParser.h" #include "MazeParser.h"
#include "Exceptions/MalformedMaze.h"
using game_exceptions::MalformedMaze;
namespace game namespace game
{ {
vector<int> MazeParser::request_numbers_from_user(const int amount_of_numbers) vector<int> MazeParser::request_numbers_from_user(const int amount_of_numbers)
@ -22,7 +26,7 @@ namespace game
// Sollte etwas schiefgelaufen sein, dann wirf eine Exception // Sollte etwas schiefgelaufen sein, dann wirf eine Exception
if (!cin) if (!cin)
throw runtime_error("Cin failed while reading numbers!"); throw MalformedMaze("Cin failed while reading numbers!");
// Schreibe die gelesene Zahl auf die Liste // Schreibe die gelesene Zahl auf die Liste
list.push_back(input); list.push_back(input);
@ -68,11 +72,11 @@ namespace game
// Werfe eine Exception, wenn der Input nicht lesbar ist, d.h. Nutzer hat eine Falsch eingabe getätigt. // Werfe eine Exception, wenn der Input nicht lesbar ist, d.h. Nutzer hat eine Falsch eingabe getätigt.
if (!cin) if (!cin)
throw runtime_error("Cin failed while reading chars!"); throw MalformedMaze("Cin failed while reading chars!");
// Kontrolliere, ob das Element in einem Labyrinth vorkommen darf // Kontrolliere, ob das Element in einem Labyrinth vorkommen darf
if (!is_valid_maze_element(input)) if (!is_valid_maze_element(input))
throw runtime_error("The given input is not a valid element of a maze!"); throw MalformedMaze("The given input is not a valid element of a maze!");
// Schreibe den eingelesenen Wert in die aktuelle Reihe // Schreibe den eingelesenen Wert in die aktuelle Reihe
row.push_back(input); row.push_back(input);

View file

@ -5,6 +5,9 @@
#include "std_lib_inc.h" #include "std_lib_inc.h"
#include "Player.h" #include "Player.h"
#include "Maze.h" #include "Maze.h"
#include "Exceptions/MovementNotPossible.h"
using game_exceptions::MovementNotPossible;
namespace game namespace game
{ {
@ -55,7 +58,7 @@ namespace game
} }
} }
else else
throw runtime_error("Bewegung nicht moeglich!"); throw MovementNotPossible("Bewegung nicht moeglich!");
return maze; return maze;
} }

103
main.cpp
View file

@ -1,113 +1,42 @@
#include "Maze.h"
#include "std_lib_inc.h" #include "std_lib_inc.h"
#include "Player.h" #include "Maze.h"
#include "PositionVector.h" #include "PositionVector.h"
#include "MazeParser.h" #include "MazeParser.h"
#include "Game.h"
#include "Exceptions/MalformedMaze.h"
#include "Exceptions/MovementNotPossible.h"
#include "Exceptions/UnkownAction.h"
using game::Player; using game::Player;
using game::PositionVector; using game::PositionVector;
using game::Maze; using game::Maze;
using game::MazeParser; using game::MazeParser;
using game::Game;
using game_exceptions::MalformedMaze;
using game_exceptions::UnkownAction;
using game_exceptions::MovementNotPossible;
// Ein Programm, welches dir erlaubt ein Labyrinth zu erkunden mit 'w', 'a', 's', und 'd'. // Ein Programm, welches dir erlaubt ein Labyrinth zu erkunden mit 'w', 'a', 's', und 'd'.
const vector<int> player_start_position = {4, 0};
int main() int main()
{ {
// Erstelle eine Variable, in der wir das eingelesene Labyrinth speichern
Maze maze;
try try
{ {
// Lese das Labyrinth ein // Erstelle eine Variable, in der wir das eingelesene Labyrinth speichern
maze = MazeParser::request_maze_from_user(); Game game = Game();
// Starte das Spiel
game.run_game();
} }
catch (...) catch (MalformedMaze& _)
{ {
// Das Labyrinth einlesen hat nicht geklappt. Gebe Fehlermeldung aus und beende das Programm. // Das Labyrinth einlesen hat nicht geklappt. Gebe Fehlermeldung aus und beende das Programm.
cout << "Fehler beim Einlesen des Labyrinths.\n"; cout << "Fehler beim Einlesen des Labyrinths.\n";
return 0; return 0;
} }
// Lese die Startpositon des Spielers aus dem eingelesenen Labyrinth aus
vector<int> player_start_position = maze.get_player_start_position();
// Erstelle einen Spieler mit der gegebenen start position
Player player = Player(player_start_position[1], player_start_position[0]);
// Erstelle eine Variable für den Input
char game_input;
// Durchlaufe die Hauptschleife des Spiels
while (true)
{
// Zeige dem Spieler das Spielfeld
maze.render(player);
// Kontrolliere, ob der Spieler an einem Geist gestorben ist
if (maze.was_player_killed_by_ghost(player))
{
cout << "Sie haben einen Geist getroffen! Game Over!\n";
break;
}
// Kontrolliere, ob der Spieler schon das Ziel erreicht hat
if (maze.is_player_at_goal(player))
{
// Ziel erreicht! Herzlichen Glückwunsch!
cout << "Ziel erreicht! Herzlichen Glueckwunsch!\n";
break;
}
// Lese Eingabe des Spielers
cin >> game_input;
// Erstelle einen Vector mit einer Bewegung von 0 und 0
PositionVector movement_vector = PositionVector(0, 0);
// Kontrolliere, was der Spieler machen möchte. Speichere die erforderte Bewegung im Bewegungsvektor.
// Schreibe nachrichten in die Konsole,
// wenn nach Hilfe gefragt wird oder eine unbekannte Eingabe eingegeben wurde
switch (game_input)
{
case 'w':
movement_vector.update(0, -1);
break;
case 'a':
movement_vector.update(-1, 0);
break;
case 's':
movement_vector.update(0, 1);
break;
case 'd':
movement_vector.update(1, 0);
break;
case 'h':
// Schreibe hilfsreiche Tipps in die Konsole
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:
// Die gewollte Aktion kenne ich nicht. Schreibe eine Fehlernachricht in die Konsole
cout << "Diese Eingabe kenne ich nicht. Gib 'h' ein, um eine Hilfe zu erhalten.\n";
break;
}
// Kontrolliere gewollte Bewegung und setze sie um.
try
{
maze = player.move(maze, movement_vector);
}
catch (runtime_error& err)
{
// Diese Bewegung ist nicht möglich!
// Gebe aus, warum.
cout << err.what() << "\n";
}
}
// Beende das Programm // Beende das Programm
return 0; return 0;
} }