Exercise-Template pushed by Artemis
This commit is contained in:
commit
6889d79ae8
4 changed files with 545 additions and 0 deletions
38
.gitattributes
vendored
Normal file
38
.gitattributes
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
# Source: https://github.com/alexkaratarakis/gitattributes/blob/master/C%2B%2B.gitattributes (08.12.2020)
|
||||
|
||||
# Sources
|
||||
*.c text diff=c
|
||||
*.cc text diff=cpp
|
||||
*.cxx text diff=cpp
|
||||
*.cpp text diff=cpp
|
||||
*.c++ text diff=cpp
|
||||
*.hpp text diff=cpp
|
||||
*.h text diff=c
|
||||
*.h++ text diff=cpp
|
||||
*.hh text diff=cpp
|
||||
|
||||
# Compiled Object files
|
||||
*.slo binary
|
||||
*.lo binary
|
||||
*.o binary
|
||||
*.obj binary
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch binary
|
||||
*.pch binary
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so binary
|
||||
*.dylib binary
|
||||
*.dll binary
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai binary
|
||||
*.la binary
|
||||
*.a binary
|
||||
*.lib binary
|
||||
|
||||
# Executables
|
||||
*.exe binary
|
||||
*.out binary
|
||||
*.app binary
|
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
*
|
||||
|
||||
!*.h
|
||||
!*.hpp
|
||||
!*.cpp
|
||||
!*.sh
|
||||
!Makefile
|
||||
!.gitignore
|
||||
!.gitattributes
|
||||
|
||||
!*/
|
197
main.cpp
Normal file
197
main.cpp
Normal file
|
@ -0,0 +1,197 @@
|
|||
// 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"
|
||||
|
||||
// Globale Labyrinth-Definition als konstanter Ausdruck
|
||||
constexpr int kRows = 5;
|
||||
constexpr int kCols = 5;
|
||||
|
||||
// Labyrinth-Daten
|
||||
// Interpretiere als Zeilen, dann Spalten
|
||||
const vector<vector<char>> kMaze = {
|
||||
{'#', '.', '.', '.', '.'},
|
||||
{'#', '.', '#', '.', '.'},
|
||||
{'.', 'Z', '#', '.', '.'},
|
||||
{'.', '#', '#', '#', '.'},
|
||||
{'.', '.', '.', '.', '.'},
|
||||
};
|
||||
|
||||
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);
|
||||
return 0;
|
||||
}
|
299
std_lib_inc.h
Normal file
299
std_lib_inc.h
Normal file
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
std_lib_inc.h
|
||||
|
||||
Version 2024-11-07
|
||||
|
||||
simple "Programming: Principles and Practice using C++ (second edition)" course header to
|
||||
be used for the first few weeks.
|
||||
It provides the most common standard headers (in the global namespace)
|
||||
and minimal exception/error support.
|
||||
|
||||
Students: please don't try to understand the details of headers just yet.
|
||||
All will be explained. This header is primarily used so that you don't have
|
||||
to understand every concept all at once.
|
||||
|
||||
By Chapter 10, you don't need this file and after Chapter 21, you'll understand it
|
||||
|
||||
Revised April 25, 2010: simple_error() added
|
||||
|
||||
Revised November 25 2013: remove support for pre-C++11 compilers, use C++11: <chrono>
|
||||
Revised November 28 2013: add a few container algorithms
|
||||
Revised June 8 2014: added #ifndef to workaround Microsoft C++11 weakness
|
||||
Revised Febrary 2 2015: randint() can now be seeded (see exercise 5.13).
|
||||
Revised August 3, 2020: a cleanup removing support for ancient compilers
|
||||
Revised November 7, 2024: assertions to avoid cassert and NDEBUG (Fritz)
|
||||
*/
|
||||
|
||||
#ifndef H112
|
||||
#define H112 080315L
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <forward_list>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <regex>
|
||||
#include <random>
|
||||
#include <stdexcept>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
typedef long Unicode;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using namespace std;
|
||||
|
||||
inline bool ASSERTIONS_ACTIVE = false;
|
||||
|
||||
template<class T> string to_string(const T& t)
|
||||
{
|
||||
ostringstream os;
|
||||
os << t;
|
||||
return os.str();
|
||||
}
|
||||
|
||||
struct Range_error : out_of_range { // enhanced vector range error reporting
|
||||
int index;
|
||||
Range_error(int i) : out_of_range("Range error: " + to_string(i)), index(i) { }
|
||||
};
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
// trivially range-checked vector (no iterator checking):
|
||||
template<class T>
|
||||
struct Vector : public std::vector<T>
|
||||
{
|
||||
using size_type = typename std::vector<T>::size_type;
|
||||
|
||||
/* #ifdef _MSC_VER
|
||||
// microsoft doesn't yet support C++11 inheriting constructors
|
||||
Vector() { }
|
||||
explicit Vector(size_type n) :std::vector<T>(n) {}
|
||||
Vector(size_type n, const T& v) :std::vector<T>(n, v) {}
|
||||
template <class I>
|
||||
Vector(I first, I last) : std::vector<T>(first, last) {}
|
||||
Vector(initializer_list<T> list) : std::vector<T>(list) {}
|
||||
*/
|
||||
using std::vector<T>::vector; // inheriting constructor
|
||||
|
||||
T &operator[](unsigned int i) // rather than return at(i);
|
||||
{
|
||||
if(i < 0 || this->size() <= i) throw Range_error(i);
|
||||
return std::vector<T>::operator[](i);
|
||||
}
|
||||
|
||||
const T &operator[](unsigned int i) const
|
||||
{
|
||||
if(i < 0 || this->size() <= i) throw Range_error(i);
|
||||
return std::vector<T>::operator[](i);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// disgusting macro hack to get a range checked vector:
|
||||
#define vector Vector
|
||||
|
||||
// trivially range-checked string (no iterator checking):
|
||||
struct String : std::string {
|
||||
using size_type = std::string::size_type;
|
||||
// using string::string;
|
||||
|
||||
char& operator[](unsigned int i) // rather than return at(i);
|
||||
{
|
||||
if (i<0 || size() <= i) throw Range_error(i);
|
||||
return std::string::operator[](i);
|
||||
}
|
||||
|
||||
const char& operator[](unsigned int i) const
|
||||
{
|
||||
if (i<0 || size() <= i) throw Range_error(i);
|
||||
return std::string::operator[](i);
|
||||
}
|
||||
};
|
||||
|
||||
namespace std {
|
||||
|
||||
template<> struct hash<String>
|
||||
{
|
||||
size_t operator()(const String& s) const
|
||||
{
|
||||
return hash<std::string>()(s);
|
||||
}
|
||||
};
|
||||
|
||||
} // of namespace std
|
||||
|
||||
|
||||
struct Exit : runtime_error {
|
||||
Exit() : runtime_error("Exit") {}
|
||||
};
|
||||
|
||||
// error() simply disguises throws:
|
||||
[[noreturn]]
|
||||
inline void error(const string& s)
|
||||
{
|
||||
throw runtime_error(s);
|
||||
}
|
||||
|
||||
[[noreturn]]
|
||||
inline void error(const string& s, const string& s2)
|
||||
{
|
||||
error(s + s2);
|
||||
}
|
||||
|
||||
inline void error(const string& s, int i)
|
||||
{
|
||||
ostringstream os;
|
||||
os << s << ": " << i;
|
||||
error(os.str());
|
||||
}
|
||||
|
||||
|
||||
template<class T> char* as_bytes(T& i) // needed for binary I/O
|
||||
{
|
||||
void* addr = &i; // get the address of the first byte
|
||||
// of memory used to store the object
|
||||
return static_cast<char*>(addr); // treat that memory as bytes
|
||||
}
|
||||
|
||||
|
||||
inline void keep_window_open()
|
||||
{
|
||||
cin.clear();
|
||||
cout << "Bitte gib ein Zeichen zum beenden ein:\n";
|
||||
char ch;
|
||||
cin >> ch;
|
||||
return;
|
||||
}
|
||||
|
||||
inline void keep_window_open(string s)
|
||||
{
|
||||
if (s == "") return;
|
||||
cin.clear();
|
||||
cin.ignore(120, '\n');
|
||||
for (;;) {
|
||||
cout << "Bitte gib '" << s << "' ein, um zu beenden\n";
|
||||
string ss;
|
||||
while (cin >> ss && ss != s)
|
||||
cout << "Bitte gib '" << s << "' ein, um zu beenden\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Assertion handling that avoids cassert and debug mode (Fritz)
|
||||
#undef assert
|
||||
|
||||
inline void activateAssertions()
|
||||
{
|
||||
ASSERTIONS_ACTIVE = true;
|
||||
}
|
||||
|
||||
inline void assert(bool condition, const string& message = "")
|
||||
{
|
||||
if (ASSERTIONS_ACTIVE && !condition)
|
||||
{
|
||||
if(message == "")
|
||||
{
|
||||
cout << "Assertion fehlgeschlagen!\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Assertion fehlgeschlagen: " << message << "\n";
|
||||
}
|
||||
keep_window_open();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// error function to be used (only) until error() is introduced in Chapter 5:
|
||||
inline void simple_error(string s) // write ``error: s and exit program
|
||||
{
|
||||
cout << "fehler: " << s << '\n';
|
||||
keep_window_open(); // for some Windows environments
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// make std::min() and std::max() accessible on systems with antisocial macros:
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
|
||||
// run-time checked narrowing cast (type conversion). See ???.
|
||||
// Fritz: deprecated with {}-construction
|
||||
template<class R, class A> R narrow_cast(const A& a)
|
||||
{
|
||||
R r = R(a);
|
||||
if (A(r) != a) error(string("informationsverlust"));
|
||||
return r;
|
||||
}
|
||||
|
||||
// random number generators. See 24.7.
|
||||
|
||||
inline default_random_engine& get_rand()
|
||||
{
|
||||
static default_random_engine ran; // note: not thread_local
|
||||
return ran;
|
||||
};
|
||||
|
||||
inline void seed_randint(int s) { get_rand().seed(s); }
|
||||
|
||||
inline int randint(int min, int max) { return uniform_int_distribution<>{min, max}(get_rand()); }
|
||||
|
||||
inline int randint(int max) { return randint(0, max); }
|
||||
|
||||
//inline double sqrt(int x) { return sqrt(double(x)); } // to match C++0x
|
||||
|
||||
// container algorithms. See 21.9. // C++ has better versions of this:
|
||||
|
||||
template<typename C>
|
||||
using Value_type = typename C::value_type;
|
||||
|
||||
template<typename C>
|
||||
using Iterator = typename C::iterator;
|
||||
|
||||
template<typename C>
|
||||
// requires Container<C>()
|
||||
void sort(C& c)
|
||||
{
|
||||
std::sort(c.begin(), c.end());
|
||||
}
|
||||
|
||||
template<typename C, typename Pred>
|
||||
// requires Container<C>() && Binary_Predicate<Value_type<C>>()
|
||||
void sort(C& c, Pred p)
|
||||
{
|
||||
std::sort(c.begin(), c.end(), p);
|
||||
}
|
||||
|
||||
template<typename C, typename Val>
|
||||
// requires Container<C>() && Equality_comparable<C,Val>()
|
||||
Iterator<C> find(C& c, Val v)
|
||||
{
|
||||
return std::find(c.begin(), c.end(), v);
|
||||
}
|
||||
|
||||
template<typename C, typename Pred>
|
||||
// requires Container<C>() && Predicate<Pred,Value_type<C>>()
|
||||
Iterator<C> find_if(C& c, Pred p)
|
||||
{
|
||||
return std::find_if(c.begin(), c.end(), p);
|
||||
}
|
||||
|
||||
#endif //H112
|
Loading…
Reference in a new issue