feat!: reworked former project to use classes, structs and multiple files
This commit is contained in:
parent
6889d79ae8
commit
7c116c8cfc
9 changed files with 314 additions and 189 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -9,3 +9,5 @@
|
|||
!.gitattributes
|
||||
|
||||
!*/
|
||||
|
||||
cmake-build-debug/
|
||||
|
|
17
CMakeLists.txt
Normal file
17
CMakeLists.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
cmake_minimum_required(VERSION 3.30)
|
||||
project(epr24pr3_ojanssen2)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
|
||||
include_directories(.)
|
||||
|
||||
add_executable(epr24pr3_ojanssen2
|
||||
main.cpp
|
||||
Player.cpp
|
||||
Player.h
|
||||
PositionVector.cpp
|
||||
PositionVector.h
|
||||
std_lib_inc.h
|
||||
Maze.h
|
||||
Maze.cpp
|
||||
)
|
45
Maze.cpp
Normal file
45
Maze.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// Created by moonleay on 12/13/24.
|
||||
//
|
||||
|
||||
#include "Maze.h"
|
||||
|
||||
namespace game
|
||||
{
|
||||
Maze::Maze()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool Maze::is_player_at_goal(const PositionVector pos) const
|
||||
{
|
||||
return this->field[pos.y][pos.x] == 'Z';
|
||||
}
|
||||
|
||||
bool Maze::is_pos_free(const PositionVector pos) const
|
||||
{
|
||||
if (pos.x < 0 || pos.y < 0 || pos.y > field.size() - 1 || pos.x > field[pos.y].size() - 1)
|
||||
return false; // Zielposition ist außerhalb des Spielfelds
|
||||
if (field[pos.y][pos.x] == '#')
|
||||
return false; // Zielposition ist eine Wand
|
||||
return true; // Zielposition ist betretbar (ist keine Wand und auch nicht außerhalb des Spielfeldes)
|
||||
}
|
||||
|
||||
void Maze::render(const PositionVector pos) const
|
||||
{
|
||||
for (int y = 0; y < field.size(); ++y)
|
||||
{
|
||||
// Für jede Reihe ...
|
||||
for (int x = 0; x < field[y].size(); ++x)
|
||||
{
|
||||
// ... schreibe für jedes Element ...
|
||||
if (y == pos.y && x == pos.x)
|
||||
cout << "S"; // ... 'S' wenn der aktuelle Eintrag die Position des Spielers ist
|
||||
else // sonst
|
||||
cout << field[y][x]; // ... den tatsächlichen Eintrag
|
||||
cout << " "; // Füge ein Leerzeichen zwischen den Einträgen hinzu
|
||||
}
|
||||
cout << "\n"; // Beende die Reihe mit einem Zeilenumbruch
|
||||
}
|
||||
}
|
||||
} // game
|
50
Maze.h
Normal file
50
Maze.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// Created by moonleay on 12/13/24.
|
||||
//
|
||||
#include "std_lib_inc.h"
|
||||
#include "PositionVector.h"
|
||||
|
||||
#ifndef MAZE_H
|
||||
#define MAZE_H
|
||||
|
||||
namespace game
|
||||
{
|
||||
class Maze
|
||||
{ // class -> members private by default
|
||||
/// Das Spielfeld
|
||||
vector<vector<char>> field = {
|
||||
{'#', '.', '.', '.', '.'},
|
||||
{'#', '.', '#', '.', '.'},
|
||||
{'.', 'Z', '#', '.', '.'},
|
||||
{'.', '#', '#', '#', '.'},
|
||||
{'.', '.', '.', '.', '.'}
|
||||
// ^ Spieler startet hier (4,0)
|
||||
};
|
||||
/* Legende
|
||||
* S - Spieler
|
||||
* Z - Ziel
|
||||
* . - Leerer Raum (begehbar)
|
||||
* # - Wand
|
||||
*/
|
||||
|
||||
public:
|
||||
/// Das Spielfeld
|
||||
Maze();
|
||||
|
||||
/// Kontrolliere, ob der Spieler am Ziel ist
|
||||
/// @param pos Die Position des Spielers
|
||||
/// @return Ob der Spieler am Ziel ist
|
||||
bool is_player_at_goal(PositionVector pos) const;
|
||||
|
||||
/// Kontrolliere, ob eine bestimmte Position begehbar ist
|
||||
/// @param pos Die Position, die überprüft werden soll
|
||||
/// @return Ob die Position begehbar ist
|
||||
bool is_pos_free(PositionVector pos) const;
|
||||
|
||||
/// Zeige das Spielfeld in der Konsole an
|
||||
/// @param pos Die Position des Spielers
|
||||
void render(PositionVector pos) const;
|
||||
};
|
||||
} // game
|
||||
|
||||
#endif //MAZE_H
|
39
Player.cpp
Normal file
39
Player.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// Created by moonleay on 12/12/24.
|
||||
//
|
||||
|
||||
#include "std_lib_inc.h"
|
||||
#include "Player.h"
|
||||
#include "Maze.h"
|
||||
|
||||
namespace game
|
||||
{
|
||||
Player::Player(const int target_x, const int target_y): pos(target_x, target_y)
|
||||
{
|
||||
// Wir brauchen keinen Inhalt in diesem Konstruktor, da wir nur die position speichern müssen
|
||||
}
|
||||
|
||||
PositionVector Player::get_pos() const
|
||||
{
|
||||
return this->pos;
|
||||
}
|
||||
|
||||
void Player::update_position(const PositionVector target)
|
||||
{
|
||||
this->pos = target;
|
||||
}
|
||||
|
||||
|
||||
void Player::move(Maze maze, const PositionVector move_vector)
|
||||
{
|
||||
// Berechne die Position, zu der der Spieler sich bewegen möchte
|
||||
const PositionVector target_position = PositionVector(this->get_pos().x + move_vector.x,
|
||||
this->get_pos().y + move_vector.y);
|
||||
|
||||
// Bewege den Spieler zu der gewollten Position, wenn diese frei ist
|
||||
if (maze.is_pos_free(target_position))
|
||||
this->update_position(target_position);
|
||||
else
|
||||
cout << "Bewegung nicht moeglich!\n";
|
||||
}
|
||||
} // game
|
42
Player.h
Normal file
42
Player.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// Created by moonleay on 12/12/24.
|
||||
//
|
||||
#include "PositionVector.h"
|
||||
#include "Maze.h"
|
||||
|
||||
#ifndef PLAYER_H
|
||||
#define PLAYER_H
|
||||
|
||||
namespace game
|
||||
{
|
||||
/// Ein Spieler.
|
||||
/// Besitzt einen veränderbaren Positionsvektor
|
||||
class Player
|
||||
{
|
||||
/// Die Position des Spielers
|
||||
PositionVector pos;
|
||||
|
||||
public:
|
||||
/// Ein Spieler.
|
||||
/// Besitzt einen veränderbaren Positionsvektor
|
||||
/// @param target_x Die Startposition des Spielers (X-Koordinate)
|
||||
/// @param target_y Die Startposition des Spielers (Y-Koordinate)
|
||||
Player(int target_x, int target_y);
|
||||
|
||||
/// Kriege die Position des Spielers
|
||||
/// @return Die Position des Spielers
|
||||
PositionVector get_pos() const;
|
||||
|
||||
/// Aktuallisiere die Position des Spielers ohne weitere Checks
|
||||
/// @param target Das ziel
|
||||
void update_position(PositionVector target);
|
||||
|
||||
/// Bewege den Splieler um den Bewegungsvektor, insofern die Zielposition begehbar ist
|
||||
/// @param maze Das Maze
|
||||
/// @param move_vector Die gewollte Bewegung
|
||||
/// @return Die neue Position des Spielers
|
||||
void move(Maze maze, PositionVector move_vector);
|
||||
};
|
||||
} // maze
|
||||
|
||||
#endif //PLAYER_H
|
20
PositionVector.cpp
Normal file
20
PositionVector.cpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// Created by moonleay on 12/12/24.
|
||||
//
|
||||
|
||||
#include "PositionVector.h"
|
||||
|
||||
namespace game
|
||||
{
|
||||
PositionVector::PositionVector(const int x, const int y)
|
||||
{
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
}
|
||||
|
||||
void PositionVector::update(const int x, const int y)
|
||||
{
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
}
|
||||
} // game
|
31
PositionVector.h
Normal file
31
PositionVector.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// Created by moonleay on 12/12/24.
|
||||
//
|
||||
|
||||
#ifndef POSITION_H
|
||||
#define POSITION_H
|
||||
|
||||
namespace game
|
||||
{
|
||||
/// Ein Vector aus zwei zahlen.
|
||||
/// Kann eine Position oder eine Differenz zwischen zwei Positionen darstellen.
|
||||
struct PositionVector
|
||||
{ // struct -> members public by default
|
||||
// Die beiden Variablen des Vectors
|
||||
int x;
|
||||
int y;
|
||||
|
||||
/// Ein Vector aus zwei zahlen.
|
||||
/// Kann eine Position oder eine Differenz zwischen zwei Positionen darstellen.
|
||||
/// @param x Die 'X'-Koordinate
|
||||
/// @param y Die 'Y'-Koordinate
|
||||
PositionVector(int x, int y);
|
||||
|
||||
/// Aktualisiere die Werte des Vectors
|
||||
/// @param x Die neue 'X'-Koordinate
|
||||
/// @param y Die neue 'Y'-Koordinate
|
||||
void update(int x, int y);
|
||||
};
|
||||
} // game
|
||||
|
||||
#endif //POSITION_H
|
257
main.cpp
257
main.cpp
|
@ -1,197 +1,76 @@
|
|||
// Ein Labyrinth-Spiel
|
||||
// Autor: Fritz Bökler
|
||||
// Datum 20.11.2024
|
||||
// MIT Lizenz
|
||||
//
|
||||
// Labyrinth wird in der Konsole ausgegeben.
|
||||
// . Leeres Feld
|
||||
// # Wand (nicht betretbar)
|
||||
// Z Ziel
|
||||
// S SpielerIn (wird nicht im Labyrinth gespeichert)
|
||||
//
|
||||
// Ziel des Spiels ist, das Ziel-Feld zu erreichen.
|
||||
// Eingabe erfolgt zeilengepuffert über cin.
|
||||
|
||||
#include "std_lib_inc.h"
|
||||
#include "Player.h"
|
||||
#include "PositionVector.h"
|
||||
// #include "Maze.h"
|
||||
// Muss nicht inkludiert werden, da es schon in Player.h inkludiert wird
|
||||
|
||||
// Globale Labyrinth-Definition als konstanter Ausdruck
|
||||
constexpr int kRows = 5;
|
||||
constexpr int kCols = 5;
|
||||
using game::Player;
|
||||
using game::PositionVector;
|
||||
using game::Maze;
|
||||
|
||||
// Labyrinth-Daten
|
||||
// Interpretiere als Zeilen, dann Spalten
|
||||
const vector<vector<char>> kMaze = {
|
||||
{'#', '.', '.', '.', '.'},
|
||||
{'#', '.', '#', '.', '.'},
|
||||
{'.', 'Z', '#', '.', '.'},
|
||||
{'.', '#', '#', '#', '.'},
|
||||
{'.', '.', '.', '.', '.'},
|
||||
};
|
||||
// Ein Programm, welches dir erlaubt ein Labyrinth zu erkunden mit 'w', 'a', 's', und 'd'.
|
||||
const vector<int> player_start_position = {4, 0};
|
||||
|
||||
const vector<int> kPlayerStartPosition = {4, 0};
|
||||
|
||||
// Funktion zur Anzeige des Labyrinths
|
||||
// player_position: Position der SpielerIn im Labyrinth
|
||||
void display_maze(vector<int> player_position)
|
||||
{
|
||||
int player_row = player_position[0];
|
||||
int player_col = player_position[1];
|
||||
|
||||
for(int i = 0; i < kRows; i++)
|
||||
{
|
||||
for(int j = 0; j < kCols; j++)
|
||||
{
|
||||
if(i == player_row && j == player_col)
|
||||
{
|
||||
cout << 'S';
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << kMaze[i][j];
|
||||
}
|
||||
cout << " ";
|
||||
}
|
||||
cout << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
// Funktion zur Umrechnung eines Kommandos zu einer neuen Position
|
||||
// player_position: Position der SpielerIn im Labyrinth
|
||||
// direction: Richtungskommando
|
||||
// Rückgabe: Die neue SpielerInnenposition
|
||||
// Vorbedingung: direction muss aus {w, s, a, d} kommen.
|
||||
vector<int> new_position_by_direction(vector<int> player_position, char direction)
|
||||
{
|
||||
int row = player_position[0];
|
||||
int col = player_position[1];
|
||||
|
||||
assert(direction == 'w' || direction == 's' || direction == 'a' || direction == 'd',
|
||||
"new_position_by_direction: invalid direction. Must be from {w, s, a, d}.");
|
||||
|
||||
switch(direction)
|
||||
{
|
||||
case 'w':
|
||||
return {row - 1, col};
|
||||
case 's':
|
||||
return {row + 1, col};
|
||||
case 'a':
|
||||
return {row, col - 1};
|
||||
case 'd':
|
||||
return {row, col + 1};
|
||||
}
|
||||
}
|
||||
|
||||
// Gibt true zurueck gdw. die Position position begehbar ist
|
||||
// position: Zu testende Position
|
||||
// Rückgabe: true gdw. die Position begehbar ist
|
||||
bool position_is_valid(vector<int> position)
|
||||
{
|
||||
const int row = position[0];
|
||||
const int col = position[1];
|
||||
|
||||
bool outside_playfield = row < 0 || col < 0 || row >= kRows || col >= kCols;
|
||||
|
||||
if(outside_playfield) // Erst prüfen, bevor Vector-Zugriff
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return kMaze[row][col] != '#';
|
||||
}
|
||||
|
||||
// Funktion zur Bewegung des Spielers
|
||||
// player_position: Position der SpielerIn vor der Bewegung
|
||||
// direction: Richtungskommando
|
||||
// Rückgabe: Die neue SpielerInnenposition der SpielerIn
|
||||
vector<int> move_player(vector<int> player_position, char direction)
|
||||
{
|
||||
vector<int> potential_new_position = new_position_by_direction(player_position, direction);
|
||||
|
||||
if(position_is_valid(potential_new_position))
|
||||
{
|
||||
return potential_new_position;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Bewegung nicht moeglich!\n";
|
||||
return player_position;
|
||||
}
|
||||
}
|
||||
|
||||
// Gibt eine kurze Hilfe aus
|
||||
void display_help()
|
||||
{
|
||||
cout << "Willkommen zum Labyrinth-Spiel!\n";
|
||||
cout << "Ziel des Spiels: Finde den Weg vom Startpunkt (S) zum Ziel (Z).\n";
|
||||
cout << "Spielfeld-Erklaerung:\n";
|
||||
cout << "S - Startpunkt: Hier beginnt der Spieler.\n";
|
||||
cout << "Z - Ziel: Erreiche diesen Punkt, um das Spiel zu gewinnen.\n";
|
||||
cout << "# - Wand: Diese Felder sind nicht begehbar.\n";
|
||||
cout << ". - Leeres Feld: Diese Felder koennen betreten werden.\n";
|
||||
cout << "\nSteuerung:\n";
|
||||
cout << "w - Nach oben bewegen\n";
|
||||
cout << "a - Nach links bewegen\n";
|
||||
cout << "s - Nach unten bewegen\n";
|
||||
cout << "d - Nach rechts bewegen\n";
|
||||
cout << "Nach jeder Befehlseingabe muss die Eingabetaste (Enter) gedrueckt werden, um sich zu bewegen.\n";
|
||||
cout << "\nViel Erfolg im Labyrinth!\n";
|
||||
}
|
||||
|
||||
// Reagiert auf das eingegebene Kommando und gibt an die jeweilige Funktion
|
||||
// ab, die sich um genau dieses Kommando kuemmert.
|
||||
// player_position: die aktuelle SpielerInnenposition
|
||||
// input: Ein Eingabezeichen
|
||||
// Rückgabe: Die neue SpielerInnenposition, falls sie sich aendert
|
||||
vector<int> process_input(vector<int> player_position, char input)
|
||||
{
|
||||
switch(input)
|
||||
{
|
||||
case 'w': case 's': case 'a': case 'd':
|
||||
return move_player(player_position, input);
|
||||
case 'h':
|
||||
display_help();
|
||||
break;
|
||||
default:
|
||||
cout << "Diese Eingabe kenne ich nicht. Gib 'h' ein, um eine Hilfe zu erhalten.\n";
|
||||
break;
|
||||
}
|
||||
return player_position;
|
||||
}
|
||||
|
||||
// Gibt true zurueck, wenn das Ziel erreicht wurde
|
||||
// player_position: Die aktuelle SpielerInnenposition
|
||||
// Rückgabe: true gdw. das Ziel erreicht wurde
|
||||
bool reached_goal(vector<int> player_position)
|
||||
{
|
||||
return kMaze[player_position[0]][player_position[1]] == 'Z';
|
||||
}
|
||||
|
||||
// Die Hauptschleife des Spiels
|
||||
// player_position: Die aktuelle SpielerInnenposition
|
||||
void game_loop(vector<int> player_position)
|
||||
{
|
||||
char input;
|
||||
bool not_won = true;
|
||||
while(cin && not_won)
|
||||
{
|
||||
display_maze(player_position);
|
||||
cin >> input;
|
||||
if(cin)
|
||||
{
|
||||
player_position = process_input(player_position, input);
|
||||
|
||||
if(reached_goal(player_position))
|
||||
{
|
||||
display_maze(player_position);
|
||||
cout << "Ziel erreicht! Herzlichen Glueckwunsch!\n";
|
||||
not_won = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
game_loop(kPlayerStartPosition);
|
||||
const Maze maze = Maze();
|
||||
// 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 input;
|
||||
|
||||
// Durchlaufe die Hauptschleife des Spiels
|
||||
while (true)
|
||||
{
|
||||
// Zeige dem Spieler das Spielfeld
|
||||
maze.render(player.get_pos());
|
||||
|
||||
// Kontrolliere, ob der Spieler schon das Ziel erreicht hat
|
||||
if (maze.is_player_at_goal(player.get_pos()))
|
||||
{
|
||||
// Ziel erreicht! Herzlichen Glückwunsch!
|
||||
cout << "Ziel erreicht! Herzlichen Glueckwunsch!\n";
|
||||
break;
|
||||
}
|
||||
|
||||
// Lese Eingabe des Spielers
|
||||
cin >> 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 << "Gebe 'w', 'a', 's', oder 'd' ein zum bewegen. Gebe 'h' ein um diesen Text anzuzeigen.\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.
|
||||
player.move(maze, movement_vector);
|
||||
}
|
||||
// Beende das Programm
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue