diff --git a/6_praktikum/bishop.h b/6_praktikum/bishop.h new file mode 100644 index 0000000000000000000000000000000000000000..7a6b60124f27766bd8f1739167db25deefbfb872 --- /dev/null +++ b/6_praktikum/bishop.h @@ -0,0 +1,11 @@ +#include "piece.h" + +class Bishop : public Piece{ +public: +Bishop(const Color& color); +Bishop(const Piece& piece); +bool isMovePossible(const Board&, const Move&) override; +protected: +vector<Field> getPossibleMoves(const Board& board, const Move& move) const override; + +}; \ No newline at end of file diff --git a/6_praktikum/board.cpp b/6_praktikum/board.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d4ac9c06dc5d1eac51950ec38807f6b99d5581d --- /dev/null +++ b/6_praktikum/board.cpp @@ -0,0 +1,186 @@ +#include <iostream> +#include <type_traits> +#include "pawn.h" +#include "bishop.h" +#include "king.h" +#include "knight.h" +#include "queen.h" +#include "rook.h" +#include "board.h" +#include "input.h" +#include "piece.h" +using namespace std; +Board::Board() : currentPlayer(Color::White){ + for(int i = 0; i < size; i++){ + gamefield.push_back(vector<Piece*>{}); + Color c = (i == 0 || i == 1 ? Color::Black : Color::White); + for(int j = 0; j < size; j++){ + if(j== 0 || j == 7){ + gamefield[i].push_back(new Rook(c)); + gamefield[i].push_back(new Knight(c)); + gamefield[i].push_back(new Bishop(c)); + gamefield[i].push_back(new Queen(c)); + gamefield[i].push_back(new King(c)); + gamefield[i].push_back(new Bishop(c)); + gamefield[i].push_back(new Knight(c)); + gamefield[i].push_back(new Rook(c)); + break; + + }else if (i == 1 || i == 6){ + gamefield[i].push_back(new Pawn(c)); + + } else + gamefield[i].push_back(new Piece("-----", Color::Empty)); + } + } +} + +Board::Board(const Board& board) : currentPlayer(board.currentPlayer){ + for(int i = 0; i < size; i++){ + gamefield.push_back(vector<Piece*>{}); + for (int j = 0; j < size; j++) { + Field field {row = (int) i, col = (int) j}; + if(board.getPieceOnField(field)->toString() == Bishop(Color::White).toString() || board.getPieceOnField(field)->toString()== Bishop(Color::Black).toString()){ + gamefield[i].push_back(new Bishop(*board.gamefield[i][j])); + } else if(board.getPieceOnField(field)->toString() == King(Color::White).toString() || board.getPieceOnField(field)->toString()== King(Color::Black).toString()){ + gamefield[i].push_back(new King(*board.gamefield[i][j])); + } else if(board.getPieceOnField(field)->toString() == Knight(Color::White).toString() || board.getPieceOnField(field)->toString()== Knight(Color::Black).toString()){ + gamefield[i].push_back(new Knight(*board.gamefield[i][j])); + } else if(board.getPieceOnField(field)->toString() == Pawn(Color::White).toString() || board.getPieceOnField(field)->toString()== Pawn(Color::Black).toString()){ + gamefield[i].push_back(new Pawn(*board.gamefield[i][j])); + } else if(board.getPieceOnField(field)->toString() == Queen(Color::White).toString() || board.getPieceOnField(field)->toString()== Queen(Color::Black).toString()){ + gamefield[i].push_back(new Queen(*board.gamefield[i][j])); + } else if(board.getPieceOnField(field)->toString() == Rook(Color::White).toString() || board.getPieceOnField(field)->toString()== Rook(Color::Black).toString()){ + gamefield[i].push_back(new Rook(*board.gamefield[i][j])); + } else{ + gamefield[i].push_back(new Piece(*board.gamefield[i][j])); + } + + } + } +} + +Board::~Board(){ + for(int i = 0; i < size; i++){ + for(int j = 0; j < size; j++){ + if(gamefield[i][j] == 0) continue; + delete gamefield[i][j]; + gamefield[i][j] = NULL; + } + gamefield[i].clear(); + } + gamefield.clear(); +} + +bool Board::isMoveInBounds(const Move& move) const{ + if(move.from.col >= 0 && move.from.col < size && move.from.row >= 0 && move.from.row < size && move.to.col >=0 && move.to.col < size && move.to.row >=0 && move.to.row < size) return true; + return false; +} +bool Board::isEnemy(const Field& field) const{ + if((currentPlayer == Color::White && getPieceOnField(field)->isBlack()) || (currentPlayer == Color::Black && getPieceOnField(field)->isWhite())) return true; + return false; +} + + +void Board::play(){ + while(true){ + printBoard(); + string player = (currentPlayer == Color::White ? "[White]" : "[Black]"); + string standardOutput = player + "Geben Sie den gewünschten Zug an(Form a1-b2): "; + + Move nextMove; + do{ + cout << standardOutput << endl; + string input; + getline(cin, input); + + if (!input.compare("quit")) return; + cout.flush(); + cout.clear(); + nextMove = convertConsoleToMove(input); + } + while(!checkMove(nextMove)); + + bool hasPlayerWon = MoveHandlerAndWinCheck(nextMove); + if(hasPlayerWon) return; + + currentPlayer = (currentPlayer == Color::White ? Color::Black : Color::White); + cout << endl; + } +} + + +void Board:: printBoard() const{ + int rowIndex = 0; + for(auto& row : gamefield){ + cout << rowIndex+1 << " "; + for(auto& piece : row){ + cout << piece-> toString() << " "; + } + cout << " " << rowIndex+1 << endl; + rowIndex++; + cout << endl; + } +} + + +bool Board::hasWon(const Field& enemy) const{ + if(getPieceOnField(enemy)->toString() == King(Color::White).toString() || getPieceOnField(enemy)->toString() == King(Color::Black).toString()) return true; +} + +int getSize() const{ + return size; +} + +bool Board::isFieldFree(const Field& field) const { + return getPieceOnField(field)->isEmpty(); +} + +bool Board::isFieldPossible(const Field& field) const{ +if(isFieldFree(field) || isEnemy(field)) return true; +return false; +} +Piece* Board::getPieceOnField(const Field& field) const{ + return gamefield[field.row][field.col]; +} + +bool Board::checkMove(const Move& move) const { + if(!isMoveInBounds(move)){ + cout << "Please enter a Move that is valid!" << endl; + return false; + } + if(!getPieceOnField(move.from)->isMovePossible(*this, move)){ + cout << "Move is not valid for " << getPieceOnField(move.from)->toString() << "!" << endl; + return false; + } + if(isFieldFree(move.from)){ + cout << "Pls select a Field that is not empty!" << endl; + return false; + + } + if(!isEnemy(move.from)){ + cout << "Please select one of your own Pieces!" << endl; + return false; + } + if(!isEnemy(move.to) && !isFieldFree(move.to)){ + cout << "Please select an enemy Piece to Attack!" << endl; + return false; + } + return true; +} + +bool Board::MoveHandlerAndWinCheck(const Move &move){ + if(isEnemy(move.to)){ + cout << "You hit an enemy!" << endl; + + if(hasWon(move.to)){ + cout << "Congratulations you won the game!" << endl; + return true; + } + } + delete(gamefield[move.to.row][move.to.col]); + gamefield[move.to.row][move.to.col] = gamefield[move.from.row][move.from.col]; + gamefield[move.from.row][move.from.col] = new Piece("-----", Color::Empty); + return false; +} + diff --git a/6_praktikum/board.h b/6_praktikum/board.h new file mode 100644 index 0000000000000000000000000000000000000000..a11c70f6b3e5db16534b921984ef837b2135ffd8 --- /dev/null +++ b/6_praktikum/board.h @@ -0,0 +1,37 @@ +#include <vector> +enum class Color; +class Piece; +#include "piece.h" +using namespace std; + +struct Field { + int row; + int col; +}; +struct Move{ + Field from; + Field to; +}; +class Board{ +public: +Board(); +Board(const Board& board); +void play(); +void printBoard() const; +bool isFieldPossible(const Field& position) const; +bool isFieldFree(const Field& position) const; +int getSize() const; +~Board(); + +private: +vector<vector<Piece*>> gamefield; +const int size = 8; +bool isMoveInBounds(const Move& move) const; +bool isEnemy(const Field& field) const; +Piece* getPieceOnField(const Field& field) const; +bool checkMove(const Move& move) const; +bool MoveHandlerAndWinCheck(const Move& move); +bool hasWon(const Field& enemyPosition) const; +Color currentPlayer; + +}; \ No newline at end of file diff --git a/6_praktikum/input.h b/6_praktikum/input.h new file mode 100644 index 0000000000000000000000000000000000000000..d38061592b0cef39c18d5b61838bf80fae1f6dfd --- /dev/null +++ b/6_praktikum/input.h @@ -0,0 +1,4 @@ +#include "board.h" + +int convertCharToInt(const char& c); +Move convertConsoleToMove(const string& input); \ No newline at end of file diff --git a/6_praktikum/king.cpp b/6_praktikum/king.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c0d55d775d40dbca0dc09fd285cea7325df9ef15 --- /dev/null +++ b/6_praktikum/king.cpp @@ -0,0 +1,16 @@ +#include "king.h" +#include "board.h" + +King::King(const Color& color) : Piece("King", color){ + +} +King::King(const Piece& piece) : Piece(piece){ + +} +bool King::isMovePossible(const Board&, const Move&){ + return true; +} +vector<Field> King::getPossibleMoves(const Board&, const Move&) const { + vector<Field> fields; + return fields; +} \ No newline at end of file diff --git a/6_praktikum/king.h b/6_praktikum/king.h new file mode 100644 index 0000000000000000000000000000000000000000..75fc21eed56c60295c84078671a5d650021cf8f0 --- /dev/null +++ b/6_praktikum/king.h @@ -0,0 +1,11 @@ +#include "piece.h" + +class King : public Piece{ +public: +King(const Color& color); +King(const Piece& piece); +bool isMovePossible(const Board&, const Move&) override; +protected: +vector<Field> getPossibleMoves(const Board& board, const Move& move) const override; + +}; \ No newline at end of file diff --git a/6_praktikum/knight.cpp b/6_praktikum/knight.cpp new file mode 100644 index 0000000000000000000000000000000000000000..00000609637ff67944ae4b215e266b0ec17af45f --- /dev/null +++ b/6_praktikum/knight.cpp @@ -0,0 +1,33 @@ +#include "knight.h" +#include "board.h" + +Knight::Knight(const Color& color) : Piece("Knight", color){ + +} +Knight::Knight(const Piece& piece) : Piece(piece){ + +} + +bool Knight::isMovePossible(const Board& b, const Move& m){ + vector<Field> possibleMoves = getPossibleMoves(b,m); + for (auto pos : possibleMoves){ + if(pos.row == m.to.row && pos.col == m.to.col) return true; + + } + return false; +} + +vector<Field> Knight::getPossibleMoves(const Board& board, const Move& move) const{ + + vector<Field> fields; + vector<Field> knightMoves { + Field {.row = -2, .col = -1}, Field{.row = -1, .col = -2},Field{.row = 1, .col = -2}, Field{.row = 2, .col = -1}, Field{.row = 2, .col = 1}, Field{.row = 1, .col = 2}, Field{.row = -1, .col = 2},Field{.row = -2, .col = 1} + }; + for(Field knightMove : knightMoves){ + Field tempField{ .row = (move.from.row + knightMove.row), .col = (move.from.col + knightMove.col)}; + if(move.from.col + knightMove.col > board.getSize()-1 || move.from.col + knightMove.col <0) continue; + if(move.from.row + knightMove.row > board.getSize()-1 || move.from.row + knightMove.crow <0) continue; + if(board.isFieldPossible(tempField)) fields.push_back(tempField); + } + return fields; +} \ No newline at end of file diff --git a/6_praktikum/knight.h b/6_praktikum/knight.h new file mode 100644 index 0000000000000000000000000000000000000000..b7dc3bf873986e728568a2f879b16374f71d5111 --- /dev/null +++ b/6_praktikum/knight.h @@ -0,0 +1,11 @@ +#include "piece.h" + +class Knight : public Piece{ +public: +Knight(const Color& color); +Knight(const Piece& piece); +bool isMovePossible(const Board&, const Move&) override; +protected: +vector<Field> getPossibleMoves(const Board& board, const Move& move) const override; + +}; \ No newline at end of file diff --git a/6_praktikum/main.cpp b/6_praktikum/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ab70af8a32cf99de494920d4c3cf9760ff61687 --- /dev/null +++ b/6_praktikum/main.cpp @@ -0,0 +1,9 @@ +#include <iostream> +#include "board.h" +using namespace std; + +int main(){ + Board gameboard1 = Board(); + gameboard1.play(); + return 0; +} \ No newline at end of file diff --git a/6_praktikum/pawn.cpp b/6_praktikum/pawn.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a9df76bf7ca9a87425e3ffbbd44319a637ad55d3 --- /dev/null +++ b/6_praktikum/pawn.cpp @@ -0,0 +1,9 @@ +#include "piece.h" +#include "pawn.h" +#include "board.h" +Pawn::Pawn(const Color& color) : Piece(Pawn, color){ +} +Pawn::Pawn(const Piece &piece) : Piece(piece){ + +} +bool Pawn::isMovePossible(const Board&, const Move& ) \ No newline at end of file diff --git a/6_praktikum/pawn.h b/6_praktikum/pawn.h new file mode 100644 index 0000000000000000000000000000000000000000..7dc8b456ed04f73244dac1e9928cdec50ccff575 --- /dev/null +++ b/6_praktikum/pawn.h @@ -0,0 +1,11 @@ +#include "piece.h" + +class Pawn : public Piece{ +public: +Pawn(const Color& color); +Pawn(const Piece& piece); +bool isMovePossible(const Board&, const Move&) override; +protected: +vector<Field> getPossibleMoves(const Board& board, const Move& move) const override; + +}; \ No newline at end of file diff --git a/6_praktikum/piece.cpp b/6_praktikum/piece.cpp new file mode 100644 index 0000000000000000000000000000000000000000..759ebe1f095ac27cef237bdfb0d7e881d7e7e1b7 --- /dev/null +++ b/6_praktikum/piece.cpp @@ -0,0 +1,35 @@ +#include "piece.h" +#include "board.h" +#include <string> + + +Piece::Piece(const string &displayString, Color color) : displayString(displayString), color(color){ + +} + +bool Piece::isEmpty() const{ + return Piece::color == Color::Empty; +} +bool Piece::isWhite() const{ + return Piece::color == Color::White; +} +bool Piece::isBlack() const{ + return Piece::color == Color::Black; +} +bool Piece::isMovePossible(const Board&, const Move&){ + return true; +} +std::string Piece::toString() const{ + if(color == Color::White){ + return "W" + displayString; + }else if (color == Color::Black){ + return "B" + displayString; + } else { + return displayString; + } +} + +vector<Field> Piece::getPossibleMoves(const Board&, const Move&) const{ + vector<Field> fields; + return fields; +} \ No newline at end of file diff --git a/6_praktikum/piece.h b/6_praktikum/piece.h new file mode 100644 index 0000000000000000000000000000000000000000..4f0b8f8fa5d48b50ca60d4f2c0da9787847bce8d --- /dev/null +++ b/6_praktikum/piece.h @@ -0,0 +1,107 @@ +#ifndef PIECE_H +#define PIECE_H + +#include "board.h" +#include <string> + +/** + * @brief The Color enum is used to represent the color of a piece. + * + * Since you are free to choose wether an empty field is represented by a piece + * object or simply a nullptr you are free to edit this enum if that is the case + * in your implementeation. + */ +enum class Color +{ + White, + Black, + Empty +}; + +/** + * @brief The Piece class represents a single chess piece + * + * This class is the base class of all other chess pieces. Every distinct chess + * piece is implemented in it's own class. Header files for those classes are + * not part of the supplied code, so you will have to write your own. + * It is also possible to declare multiple classes in a single header, so you + * could also declare the needed classes here. + * + * Every piece object has a distinct \ref displayString which is the string + * representation of that particular piece. Subclasses of piece are supposed to + * set those string via constructor chaining. + */ +class Piece +{ + public: + /** + * @brief Piece constructor + * @param displayString The string representation of this piece + * @param color The color of this piece + */ + Piece(const std::string& displayString, Color color); + + /** + * @brief Piece destructor + * + * This is needed in **every** inheritance hierarchy and insures that the + * correct (subclass) destructor is always called when an object is deletet + * via a base class pointer. + * + * You do not need to implement anything special here, it is just important + * that the destructor is declared virtual. + * + * Setting the destructor to = default gives that destructor the default + * behaviour (which is: do nothing) + */ + virtual ~Piece() = default; + + /** + * @brief isWhite return true if piece is White + * @return true if piece is White + */ + bool isWhite() const; + + /** + * @brief isBlack return true if piece is Black + * @return true if piece is Black + */ + bool isBlack() const; + + /** + * @brief isEmpty return true if this is an empty piece + * @return true if piece is an empty piece + * + * Note: You can choose whether you want to represent the concept of an "empty + * field" by a special type of object, or by having a nullptr for empty + * fields. + * When choosing the latter, you can omit this method. + */ + bool isEmpty() const; + + /** + * @brief toString returns string representation of piece + * @return string representation pf piece + */ + std::string toString() const; + + /** + * @brief isMovePossible checks if the supplied move is possible + * @return true if the move was possible + * + * This method need to be virtual because it is overwritten in certain + * subclasses. You can implement a "default version" in the piece class which + * just return true. + * The "virtual" keyword has the effect, that, for example, + * Rook::isMovePossible is called automagically when called on a piece* when + * that piece* is referencing a Rook object. + */ + virtual bool isMovePossible(const Board& /*b*/, const Board::Move& /*m*/); + + private: + const std::string displayString; + const Color color; +}; + +#endif // PIECE_H + diff --git a/6_praktikum/queen.cpp b/6_praktikum/queen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8618a6a4de2518ceb396f9bbefcb4016bdc7e432 --- /dev/null +++ b/6_praktikum/queen.cpp @@ -0,0 +1,16 @@ +#include "queen.h" +#include "board.h" + +Queen::Queen(const Color& color) : Piece("Queen", color){ + +} +Queen::Queen(const Piece& piece) : Piece(piece){ + +} +bool Queen::isMovePossible(const Board&, const Move&){ + return true; +} +vector<Field> Queen::getPossibleMoves(const Board&, const Move&) const { + vector<Field> fields; + return fields; +} \ No newline at end of file diff --git a/6_praktikum/queen.h b/6_praktikum/queen.h new file mode 100644 index 0000000000000000000000000000000000000000..f10f48385bcd6e5163a80dc56791d73716e3cffc --- /dev/null +++ b/6_praktikum/queen.h @@ -0,0 +1,11 @@ +#include "piece.h" + +class Queen : public Piece{ +public: +Queen(const Color& color); +Queen(const Piece& piece); +bool isMovePossible(const Board&, const Move&) override; +protected: +vector<Field> getPossibleMoves(const Board& board, const Move& move) const override; + +}; \ No newline at end of file diff --git a/6_praktikum/rook.h b/6_praktikum/rook.h new file mode 100644 index 0000000000000000000000000000000000000000..d9e6f87e91d9c62ea06172a80dd081d0d16d76de --- /dev/null +++ b/6_praktikum/rook.h @@ -0,0 +1,11 @@ +#include "piece.h" + +class Rook : public Piece{ +public: +Rook(const Color& color); +Rook(const Piece& piece); +bool isMovePossible(const Board&, const Move&) override; +protected: +vector<Field> getPossibleMoves(const Board& board, const Move& move) const override; + +}; \ No newline at end of file