Compare commits
49 Commits
4cf45f75bc
...
main
Author | SHA1 | Date | |
---|---|---|---|
3891d90f43
|
|||
a7ef306800
|
|||
a1e1205247
|
|||
1007b6744d
|
|||
f0701fe9e7
|
|||
b462ae3c7e
|
|||
8ad2a1342a
|
|||
99007047eb
|
|||
|
d8b9430120 | ||
|
4f4d598eb6 | ||
|
2f065f4917 | ||
3e8d6d9557
|
|||
|
6c8d033629 | ||
|
3dfe314836 | ||
|
ca546e5ba6 | ||
|
6b01273580 | ||
625d607ef0
|
|||
|
14869f4a83 | ||
|
47b880e737 | ||
efd60b89e4
|
|||
bbd92bfa8b | |||
65227d12ab | |||
d2fbaa4af6
|
|||
|
2ae5de715d | ||
8d75c055c0 | |||
83eb22e627 | |||
30cd5c4af8 | |||
faa0e236b6 | |||
|
12a009b7db | ||
|
373c186075 | ||
|
9821f78c87 | ||
|
9fb66b6755 | ||
50b3312f49
|
|||
6127e4cf37 | |||
|
8636bcfb0c | ||
aa06318c07
|
|||
7695efa5d3
|
|||
c38f134254
|
|||
99c644bffb
|
|||
4602cbe187
|
|||
0a1f3d1e26
|
|||
|
b4c2f84ea0 | ||
|
c9f83c396f | ||
|
5a77578699 | ||
|
0fbe762391 | ||
|
85d22b4736 | ||
|
d1286469c3 | ||
|
de0cbf5a8b | ||
|
e24ebcfc0b |
@@ -8,3 +8,7 @@ trim_trailing_whitespace = true
|
||||
|
||||
[*.{cc,cpp,hpp,h}]
|
||||
insert_final_newline = true
|
||||
|
||||
[makefile]
|
||||
indent_size = 4
|
||||
indent_style = tab
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,4 +1,7 @@
|
||||
.vscode/
|
||||
.idea/
|
||||
build/
|
||||
docs/
|
||||
*.exe
|
||||
*.txt
|
||||
chess
|
@@ -1,174 +0,0 @@
|
||||
#include "Pawn.hpp"
|
||||
|
||||
/**
|
||||
* Creates a new pawn with a specified color and position.
|
||||
* @param color The color of the pawn.
|
||||
* @param position The position of the pawn.
|
||||
*/
|
||||
Pawn::Pawn(ChessPieceColor color, ChessPiecePosition position) : ChessPiece(color, position) {
|
||||
this->_char = this->_CHAR_PAWN;
|
||||
this->_unicode = {"\u265F", "\u2659"};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all chess piece positions the pawn can move next.
|
||||
* The set of chess piece positions will be ignored, because the pawn has a fixed movement.
|
||||
* @param chessboard A pointer to the chessboard.
|
||||
* @param ignore A set of chess piece positions to be ignored.
|
||||
* @return A set of chess piece positions the pawn can move next.
|
||||
*/
|
||||
std::set<ChessPiecePosition> Pawn::GetNextPositions(Chessboard* chessboard, std::set<ChessPiecePosition> ignore) {
|
||||
std::set<ChessPiecePosition> positions;
|
||||
ChessPiecePosition currentPosition = this->GetPosition();
|
||||
ChessPiecePosition* nextPosition = ¤tPosition;
|
||||
|
||||
if (this->GetColor() == ChessPieceColor::Black) {
|
||||
|
||||
// 3.7.1. The pawn may move forward to the square immediately in front of it on the same file, provided that this square is unoccupied.
|
||||
// 3.7.2. On its first move the pawn may move as in 3.7.1 or alternatively it may advance two squares along the same file, provided that both squares are unoccupied.
|
||||
for (int move = 1; move <= 2; move++) {
|
||||
nextPosition = nextPosition->NextBottom();
|
||||
|
||||
if (nextPosition) {
|
||||
if (chessboard->IsEmptyField(nextPosition) == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (move == 1) {
|
||||
positions.insert(*nextPosition);
|
||||
} else if (move == 2 && this->IsFirstMove()) {
|
||||
positions.insert(*nextPosition);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 3.7.3. the pawn may move to a square occupied by an opponent's piece diagonally in front of it on an adjacent file, capturing that piece.
|
||||
for (std::string move : {"B1L1", "B1R1"}) {
|
||||
nextPosition = ¤tPosition;
|
||||
nextPosition = nextPosition->NextFromString(move);
|
||||
|
||||
if (nextPosition && chessboard->IsEmptyField(nextPosition) == false) {
|
||||
ChessPiece* chessPiece = chessboard->GetChessPiece(nextPosition);
|
||||
|
||||
if (chessPiece->GetColor() != this->GetColor()) {
|
||||
positions.insert(*nextPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3.7.3.1. A pawn occupying a square on the same rank as and on an adjacent file to an opponent's pawn which has just advanced two squares
|
||||
// in one move from its original square may capture this opponent's pawn as though the latter had been moved only one square.
|
||||
// 3.7.3.2. This capture is only legal on the move following this advance and is called an "en passant" capture.
|
||||
if (chessboard->GetCountMoves() > 0) {
|
||||
std::pair<ChessPiecePosition, ChessPiecePosition> lastMove = chessboard->GetLastMove();
|
||||
std::string moveDifference = ChessPiecePosition::GetDifference(lastMove.first, lastMove.second);
|
||||
ChessPiecePosition* leftPosition = currentPosition.NextLeft();
|
||||
ChessPiecePosition* rightPosition = currentPosition.NextRight();
|
||||
|
||||
if (leftPosition && chessboard->IsEmptyField(leftPosition) == false) {
|
||||
ChessPiece* chessPiece = chessboard->GetChessPiece(leftPosition);
|
||||
|
||||
if (chessPiece->GetColor() != this->GetColor() && chessPiece->IsPawn()) {
|
||||
if (chessPiece->GetNumberOfMoves() == 1 && moveDifference == "T2" && chessPiece->GetPosition() == lastMove.second) {
|
||||
ChessPiecePosition* bottomLeftPosition = currentPosition.NextFromString("B1L1");
|
||||
|
||||
if (bottomLeftPosition && chessboard->IsEmptyField(bottomLeftPosition)) {
|
||||
positions.insert(*bottomLeftPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rightPosition && chessboard->IsEmptyField(rightPosition) == false) {
|
||||
ChessPiece* chessPiece = chessboard->GetChessPiece(rightPosition);
|
||||
|
||||
if (chessPiece->GetColor() != this->GetColor() && chessPiece->IsPawn()) {
|
||||
if (chessPiece->GetNumberOfMoves() == 1 && moveDifference == "T2" && chessPiece->GetPosition() == lastMove.second) {
|
||||
ChessPiecePosition* bottomRightPosition = currentPosition.NextFromString("B1R1");
|
||||
|
||||
if (bottomRightPosition && chessboard->IsEmptyField(bottomRightPosition)) {
|
||||
positions.insert(*bottomRightPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (this->GetColor() == ChessPieceColor::White) {
|
||||
|
||||
// 3.7.1. The pawn may move forward to the square immediately in front of it on the same file, provided that this square is unoccupied.
|
||||
// 3.7.2. On its first move the pawn may move as in 3.7.1 or alternatively it may advance two squares along the same file, provided that both squares are unoccupied.
|
||||
for (int move = 1; move <= 2; move++) {
|
||||
nextPosition = nextPosition->NextTop();
|
||||
|
||||
if (nextPosition) {
|
||||
if (chessboard->IsEmptyField(nextPosition) == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (move == 1) {
|
||||
positions.insert(*nextPosition);
|
||||
} else if (move == 2 && this->IsFirstMove()) {
|
||||
positions.insert(*nextPosition);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 3.7.3. the pawn may move to a square occupied by an opponent's piece diagonally in front of it on an adjacent file, capturing that piece.
|
||||
for (std::string move : {"T1L1", "T1R1"}) {
|
||||
nextPosition = ¤tPosition;
|
||||
nextPosition = nextPosition->NextFromString(move);
|
||||
|
||||
if (nextPosition && chessboard->IsEmptyField(nextPosition) == false) {
|
||||
ChessPiece* chessPiece = chessboard->GetChessPiece(nextPosition);
|
||||
|
||||
if (chessPiece->GetColor() != this->GetColor()) {
|
||||
positions.insert(*nextPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3.7.3.1. A pawn occupying a square on the same rank as and on an adjacent file to an opponent's pawn which has just advanced two squares
|
||||
// in one move from its original square may capture this opponent's pawn as though the latter had been moved only one square.
|
||||
// 3.7.3.2. This capture is only legal on the move following this advance and is called an "en passant" capture.
|
||||
if (chessboard->GetCountMoves() > 0) {
|
||||
std::pair<ChessPiecePosition, ChessPiecePosition> lastMove = chessboard->GetLastMove();
|
||||
std::string moveDifference = ChessPiecePosition::GetDifference(lastMove.first, lastMove.second);
|
||||
ChessPiecePosition* leftPosition = currentPosition.NextLeft();
|
||||
ChessPiecePosition* rightPosition = currentPosition.NextRight();
|
||||
|
||||
if (leftPosition && chessboard->IsEmptyField(leftPosition) == false) {
|
||||
ChessPiece* chessPiece = chessboard->GetChessPiece(leftPosition);
|
||||
|
||||
if (chessPiece->GetColor() != this->GetColor() && chessPiece->IsPawn()) {
|
||||
if (chessPiece->GetNumberOfMoves() == 1 && moveDifference == "B2" && chessPiece->GetPosition() == lastMove.second) {
|
||||
ChessPiecePosition* topLeftPosition = currentPosition.NextFromString("T1L1");
|
||||
|
||||
if (topLeftPosition && chessboard->IsEmptyField(topLeftPosition)) {
|
||||
positions.insert(*topLeftPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rightPosition && chessboard->IsEmptyField(rightPosition) == false) {
|
||||
ChessPiece* chessPiece = chessboard->GetChessPiece(rightPosition);
|
||||
|
||||
if (chessPiece->GetColor() != this->GetColor() && chessPiece->IsPawn()) {
|
||||
if (chessPiece->GetNumberOfMoves() == 1 && moveDifference == "B2" && chessPiece->GetPosition() == lastMove.second) {
|
||||
ChessPiecePosition* topRightPosition = currentPosition.NextFromString("T1R1");
|
||||
|
||||
if (topRightPosition && chessboard->IsEmptyField(topRightPosition)) {
|
||||
positions.insert(*topRightPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return positions;
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
//
|
||||
// Created by hamac on 18.12.2024.
|
||||
//
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include "ChessUtils.h"
|
||||
|
||||
std::vector<std::string> ChessUtils::split(const std::string &s, char delim) {
|
||||
std::vector<std::string> elems;
|
||||
std::stringstream ss(s);
|
||||
std::string item;
|
||||
while (std::getline(ss, item, delim)) {
|
||||
elems.push_back(item);
|
||||
}
|
||||
return elems;
|
||||
}
|
||||
//a4
|
||||
std::pair<int, int> ChessUtils::convertPosition(const std::string &pos) {
|
||||
int y = pos[pos.size()-2] - 'a';
|
||||
int x = ChessUtils::fileConvertion.find((pos[pos.size()-1] - '0')-1)->second;
|
||||
return std::make_pair(x, y);
|
||||
}
|
34
ChessUtils.h
34
ChessUtils.h
@@ -1,34 +0,0 @@
|
||||
//
|
||||
// Created by hamac on 20.12.2024.
|
||||
//
|
||||
|
||||
#ifndef CHESSUTILS_H
|
||||
#define CHESSUTILS_H
|
||||
|
||||
//
|
||||
// Created by hamac on 18.12.2024.
|
||||
//
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
class ChessUtils {
|
||||
public:
|
||||
inline static const std::unordered_map<int, int> fileConvertion = {
|
||||
{0, 7},
|
||||
{1, 6},
|
||||
{2, 5},
|
||||
{3, 4},
|
||||
{4, 3},
|
||||
{5, 2},
|
||||
{6, 1},
|
||||
{7, 0}
|
||||
};
|
||||
static std::vector<std::string> split(const std::string &s, char delim);
|
||||
|
||||
static std::pair<int, int> convertPosition(const std::string &pos);
|
||||
};
|
||||
|
||||
#endif //CHESSUTILS_H
|
1025
Chessboard.cpp
1025
Chessboard.cpp
File diff suppressed because it is too large
Load Diff
143
Chessboard.h
143
Chessboard.h
@@ -1,143 +0,0 @@
|
||||
//
|
||||
// Created by hamac on 20.12.2024.
|
||||
//
|
||||
|
||||
#ifndef CHESSBOARD_H
|
||||
#define CHESSBOARD_H
|
||||
|
||||
#include "Chesspiece.h"
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
class Chessboard {
|
||||
private:
|
||||
/* Constants */
|
||||
// Chars to display board
|
||||
// Corners
|
||||
const std::string topLeft = "┌";
|
||||
const std::string topRight = "┐";
|
||||
const std::string bottomLeft = "└";
|
||||
const std::string bottomRight = "┘";
|
||||
|
||||
// Line chars
|
||||
const std::string horizontal = "─";
|
||||
const std::string vertical = "│";
|
||||
const std::string topIntersection = "┬";
|
||||
const std::string bottomIntersection = "┴";
|
||||
const std::string middleIntersection = "┼";
|
||||
|
||||
// White pieces
|
||||
const std::string whiteSquare = "□";
|
||||
const std::string whiteKing = "♔";
|
||||
const std::string whiteQueen = "♕";
|
||||
const std::string whiteRook = "♖";
|
||||
const std::string whiteBischop = "♗";
|
||||
const std::string whiteKnight = "♘";
|
||||
const std::string whitePawn = "♙";
|
||||
|
||||
// Black pieces
|
||||
const std::string blackSquare = "■";
|
||||
const std::string blackKing = "♚";
|
||||
const std::string blackQueen = "♛";
|
||||
const std::string blackRook = "♜";
|
||||
const std::string blackBischop = "♝";
|
||||
const std::string blackKnight = "♞";
|
||||
const std::string blackPawn = "♟";
|
||||
|
||||
/* class fields */
|
||||
std::vector<std::vector<char>> currentBoard;
|
||||
|
||||
std::unordered_map<char, std::vector<std::unique_ptr<Chesspiece>>> playingPieces;
|
||||
|
||||
// Starting formatting
|
||||
std::vector<std::vector<char>> startBoard = {
|
||||
{'r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'},
|
||||
{'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p'},
|
||||
{'w', 'x', 'w', 'x' ,'w', 'x', 'w', 'x'},
|
||||
{'x', 'w', 'x', 'w', 'x', 'w', 'x', 'w'},
|
||||
{'w', 'x', 'w', 'x' ,'w', 'x', 'w', 'x'},
|
||||
{'x', 'w', 'x', 'w', 'x', 'w', 'x', 'w'},
|
||||
{'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'},
|
||||
{'R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R'},
|
||||
};
|
||||
|
||||
// ToDo: Mathematisch sicherlich weg rationalisierbar
|
||||
std::vector<std::vector<char>> emptyBoard = {
|
||||
{'w', 'x', 'w', 'x' ,'w', 'x', 'w', 'x'},
|
||||
{'x', 'w', 'x', 'w', 'x', 'w', 'x', 'w'},
|
||||
{'w', 'x', 'w', 'x' ,'w', 'x', 'w', 'x'},
|
||||
{'x', 'w', 'x', 'w', 'x', 'w', 'x', 'w'},
|
||||
{'w', 'x', 'w', 'x' ,'w', 'x', 'w', 'x'},
|
||||
{'x', 'w', 'x', 'w', 'x', 'w', 'x', 'w'},
|
||||
{'w', 'x', 'w', 'x' ,'w', 'x', 'w', 'x'},
|
||||
{'x', 'w', 'x', 'w', 'x', 'w', 'x', 'w'}
|
||||
};
|
||||
|
||||
// Saves turn order; true = white and false = black
|
||||
bool turnOrder = true;
|
||||
|
||||
// ToDo: Max Size definieren?
|
||||
std::queue<std::string> queue;
|
||||
|
||||
/* methods */
|
||||
// Method returns unicode for chess icon depending on the identifier
|
||||
std::string getChessIcon(char identifier);
|
||||
|
||||
void generateTopLine();
|
||||
|
||||
void generatePlayingField(const std::vector<std::vector<char>>& chessboard);
|
||||
|
||||
void generateBottomLine();
|
||||
|
||||
public:
|
||||
/* fields */
|
||||
std::string display;
|
||||
int boardSize = 8;
|
||||
|
||||
/* methods */
|
||||
bool getTurnOrder();
|
||||
void setTurnOrder(bool turnOrder);
|
||||
|
||||
std::vector<std::vector<char>> getBoard();
|
||||
void setBoard(std::vector<std::vector<char>> board);
|
||||
|
||||
std::vector<std::vector<char>> getStartBoard();
|
||||
|
||||
std::vector<std::vector<char>> getEmptyBoard();
|
||||
|
||||
void draw ();
|
||||
|
||||
void draw (const std::vector<std::vector<char>>& chessboard);
|
||||
|
||||
// ToDo:
|
||||
// Methode um mögliche Züge anzuzeigen
|
||||
// Rochade
|
||||
// Mate
|
||||
// Schachmate
|
||||
// En Passond
|
||||
// Restlichen moves
|
||||
// Angabe mit Menü Optionen als Zahlen
|
||||
// Figuren wählen mit Schachnotation
|
||||
|
||||
void init();
|
||||
|
||||
void initPieces();
|
||||
|
||||
void move();
|
||||
|
||||
char getCorrectPiece(char pieceIdentifier);
|
||||
|
||||
//
|
||||
void move(std::string move);
|
||||
|
||||
// This method saves the current board state
|
||||
void saveBoard();
|
||||
|
||||
// This method loads a save state
|
||||
void loadBoard(std::string filepath);
|
||||
};
|
||||
|
||||
|
||||
#endif //CHESSBOARD_H
|
@@ -1,492 +0,0 @@
|
||||
#include "../Chessboard/Chessboard.hpp"
|
||||
#include "../ChessPieces/Rook.hpp"
|
||||
#include "../ChessPieces/Queen.hpp"
|
||||
#include "../ChessPieces/Bishop.hpp"
|
||||
#include "../ChessPieces/Knight.hpp"
|
||||
#include "../ChessPieces/ChessPieceMove.hpp"
|
||||
#include "../ChessPieces/ChessPiece.hpp"
|
||||
|
||||
void Chessboard::SetChessPiece(ChessPiece* chesspiece) {
|
||||
this->chessboard[chesspiece->GetPosition()] = chesspiece;
|
||||
}
|
||||
|
||||
bool Chessboard::IsEmptyField(ChessPiecePosition* position) {
|
||||
return (this->chessboard.count(*position) == 0);
|
||||
}
|
||||
|
||||
ChessPiece* Chessboard::GetChessPiece(ChessPiecePosition* position) {
|
||||
return this->chessboard.at(*position);
|
||||
}
|
||||
|
||||
void Chessboard::RemoveChessPiece(ChessPiecePosition position) {
|
||||
if (this->chessboard.count(position) == 1) {
|
||||
delete this->chessboard[position];
|
||||
this->chessboard.erase(position);
|
||||
}
|
||||
}
|
||||
|
||||
bool Chessboard::MoveCastling(ChessPieceColor color, bool shortCastling) {
|
||||
ChessPiecePosition fromPositionKing = (color == ChessPieceColor::White) ? ChessPiecePosition("E1") : ChessPiecePosition("E8");
|
||||
ChessPiecePosition fromPositionRook = (color == ChessPieceColor::White) ? ChessPiecePosition(shortCastling ? "H1" : "A1") : ChessPiecePosition(shortCastling ? "H8" : "A8");
|
||||
ChessPiecePosition toPositionKing = (color == ChessPieceColor::White) ? ChessPiecePosition(shortCastling ? "G1" : "C1") : ChessPiecePosition(shortCastling ? "G8" : "C8");
|
||||
ChessPiecePosition toPositionRook = (color == ChessPieceColor::White) ? ChessPiecePosition(shortCastling ? "F1" : "D1") : ChessPiecePosition(shortCastling ? "F8" : "D8");
|
||||
|
||||
ChessPiece* chessPieceRook = this->GetChessPiece(&fromPositionRook);
|
||||
ChessPiece* chessPieceKing = this->GetChessPiece(&fromPositionKing);
|
||||
|
||||
if (chessPieceKing == nullptr || chessPieceRook == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chessPieceKing->IsKing() == false || chessPieceRook->IsRook() == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chessPieceKing->IsFirstMove() == false || chessPieceRook->IsFirstMove() == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string step = ChessPiecePosition::GetStep(chessPieceKing->GetPosition(), toPositionKing);
|
||||
ChessPiecePosition currentPosition = chessPieceKing->GetPosition();
|
||||
ChessPiecePosition* nextPosition = ¤tPosition;
|
||||
while (nextPosition = nextPosition->NextFromString(step)) {
|
||||
if (this->IsEmptyField(nextPosition)) {
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
if (field.second->GetColor() != color) {
|
||||
if (field.second->GetNextPositions().count(*nextPosition) == 0) {
|
||||
continue;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nextPosition->ToString() == toPositionKing.ToString()) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
this->chessboard[toPositionKing] = chessPieceKing;
|
||||
this->chessboard.erase(chessPieceKing->GetPosition());
|
||||
this->SetToHistory(chessPieceKing->GetPosition(), toPositionKing);
|
||||
chessPieceKing->SetPosition(toPositionKing);
|
||||
this->chessboard[toPositionRook] = chessPieceRook;
|
||||
this->chessboard.erase(chessPieceRook->GetPosition());
|
||||
this->SetToHistory(chessPieceRook->GetPosition(), toPositionRook);
|
||||
chessPieceRook->SetPosition(toPositionRook);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Chessboard::MoveChessPiece(std::string move) {
|
||||
ChessPieceMove chessPieceMove = ChessPieceMove(move);
|
||||
|
||||
if (chessPieceMove.IsValidShortNotation() == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (chessPieceMove.IsShortCastling()) {
|
||||
this->MoveCastling(this->GetCurrentPlayer()->GetColor(), true);
|
||||
} else if (chessPieceMove.IsLongCastling()) {
|
||||
this->MoveCastling(this->GetCurrentPlayer()->GetColor(), false);
|
||||
} else if (chessPieceMove.IsDrawOffer()) {
|
||||
// Remis
|
||||
} else {
|
||||
ChessPiece* chessPiece = nullptr;
|
||||
ChessPiecePosition toChessPiecePosition = ChessPiecePosition(chessPieceMove.GetToPositionFile(), chessPieceMove.GetToPositionRank());
|
||||
char fromPositionFile = chessPieceMove.GetFromPositionFile();
|
||||
int fromPositionRank = chessPieceMove.GetFromPositionRank();
|
||||
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
if (field.second->GetColor() == this->GetCurrentPlayer()->GetColor()) {
|
||||
if (field.second->GetChar() == chessPieceMove.GetChessPieceChar() && field.second->GetNextPositions().count(toChessPiecePosition) == 1) {
|
||||
|
||||
if (fromPositionFile >= 'a' && fromPositionFile <= 'h') {
|
||||
if (field.second->GetPosition().GetFile() == std::toupper(fromPositionFile)) {
|
||||
chessPiece = field.second;
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (fromPositionRank >= 1 && fromPositionRank <= 8) {
|
||||
if (field.second->GetPosition().GetRank() == fromPositionRank) {
|
||||
chessPiece = field.second;
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
chessPiece = field.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chessPiece) {
|
||||
if (this->IsEmptyField(&toChessPiecePosition) == false) {
|
||||
this->RemoveChessPiece(toChessPiecePosition);
|
||||
this->chessboard[toChessPiecePosition] = this->chessboard[chessPiece->GetPosition()];
|
||||
this->chessboard.erase(chessPiece->GetPosition());
|
||||
this->SetToHistory(chessPiece->GetPosition(), toChessPiecePosition);
|
||||
chessPiece->SetPosition(toChessPiecePosition);
|
||||
} else {
|
||||
if (chessPiece->IsPawn()) {
|
||||
if (chessPiece->GetColor() == ChessPieceColor::White) {
|
||||
std::string difference = ChessPiecePosition::GetDifference(chessPiece->GetPosition(), toChessPiecePosition);
|
||||
|
||||
if (difference == "T1L1" || difference == "T1R1") {
|
||||
ChessPiecePosition currentPosition = toChessPiecePosition;
|
||||
ChessPiecePosition* nextPosition = ¤tPosition;
|
||||
|
||||
if (nextPosition = nextPosition->NextBottom()) {
|
||||
if (this->IsEmptyField(nextPosition) == false) {
|
||||
ChessPiece* chessPieceRemove = this->GetChessPiece(nextPosition);
|
||||
|
||||
if (chessPieceRemove->GetColor() != chessPiece->GetColor() && chessPieceRemove->IsPawn()) {
|
||||
this->chessboard[toChessPiecePosition] = this->chessboard[chessPiece->GetPosition()];
|
||||
this->chessboard.erase(chessPiece->GetPosition());
|
||||
this->SetToHistory(chessPiece->GetPosition(), toChessPiecePosition);
|
||||
chessPiece->SetPosition(toChessPiecePosition);
|
||||
this->RemoveChessPiece(chessPieceRemove->GetPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this->chessboard[toChessPiecePosition] = this->chessboard[chessPiece->GetPosition()];
|
||||
this->chessboard.erase(chessPiece->GetPosition());
|
||||
this->SetToHistory(chessPiece->GetPosition(), toChessPiecePosition);
|
||||
chessPiece->SetPosition(toChessPiecePosition);
|
||||
}
|
||||
} else if (chessPiece->GetColor() == ChessPieceColor::Black) {
|
||||
std::string difference = ChessPiecePosition::GetDifference(chessPiece->GetPosition(), toChessPiecePosition);
|
||||
|
||||
if (difference == "B1L1" || difference == "B1R1") {
|
||||
ChessPiecePosition currentPosition = toChessPiecePosition;
|
||||
ChessPiecePosition* nextPosition = ¤tPosition;
|
||||
|
||||
if (nextPosition = nextPosition->NextTop()) {
|
||||
if (this->IsEmptyField(nextPosition) == false) {
|
||||
ChessPiece* chessPieceRemove = this->GetChessPiece(nextPosition);
|
||||
|
||||
if (chessPieceRemove->GetColor() != chessPiece->GetColor() && chessPieceRemove->IsPawn()) {
|
||||
this->chessboard[toChessPiecePosition] = this->chessboard[chessPiece->GetPosition()];
|
||||
this->chessboard.erase(chessPiece->GetPosition());
|
||||
this->SetToHistory(chessPiece->GetPosition(), toChessPiecePosition);
|
||||
chessPiece->SetPosition(toChessPiecePosition);
|
||||
this->RemoveChessPiece(chessPieceRemove->GetPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this->chessboard[toChessPiecePosition] = this->chessboard[chessPiece->GetPosition()];
|
||||
this->chessboard.erase(chessPiece->GetPosition());
|
||||
this->SetToHistory(chessPiece->GetPosition(), toChessPiecePosition);
|
||||
chessPiece->SetPosition(toChessPiecePosition);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this->chessboard[toChessPiecePosition] = this->chessboard[chessPiece->GetPosition()];
|
||||
this->chessboard.erase(chessPiece->GetPosition());
|
||||
this->SetToHistory(chessPiece->GetPosition(), toChessPiecePosition);
|
||||
chessPiece->SetPosition(toChessPiecePosition);
|
||||
}
|
||||
}
|
||||
|
||||
if (chessPieceMove.GetPromotionChessPieceChar() != '\0') {
|
||||
ChessPieceColor color = chessPiece->GetColor();
|
||||
this->RemoveChessPiece(toChessPiecePosition);
|
||||
|
||||
switch (chessPieceMove.GetPromotionChessPieceChar()) {
|
||||
case 'R':
|
||||
this->chessboard[toChessPiecePosition] = new Rook(color, toChessPiecePosition);
|
||||
break;
|
||||
case 'B':
|
||||
this->chessboard[toChessPiecePosition] = new Bishop(color, toChessPiecePosition);
|
||||
break;
|
||||
case 'N':
|
||||
this->chessboard[toChessPiecePosition] = new Knight(color, toChessPiecePosition);
|
||||
break;
|
||||
case 'Q':
|
||||
this->chessboard[toChessPiecePosition] = new Queen(color, toChessPiecePosition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->UpdateChessPieces();
|
||||
this->SwitchCurrentPlayer();
|
||||
}
|
||||
|
||||
void Chessboard::SetToHistory(ChessPiecePosition fromPosition, ChessPiecePosition toPosition) {
|
||||
this->history.push_back({fromPosition, toPosition});
|
||||
}
|
||||
|
||||
int Chessboard::GetCountMoves() {
|
||||
return this->history.size();
|
||||
}
|
||||
|
||||
std::pair<ChessPiecePosition, ChessPiecePosition> Chessboard::GetLastMove() {
|
||||
return this->history.back();
|
||||
}
|
||||
|
||||
std::vector<ChessPiece*> Chessboard::GetChessPieces() {
|
||||
std::vector<ChessPiece*> chessPieces;
|
||||
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
chessPieces.push_back(field.second);
|
||||
}
|
||||
|
||||
return chessPieces;
|
||||
}
|
||||
|
||||
bool Chessboard::IsCheck() {
|
||||
ChessPiece* chessPieceKing = this->GetChessPieceKing(this->GetCurrentPlayer()->GetColor());
|
||||
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
if (field.second->GetColor() == this->GetOpponentPlayer()->GetColor()) {
|
||||
if (field.second->GetNextPositions().count(chessPieceKing->GetPosition()) == 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Chessboard::IsCheckmate() {
|
||||
|
||||
if (this->IsCheck() == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ChessPiece* chessPieceKing = this->GetChessPieceKing(this->GetCurrentPlayer()->GetColor());
|
||||
|
||||
if (chessPieceKing->GetNextPositions().size() > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int cntAttacker = 0;
|
||||
|
||||
for (ChessPiece* chessPieceOpponent : this->GetChessPieces()) {
|
||||
if (chessPieceOpponent->GetColor() == this->GetOpponentPlayer()->GetColor()) {
|
||||
if (chessPieceOpponent->GetNextPositions().count(chessPieceKing->GetPosition()) == 1) { // Is an attacker
|
||||
cntAttacker++;
|
||||
|
||||
bool deniable = false;
|
||||
|
||||
// remove attacker
|
||||
for (ChessPiece* chessPieceCurrent : this->GetChessPieces()) {
|
||||
if (chessPieceCurrent->GetColor() == this->GetCurrentPlayer()->GetColor()) {
|
||||
if (chessPieceCurrent->GetNextPositions().count(chessPieceOpponent->GetPosition()) == 1) {
|
||||
deniable = true; // blocked attack because current player can remove attacker
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deniable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// move between attacker and king
|
||||
// this is not possible for pawn, knight and king because they beat on next field.
|
||||
std::string step = ChessPiecePosition::GetStep(chessPieceOpponent->GetPosition(), chessPieceKing->GetPosition());
|
||||
|
||||
ChessPiecePosition currentPosition = chessPieceOpponent->GetPosition();
|
||||
ChessPiecePosition* nextPosition = ¤tPosition;
|
||||
|
||||
while (nextPosition = nextPosition->NextFromString(step)) {
|
||||
for (ChessPiece* chessPieceCurrent : this->GetChessPieces()) {
|
||||
if (chessPieceCurrent->GetColor() == this->GetCurrentPlayer()->GetColor()) {
|
||||
if (chessPieceCurrent->GetNextPositions().count(*nextPosition) == 1) {
|
||||
deniable = true; // blocked attack because current player can block between attacker and king
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deniable == false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cntAttacker > 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Chessboard::IsStalemate() {
|
||||
ChessPieceColor currentColor = this->GetCurrentPlayer()->GetColor();
|
||||
ChessPieceColor opponentColor = this->GetOpponentPlayer()->GetColor();
|
||||
ChessPiece* chessPieceKing;
|
||||
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
if (field.second->IsKing() && field.second->GetColor() == currentColor) {
|
||||
chessPieceKing = field.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Der König hat aber auch keine validen Züge mehr.
|
||||
if (chessPieceKing->GetNextPositions().size() > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Man hat selbst keine Figuren mehr welche noch ziehen könnten.
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
if (field.second->GetColor() == currentColor) {
|
||||
if (field.second->GetNextPositions().size() > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// König wird nicht direkt attackiert.
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
if (field.second->GetColor() == opponentColor) {
|
||||
if (field.second->GetNextPositions().count(chessPieceKing->GetPosition()) == 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current player.
|
||||
*/
|
||||
Player* Chessboard::GetCurrentPlayer() {
|
||||
return this->currentPlayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the opponent player.
|
||||
*/
|
||||
Player* Chessboard::GetOpponentPlayer() {
|
||||
if (this->GetCurrentPlayer()->GetColor() == ChessPieceColor::Black) {
|
||||
return this->GetPlayer(ChessPieceColor::White);
|
||||
} else {
|
||||
return this->GetPlayer(ChessPieceColor::Black);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a player by color.
|
||||
* @return Player* The player who is associated with the given color.
|
||||
*/
|
||||
Player* Chessboard::GetPlayer(ChessPieceColor color) {
|
||||
if (color == ChessPieceColor::Black) {
|
||||
return std::get<ChessPieceColor::Black>(this->players);
|
||||
} else {
|
||||
return std::get<ChessPieceColor::White>(this->players);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the players to the chessboard.
|
||||
* This function also determines the starting player.
|
||||
* @param Player* playerA The first player.
|
||||
* @param Player* playerB The second player.
|
||||
*/
|
||||
void Chessboard::SetPlayers(Player* playerA, Player* playerB) {
|
||||
std::random_device rngdevice;
|
||||
std::mt19937 generator(rngdevice());
|
||||
std::uniform_int_distribution<int> distr(0, 1);
|
||||
|
||||
if (distr(generator) == 0) { // 0 = A starts (white)
|
||||
this->players = {playerB, playerA};
|
||||
} else { // 1 = B starts (white)
|
||||
this->players = {playerA, playerB};
|
||||
}
|
||||
|
||||
this->GetPlayer(ChessPieceColor::White)->SetColor(ChessPieceColor::White);
|
||||
this->GetPlayer(ChessPieceColor::Black)->SetColor(ChessPieceColor::Black);
|
||||
this->currentPlayer = this->GetPlayer(ChessPieceColor::White);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch the current player.
|
||||
*/
|
||||
void Chessboard::SwitchCurrentPlayer() {
|
||||
if (this->GetCurrentPlayer()->GetColor() == ChessPieceColor::White) {
|
||||
this->currentPlayer = this->GetPlayer(ChessPieceColor::Black);
|
||||
} else {
|
||||
this->currentPlayer = this->GetPlayer(ChessPieceColor::White);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the next positions of all chess pieces.
|
||||
*/
|
||||
void Chessboard::UpdateChessPieces() {
|
||||
for (char chessPieceCode : {'B', 'N', 'P', 'Q', 'R', 'K'}) {
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
if (field.second->GetChar() == chessPieceCode) {
|
||||
field.second->UpdateNextPositions(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a given position is under attack.
|
||||
* @param ChessPiecePosition position The position which should be checked.
|
||||
* @param ChessPieceColor color The color that attacks (opponent color).
|
||||
* @return bool The status whether the given position is under attack.
|
||||
*/
|
||||
bool Chessboard::IsPositionUnderAttack(ChessPiecePosition position, ChessPieceColor color) {
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
if (field.second->IsPawn() == false && field.second->GetColor() == color && field.second->GetNextPositions().count(position) == 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
if (field.second->IsPawn() && field.second->GetColor() == color) {
|
||||
std::string difference = ChessPiecePosition::GetDifference(field.second->GetPosition(), position);
|
||||
if (color == ChessPieceColor::White && (difference == "T1L1" || difference == "T1R1")) {
|
||||
return true;
|
||||
} else if (color == ChessPieceColor::Black && (difference == "B1L1" || difference == "B1R1")) {
|
||||
return true;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Chessboard::~Chessboard() {
|
||||
delete this->players.first;
|
||||
delete this->players.second;
|
||||
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
delete field.second;
|
||||
}
|
||||
this->chessboard.clear();
|
||||
}
|
||||
|
||||
ChessPiece* Chessboard::GetChessPieceKing(ChessPieceColor color) {
|
||||
ChessPiece* chessPieceKing;
|
||||
|
||||
for (ChessPiece* chessPiece : this->GetChessPieces()) {
|
||||
if (chessPiece->IsKing() && chessPiece->GetColor() == color) {
|
||||
chessPieceKing = chessPiece;
|
||||
}
|
||||
}
|
||||
|
||||
return chessPieceKing;
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
#ifndef Chessboard_H
|
||||
#define Chessboard_H
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <random>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../Player/Player.hpp"
|
||||
#include "../ChessPieces/ChessPieceColor.hpp"
|
||||
#include "../ChessPieces/ChessPiecePosition.hpp"
|
||||
|
||||
class ChessPiece;
|
||||
|
||||
class Chessboard {
|
||||
private:
|
||||
std::map<ChessPiecePosition, ChessPiece*> chessboard;
|
||||
std::vector<std::pair<ChessPiecePosition, ChessPiecePosition>> history;
|
||||
std::pair<Player*, Player*> players;
|
||||
Player* currentPlayer;
|
||||
void RemoveChessPiece(ChessPiecePosition position);
|
||||
|
||||
public:
|
||||
~Chessboard();
|
||||
void SetChessPiece(ChessPiece* chesspiece);
|
||||
bool IsEmptyField(ChessPiecePosition* position);
|
||||
ChessPiece* GetChessPiece(ChessPiecePosition* position);
|
||||
std::vector<ChessPiece*> GetChessPieces();
|
||||
void UpdateChessPieces();
|
||||
void MoveChessPiece(std::string move);
|
||||
bool MoveCastling(ChessPieceColor color, bool shortCastling);
|
||||
void SetToHistory(ChessPiecePosition fromPosition, ChessPiecePosition toPosition);
|
||||
int GetCountMoves();
|
||||
std::pair<ChessPiecePosition, ChessPiecePosition> GetLastMove();
|
||||
bool IsCheckmate();
|
||||
bool IsCheck();
|
||||
bool IsStalemate();
|
||||
bool IsPositionUnderAttack(ChessPiecePosition position, ChessPieceColor color);
|
||||
Player* GetCurrentPlayer();
|
||||
Player* GetOpponentPlayer();
|
||||
void SetPlayers(Player* playerA, Player* playerB);
|
||||
void SwitchCurrentPlayer();
|
||||
Player* GetPlayer(ChessPieceColor color);
|
||||
ChessPiece* GetChessPieceKing(ChessPieceColor color);
|
||||
};
|
||||
|
||||
#endif
|
@@ -1 +0,0 @@
|
||||
#include "../Chessboard/ChessboardVisualizer.hpp"
|
@@ -1,168 +0,0 @@
|
||||
#include "../Chessboard/ChessboardVisualizerGraphic.hpp"
|
||||
#include "../ChessPieces/ChessPiecePosition.hpp"
|
||||
|
||||
void ChessboardVisualizerGraphic::SetConsoleColor(Colors foreground, Colors background) {
|
||||
const std::string SEQ_FOREGROUND = "\x1b[3";
|
||||
const std::string SEQ_FOREGROUND_LIGHT = "\x1b[9";
|
||||
const std::string SEQ_BACKGROUND = "\x1b[4";
|
||||
const std::string SEQ_BACKGROUND_LIGHT = "\x1b[10";
|
||||
|
||||
// set foreground color
|
||||
switch (foreground) {
|
||||
case BLACK:
|
||||
case RED:
|
||||
case GREEN:
|
||||
case YELLOW:
|
||||
case BLUE:
|
||||
case MAGENTA:
|
||||
case CYAN:
|
||||
case WHITE:
|
||||
std::cout << SEQ_FOREGROUND << foreground << "m";
|
||||
break;
|
||||
case LIGHT_BLACK:
|
||||
case LIGHT_RED:
|
||||
case LIGHT_GREEN:
|
||||
case LIGHT_YELLOW:
|
||||
case LIGHT_BLUE:
|
||||
case LIGHT_MAGENTA:
|
||||
case LIGHT_CYAN:
|
||||
case LIGHT_WHITE:
|
||||
std::cout << SEQ_FOREGROUND_LIGHT << foreground << "m";
|
||||
break;
|
||||
case DEFAULT:
|
||||
default:
|
||||
std::cout << SEQ_FOREGROUND << foreground << "m";
|
||||
break;
|
||||
}
|
||||
|
||||
// set background color
|
||||
switch (background) {
|
||||
case BLACK:
|
||||
case RED:
|
||||
case GREEN:
|
||||
case YELLOW:
|
||||
case BLUE:
|
||||
case MAGENTA:
|
||||
case CYAN:
|
||||
case WHITE:
|
||||
std::cout << SEQ_BACKGROUND << background << "m";
|
||||
break;
|
||||
case LIGHT_BLACK:
|
||||
case LIGHT_RED:
|
||||
case LIGHT_GREEN:
|
||||
case LIGHT_YELLOW:
|
||||
case LIGHT_BLUE:
|
||||
case LIGHT_MAGENTA:
|
||||
case LIGHT_CYAN:
|
||||
case LIGHT_WHITE:
|
||||
std::cout << SEQ_BACKGROUND_LIGHT << background << "m";
|
||||
break;
|
||||
case DEFAULT:
|
||||
default:
|
||||
std::cout << SEQ_BACKGROUND << background << "m";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ChessboardVisualizerGraphic::Draw(Chessboard* chessboard) {
|
||||
std::cout << "\033[2J"; // clear the console
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << " " << chessboard->GetPlayer(ChessPieceColor::White)->GetName() << " vs. " << chessboard->GetPlayer(ChessPieceColor::Black)->GetName();
|
||||
std::cout << std::endl;
|
||||
|
||||
for (int rank = 8; rank >= 1; rank--) {
|
||||
if (rank == 8) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (i == 0) {
|
||||
std::cout << " " << " " << " ";
|
||||
std::cout << "\u2554";
|
||||
}
|
||||
std::cout << "\u2550" << "\u2550" << "\u2550" << "\u2550" << "\u2550" << "\u2550" << "\u2550";
|
||||
if (i == 7) {
|
||||
std::cout << "\u2557";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (char file = 'A'; file <= 'H'; file++) {
|
||||
if (i == 1) {
|
||||
if (file == 'A') {
|
||||
std::cout << " " << rank << " ";
|
||||
std::cout << "\u2551";
|
||||
}
|
||||
} else {
|
||||
if (file == 'A') {
|
||||
std::cout << " " << " " << " ";
|
||||
std::cout << "\u2551";
|
||||
}
|
||||
}
|
||||
if (file % 2 == (rank % 2)) {
|
||||
this->SetConsoleColor(BLACK, WHITE);
|
||||
|
||||
if (i == 1) {
|
||||
ChessPiecePosition* position = new ChessPiecePosition(file, rank);
|
||||
|
||||
if (chessboard->IsEmptyField(position)) {
|
||||
std::cout << " ";
|
||||
} else {
|
||||
ChessPiece* piece = chessboard->GetChessPiece(position);
|
||||
std::cout << " " << piece->GetUnicode() << " ";
|
||||
}
|
||||
} else {
|
||||
std::cout << " ";
|
||||
}
|
||||
} else {
|
||||
this->SetConsoleColor(WHITE, BLACK);
|
||||
|
||||
if (i == 1) {
|
||||
ChessPiecePosition* position = new ChessPiecePosition(file, rank);
|
||||
|
||||
if (chessboard->IsEmptyField(position)) {
|
||||
std::cout << " ";
|
||||
} else {
|
||||
ChessPiece* piece = chessboard->GetChessPiece(position);
|
||||
std::cout << " " << piece->GetUnicode() << " ";
|
||||
}
|
||||
} else {
|
||||
std::cout << " ";
|
||||
}
|
||||
}
|
||||
if (file == 'H') {
|
||||
this->SetConsoleColor(DEFAULT, DEFAULT);
|
||||
std::cout << "\u2551";
|
||||
}
|
||||
}
|
||||
|
||||
this->SetConsoleColor(DEFAULT, DEFAULT);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
if (rank == 1) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (i == 0) {
|
||||
std::cout << " " << " " << " ";
|
||||
std::cout << "\u255A";
|
||||
}
|
||||
std::cout << "\u2550" << "\u2550" << "\u2550" << "\u2550" << "\u2550" << "\u2550" << "\u2550";
|
||||
if (i == 7) {
|
||||
std::cout << "\u255D";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
for (char file = 'A'; file <= 'H'; file++) {
|
||||
if (file == 'A') {
|
||||
std::cout << " ";
|
||||
std::cout << " ";
|
||||
}
|
||||
std::cout << " " << file << " ";
|
||||
if (file == 'H') {
|
||||
std::cout << " ";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
this->SetConsoleColor(DEFAULT, DEFAULT);
|
||||
std::cout << std::endl;
|
||||
}
|
@@ -1,21 +0,0 @@
|
||||
#ifndef ChessboardVisualizerGraphic_H
|
||||
#define ChessboardVisualizerGraphic_H
|
||||
|
||||
#include "../Chessboard/ChessboardVisualizer.hpp"
|
||||
|
||||
enum Colors {
|
||||
BLACK = 0, RED = 1, GREEN = 2, YELLOW = 3, BLUE = 4, MAGENTA = 5, CYAN = 6, WHITE = 7,
|
||||
LIGHT_BLACK = 10, LIGHT_RED = 11, LIGHT_GREEN = 12, LIGHT_YELLOW = 13, LIGHT_BLUE = 14,
|
||||
LIGHT_MAGENTA = 15, LIGHT_CYAN = 16, LIGHT_WHITE = 17, DEFAULT = 9
|
||||
};
|
||||
|
||||
class ChessboardVisualizerGraphic : public ChessboardVisualizer {
|
||||
private:
|
||||
void SetConsoleColor(Colors foreground, Colors background);
|
||||
|
||||
public:
|
||||
ChessboardVisualizerGraphic() = default;
|
||||
void Draw(Chessboard* chessboard);
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,91 +0,0 @@
|
||||
#include "../Chessboard/ChessboardVisualizerText.hpp"
|
||||
#include "../ChessPieces/ChessPiecePosition.hpp"
|
||||
|
||||
void ChessboardVisualizerText::Draw(Chessboard* chessboard) {
|
||||
std::cout << "\033[2J"; // clear the console
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << " " << chessboard->GetPlayer(ChessPieceColor::White)->GetName() << " vs. " << chessboard->GetPlayer(ChessPieceColor::Black)->GetName();
|
||||
std::cout << std::endl;
|
||||
|
||||
for (int rank = 8; rank >= 1; rank--) {
|
||||
if (rank == 8) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (i == 0) {
|
||||
std::cout << " " << " " << " ";
|
||||
std::cout << "\u250F";
|
||||
} else {
|
||||
std::cout << "\u2533";
|
||||
}
|
||||
std::cout << "\u2501" << "\u2501" << "\u2501";
|
||||
if (i == 7) {
|
||||
std::cout << "\u2513";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
for (char file = 'A'; file <= 'H'; file++) {
|
||||
if (file == 'A') { // Beginn der Zeile
|
||||
std::cout << " " << rank << " ";
|
||||
std::cout << "\u2503";
|
||||
}
|
||||
|
||||
ChessPiecePosition* position = new ChessPiecePosition(file, rank);
|
||||
|
||||
if (chessboard->IsEmptyField(position)) {
|
||||
std::cout << " " << " " << " ";
|
||||
} else {
|
||||
ChessPiece* piece = chessboard->GetChessPiece(position);
|
||||
std::cout << " " << piece->GetUnicode() << " ";
|
||||
}
|
||||
|
||||
std::cout << "\u2503";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
if (rank != 1) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (i == 0) {
|
||||
std::cout << " " << " " << " ";
|
||||
std::cout << "\u2523";
|
||||
} else {
|
||||
std::cout << "\u254B";
|
||||
}
|
||||
std::cout << "\u2501" << "\u2501" << "\u2501";
|
||||
if (i == 7) {
|
||||
std::cout << "\u252B";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
} else {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (i == 0) {
|
||||
std::cout << " " << " " << " ";
|
||||
std::cout << "\u2517";
|
||||
} else {
|
||||
std::cout << "\u253B";
|
||||
}
|
||||
std::cout << "\u2501" << "\u2501" << "\u2501";
|
||||
if (i == 7) {
|
||||
std::cout << "\u251B";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
for (char file = 'A'; file <= 'H'; file++) {
|
||||
if (file == 'A') {
|
||||
std::cout << " " << " " << " ";
|
||||
std::cout << " ";
|
||||
} else {
|
||||
std::cout << " ";
|
||||
}
|
||||
std::cout << " " << file << " ";
|
||||
if (file == 'H') {
|
||||
std::cout << " ";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
#ifndef ChessboardVisualizerText_H
|
||||
#define ChessboardVisualizerText_H
|
||||
|
||||
#include "../Chessboard/ChessboardVisualizer.hpp"
|
||||
|
||||
class ChessboardVisualizerText : public ChessboardVisualizer {
|
||||
private:
|
||||
void Clear();
|
||||
|
||||
public:
|
||||
ChessboardVisualizerText() = default;
|
||||
void Draw(Chessboard* chessboard);
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,25 +0,0 @@
|
||||
//
|
||||
// Created by hamac on 18.12.2024.
|
||||
//
|
||||
|
||||
#include "Chesspiece.h"
|
||||
|
||||
Chesspiece::Chesspiece(char color, std::pair<int, int> position)
|
||||
: color(color), position(position) {}
|
||||
|
||||
std::pair<int, int> Chesspiece::getPosition() { return this->position; };
|
||||
void Chesspiece::setPosition(std::pair<int, int> position) {
|
||||
this->position = position;
|
||||
//Chesspiece::calcAvaibleMoves(); // Brett -> Auswahl Figuren -> Züge gewählte
|
||||
}
|
||||
|
||||
char Chesspiece::getColor() { return color; }
|
||||
void Chesspiece::setColor(char color) { color = color; }
|
||||
|
||||
std::vector<std::string> Chesspiece::getAvaibleMoves() { return avaibleMoves; }
|
||||
|
||||
bool Chesspiece::checkNotation(std::string notation) {
|
||||
std::regex pattern("R^([KQRNBP]?)([a-h][1-8])[-x]([a-h][1-8])([+#]?)$");
|
||||
std::smatch match;
|
||||
return (std::regex_search(notation, match, pattern) ? true : false);
|
||||
}
|
46
Chesspiece.h
46
Chesspiece.h
@@ -1,46 +0,0 @@
|
||||
//
|
||||
// Created by hamac on 19.12.2024.
|
||||
//
|
||||
|
||||
#ifndef CHESSPIECE_H
|
||||
#define CHESSPIECE_H
|
||||
|
||||
//
|
||||
// Created by hamac on 18.12.2024.
|
||||
//
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <regex>
|
||||
|
||||
class Chesspiece {
|
||||
private:
|
||||
/* fields */
|
||||
// ToDo: von char auf enum Color {W, B} umstellen
|
||||
char color;
|
||||
char identifier; // P,K,...
|
||||
std::pair<int, int> position;
|
||||
// std::vector<std::pair<int, int>>
|
||||
std::vector<std::string> avaibleMoves;
|
||||
|
||||
/* methods */
|
||||
virtual std::vector<std::string> calcAvaibleMoves() = 0;
|
||||
|
||||
public:
|
||||
Chesspiece(char color, std::pair<int, int> position);
|
||||
|
||||
virtual ~Chesspiece() = default;
|
||||
|
||||
std::pair<int, int> getPosition();
|
||||
void setPosition(std::pair<int, int> position);
|
||||
|
||||
char getColor();
|
||||
void setColor(char color);
|
||||
|
||||
std::vector<std::string> getAvaibleMoves();
|
||||
|
||||
bool checkNotation(std::string notation);
|
||||
};
|
||||
|
||||
|
||||
#endif //CHESSPIECE_H
|
60
OldCode.txt
60
OldCode.txt
@@ -1,60 +0,0 @@
|
||||
void firstVersion() {
|
||||
const std::string white = "\u2B1C";
|
||||
const std::string black = "\u2B1B";
|
||||
|
||||
std::string brett[8][8];
|
||||
|
||||
std::string field;
|
||||
for (int y = 0; y < 8; y++) {
|
||||
for (int x = 0; x < 8; x++) {
|
||||
if (y % 2 == 0) {
|
||||
field = (x % 2 == 0) ? "\u2B1C" : "\u2B1B";
|
||||
}
|
||||
else {
|
||||
field = (x % 2 == 0) ? "⬛" : "⬜";
|
||||
}
|
||||
std::cout << field;
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void secondVersion() {
|
||||
//wchar_t t = 0x25FF;
|
||||
|
||||
// Horizontale Linie u2500
|
||||
// Vertikale Linie u2502
|
||||
// Top Right Corner u250C
|
||||
// Top Left Corner u2510
|
||||
// Bottom Right Corner u2514
|
||||
// Bottom Left Corner u2518
|
||||
|
||||
std::string topRightCorner = "\u2554";
|
||||
std::string topLeftCorner = "\u2557";
|
||||
std::string bottomLeftCorner = "\u255A";
|
||||
std::string bottomRightCorner = "\u255D";
|
||||
std::string horizontalLine = "\u2550\u2550";
|
||||
std::string verticalLine = "\u2551";
|
||||
std::string crossSuc = "\u256C";
|
||||
std::string leftSide = "\u2560";
|
||||
std::string rightSide = "\u2563";
|
||||
std::string topSide = "\u2566";
|
||||
std::string bottomSide = "\u2569";
|
||||
|
||||
std::string firstLine = "\u2554\u2550\u2566";
|
||||
std::string line;
|
||||
|
||||
for (int row = 0; row < 9; ++row) {
|
||||
for (int col = 0; col < 8; ++col) {
|
||||
if (row == 0 && col > 0) line += topSide + horizontalLine;
|
||||
if (row == 8 && col > 0) line += bottomSide + horizontalLine;
|
||||
if (col == 0 && row < 8 && row > 0) line += leftSide + horizontalLine;
|
||||
if (row > 0 && row < 8 && col > 0) line += crossSuc + horizontalLine;
|
||||
if (col == 7 && row < 8 && row > 0) line += rightSide;
|
||||
if (row == 0 && col == 0) line += topRightCorner + horizontalLine;
|
||||
if (row == 8 && col == 0) line += bottomLeftCorner + horizontalLine;
|
||||
if (row == 0 && col == 7) line += topLeftCorner + "\n" + verticalLine;
|
||||
if (row == 8 && col == 7) line += bottomRightCorner;
|
||||
}
|
||||
line += "\n";
|
||||
}
|
167
README.md
167
README.md
@@ -1,118 +1,69 @@
|
||||
# c/c++ Abschlussprojekt - Schach
|
||||
# TurboSchach
|
||||
|
||||
## Notwendige Umsetzungen
|
||||
## Kompilieren / Ausführen
|
||||
Für die Ausführung von TurboSchach sollte die Konsole / das Terminal im Vollbildmodus geöffnet sein. Durch ein zu kleines Terminal kann es zu Verschiebungen in der Benutzeroberfläche kommen. Um TurboSchach kompilieren zu können wird mindestens C++ 17 benötigt.
|
||||
|
||||
1. Klasse für Spielbrett
|
||||
2. Oberklasse für Spielfiguren
|
||||
1. Bauer
|
||||
2. Dame
|
||||
3. König
|
||||
4. Läufer
|
||||
5. Turm
|
||||
6. Springer
|
||||
3. Fancy User Interface
|
||||
4. Speicherung des Spielbretts
|
||||
5. Unentschieden anbieten
|
||||
6. Aufgegeben
|
||||
|
||||
### Spielbrett
|
||||
|
||||
- 8x8 Matrix
|
||||
- ANSI Linien checken
|
||||
- Unterscheidung von schwarzen und weißen Feldern
|
||||
- UTF-8 Spielfiguren
|
||||
- draw() Funktion
|
||||
- movement
|
||||
- Schachnotation
|
||||
- oder Klickbar?
|
||||
- Beschriftung des Spielbretts
|
||||
|
||||
### Spielfiguren
|
||||
|
||||
- Interface für Implementierung?
|
||||
- Default Felder:
|
||||
- Art der Figure
|
||||
- UTF-8 Code
|
||||
- Schlagen: Ich sehe dich nach movement Regeln -> Du stirbst
|
||||
- Bauer:
|
||||
- Movement: 1 Felder, außer bei Start 1-2 Felder
|
||||
- Schlagen: 1 Feld vor Diagonal
|
||||
- Spezialmove:
|
||||
- Beförderung
|
||||
- En Passent - Wie?
|
||||
- Dame:
|
||||
- Movement: Fuck it, i do what i want
|
||||
- König:
|
||||
- Movement: Körperklaus. Ich kann nur ein Feld nach überall
|
||||
- Spezialmove: Castlen
|
||||
- Läufer:
|
||||
- Movement: Die Diagnal ist mir
|
||||
- Turm:
|
||||
- Movement: Vertikal und Horizontal
|
||||
- Springer:
|
||||
- Movement: L-Bewegung (2 nach vorn + 1 nach links oder rechts); Krake
|
||||
- Spezial Moves:
|
||||
- Rochade -> Kurz/Lang
|
||||
- En Passant
|
||||
- Stalemate
|
||||
- Bauer: 2 Felder
|
||||
- Umwandeln
|
||||
|
||||
## Optional wenn Lust und Zeit?
|
||||
|
||||
1. Bedienung per Maus
|
||||
2. Multiplayer
|
||||
3. Historie der Spielzüge
|
||||
4. Gravejard der geschlagenen Figuren
|
||||
5. König platzieren -> Anzeigen wer gewinnt
|
||||
|
||||
# Gedankensammlung
|
||||
- Initialisierung:
|
||||
- Brett zeichnen
|
||||
- Figuren mit Zugmöglichkeiten ermitteln
|
||||
- Züge kalkulieren
|
||||
- Objekt mit allen Figuren erstellen -> alle Figuren initialisieren
|
||||
- Kalkulation der Züge
|
||||
- Anhand der aktuellen Position
|
||||
- Mit einbeziehen, dass Zug König nicht in Mate versetzt (verboten)
|
||||
- Sonder Züge, wie En passant, Rochade (Lang, Kurz), Bauern zwei Feld, beachten
|
||||
- Prüfen, ob andere Figuren im Weg stehen
|
||||
- Array von Linked Lists
|
||||
- Array Index steht für Richtung von Bewegungen (diagonalen, L, Gerade)
|
||||
- alles droppen, was nach pos mit Figur kommt
|
||||
|
||||
## Figuren
|
||||
|
||||
- Läufer (Bishop)
|
||||
- König (King)
|
||||
- Königin (Queen)
|
||||
- Turm (Rook)
|
||||
- Bauer (Pawn)
|
||||
- Pferd (Knight)
|
||||
|
||||
## ToDo
|
||||
- Speicherfunktion
|
||||
- Menü (ASCII Art of TurboSchach)
|
||||
- Startmenü
|
||||
- Spielmenü mit Historie, Kommand
|
||||
- Plattformunabhängiges CMD clearing vor dem Zeichnen
|
||||
|
||||
## Kompilieren und Ausführen
|
||||
|
||||
### Windows
|
||||
### Linux und MacOS
|
||||
|
||||
```
|
||||
g++ -o chess.exe main.cpp ChessPieces/*.cpp Chessboard/*.cpp Player/*.cpp
|
||||
# build
|
||||
make
|
||||
|
||||
# run
|
||||
make run
|
||||
```
|
||||
|
||||
### Microsoft Windows
|
||||
|
||||
```
|
||||
# build
|
||||
g++ -std=c++17 -o chess.exe main.cpp ChessPieces/*.cpp Chessboard/*.cpp Controller/*.cpp Player/*.cpp Visualizer/*.cpp
|
||||
|
||||
# run
|
||||
./chess.exe
|
||||
|
||||
# build and run (PowerShell)
|
||||
.\run
|
||||
```
|
||||
|
||||
### Linux
|
||||
## Algebraische Notation
|
||||
Um die Figuren auf dem Schachbrett zu bewegen, wird die kurze algebraische Notation nach [FIDE](https://handbook.fide.com/chapter/E012023) (siehe Appendix C) unterstützt. Es werden die Schachfiguren sowohl in deutscher als auch in englischer Sprache unterstützt.
|
||||
|
||||
```
|
||||
g++ -o chess main.cpp ChessPieces/*.cpp Chessboard/*.cpp Player/*.cpp
|
||||
./chess
|
||||
```
|
||||
| Schachfigur | Deutsch | Englisch |
|
||||
| ----------- | ------- | -------- |
|
||||
| Bauer (Pawn) | B | P |
|
||||
| Springer (Knight) | S | N |
|
||||
| Läufer (Bishop) | L | B |
|
||||
| Turm (Rook) | T | R |
|
||||
| Dame (Queen) | D | Q |
|
||||
| König (King) | K | K |
|
||||
|
||||
## Voraussetzungen
|
||||
Bei der kurzen Notation wird immer nur das Zielfeld eines Spielzuges genannt. Sollte der Ursprung nicht eindeutig sein kann auch die Spalte oder Zeile der zu bewegenden Figur genannt werden. So gibt der Spielzug `dxe5` an dass der Bauer in der Spalte D auf das Feld E5 zieht. Das `x` gibt an dass dabei eine Spielfigur des Gegeners geschlagen wird. Dies muss aber nicht zwingend angegeben werden.
|
||||
Der Bauer wird in den Spielzügen nicht benannt. Der Spielzug `b4` ist daher der Zug eines Bauern auf das Feld B4. Alle anderen Schachfiguren werden im Zug mit ihrem entsprechenden Buchstaben genannt. So gibt der Spielzug `Bc4` an dass der Läufer auf das Feld C4 gezogen wird.
|
||||
|
||||
- C++ 17
|
||||
### Beispiele
|
||||
|
||||
- `(=)` Draw: Das Draw wird dann aktiv wenn dieses im nächsten Spielzug vom Gegner bestätigt wird.
|
||||
- `b4` Der Bauer zieht auf das Feld B4.
|
||||
- `Bc4` Der Läufer zieht auf das Feld C4.
|
||||
- `0-0` Kleine Rochade (Rochade am Königsflügel)
|
||||
- `0-0-0` Große Rochade (Rochade am Damenflügel)
|
||||
- `d8Q` Umwandlung: Der Bauer zieht auf D8 und wandelt sich zur Dame.
|
||||
|
||||
## PGN (Portable Game Notation)
|
||||
TurboSchach unterstützt das Datenformat [PGN (Portable Game Notation)](https://www.saremba.de/chessgml/standards/pgn/pgn-complete.htm), welches zur Speicherung von Schachpartien verwendet wird. Auf der Website https://www.chessgames.com/ werden beispielsweise viele Schachpartien von offiziellen Turnieren im PGN-Format zur Verfügung gestellt. Diese Dateien können in TurboSchach importiert werden. Über den Menüpunkt 2 direkt nach dem Start der Anwendung ist dieser Import möglich.
|
||||
|
||||
Diese PGN-Dateien wurden auch zum Testen der Anwendung verwendet. Nachfolgend einige Schachspiele mit bestimmten Eigenschaften:
|
||||
|
||||
- [Jack Rudd vs Martin Simons](https://www.chessgames.com/perl/chessgame?gid=1588906) vom 09.08.2000 - Schachmatt
|
||||
- [Tim Jaksland vs Line Jin Jorgensen](https://www.chessgames.com/perl/chessgame?gid=1482551) vom 22.01.2008 - Schachmatt
|
||||
- [Gabriel Sargissian vs Nigel Short](https://www.chessgames.com/perl/chessgame?gid=1775611) vom 04.10.2014 - En Passant (`axb6`)
|
||||
- [Ulf Andersson vs Daniel Stellwagen](https://www.chessgames.com/perl/chessgame?gid=1427255) vom 27.08.2006 - En Passant (`bxc6+` und `dxe6`)
|
||||
- [Garry Kasparov vs Kiril Georgiev](https://www.chessgames.com/perl/chessgame?gid=1258478) vom 20.02.1988 - Stalemate
|
||||
- [Magnus Carlsen vs Hans Niemann](https://www.chessgames.com/perl/chessgame?gid=2821644) vom 31.12.2024
|
||||
|
||||
## Ausblick
|
||||
|
||||
- Multiplayer-Modus
|
||||
- Abspielen der Schachpartien (Schritt für Schritt) aus einer PGN-Datei
|
||||
- Anzeige der nächstmöglichen Züge bei Auswahl einer Figur
|
27
chessgames/Tests/1229276.pgn
Normal file
27
chessgames/Tests/1229276.pgn
Normal file
@@ -0,0 +1,27 @@
|
||||
[Event "Bosna 21st"]
|
||||
[Site "Sarajevo YUG"]
|
||||
[Date "1982.??.??"]
|
||||
[EventDate "1983.03.00"]
|
||||
[Round "?"]
|
||||
[Result "0-1"]
|
||||
[White "Vitomir Arapovic"]
|
||||
[Black "Alexander Beliavsky"]
|
||||
[ECO "C26"]
|
||||
[WhiteElo "?"]
|
||||
[BlackElo "?"]
|
||||
[PlyCount "150"]
|
||||
|
||||
1.e4 e5 2.Nc3 Nf6 3.Bc4 Bc5 4.d3 O-O 5.Nf3 Re8 6.Ng5 Re7 7.O-O
|
||||
h6 8.Nf3 c6 9.d4 exd4 10.e5 Ne8 11.Nxd4 d5 12.exd6 Nxd6 13.Bb3
|
||||
Na6 14.Be3 Qe8 15.Qf3 Bxd4 16.Bxd4 Nf5 17.Rad1 Bd7 18.Qh5 b6
|
||||
19.Qg6 Nxd4 20.Rxd4 Nc5 21.Bc4 Be6 22.Qg3 Bxc4 23.Rxc4 Rd8
|
||||
24.Rg4 f5 25.Rg6 Rd4 26.Rd6 f4 27.Qg6 Qxg6 28.Rxg6 Ne6 29.h4
|
||||
h5 30.g4 fxg3 31.Rxg3 Rf7 32.Re1 Nc5 33.Re8+ Kh7 34.Rg5 Rxh4
|
||||
35.b4 Nd7 36.Ne4 Nf6 37.Nxf6+ Rxf6 38.Re7 Rg6 39.Rxg6 Kxg6
|
||||
40.Re6+ Kh7 41.a3 Rc4 42.Re7 Rxc2 43.Rxa7 Rc4 44.Kg2 b5 45.Ra6
|
||||
g6 46.Ra8 Kh6 47.Rh8+ Kg5 48.Rg8 Kf5 49.Rf8+ Kg4 50.Rf6 g5
|
||||
51.Rf8 Rc3 52.Ra8 h4 53.a4 h3+ 54.Kh2 Rc2 55.Kg1 Rb2 56.axb5
|
||||
cxb5 57.Ra3 Kh4 58.Rd3 Rxb4 59.Kh2 g4 60.Rd5 Rb2 61.Kg1 Rb1+
|
||||
62.Kh2 Rf1 63.Rxb5 Rxf2+ 64.Kg1 Rc2 65.Rb4 Re2 66.Ra4 Kg3
|
||||
67.Ra1 Re3 68.Kh1 Kf3 69.Rf1+ Ke2 70.Rf8 g3 71.Kg1 Re4 72.Rh8
|
||||
Kf3 73.Rf8+ Rf4 74.Rg8 Rf7 75.Rh8 h2+ 0-1
|
29
chessgames/Tests/1258478.pgn
Normal file
29
chessgames/Tests/1258478.pgn
Normal file
@@ -0,0 +1,29 @@
|
||||
[Event "Wch-blitz"]
|
||||
[Site "Saint John CAN"]
|
||||
[Date "1988.02.20"]
|
||||
[EventDate "1988.02.19"]
|
||||
[Round "3"]
|
||||
[Result "1/2-1/2"]
|
||||
[White "Garry Kasparov"]
|
||||
[Black "Kiril Dimitrov Georgiev"]
|
||||
[ECO "A29"]
|
||||
[WhiteElo "2750"]
|
||||
[BlackElo "2595"]
|
||||
[PlyCount "155"]
|
||||
|
||||
1. c4 e5 2. Nc3 Nf6 3. Nf3 Nc6 4. g3 d5 5. cxd5 Nxd5 6. Bg2
|
||||
Nb6 7. O-O Be7 8. a3 a5 9. d3 O-O 10. Be3 Be6 11. Na4 Nd5
|
||||
12. Bc5 Bd6 13. Rc1 h6 14. Nd2 Rc8 15. Ne4 b6 16. Nxd6 cxd6
|
||||
17. Bxb6 Nxb6 18. Rxc6 Rb8 19. Nxb6 Rxb6 20. Qc2 Qb8 21. Rxb6
|
||||
Qxb6 22. Rb1 Bb3 23. Qd2 Rb8 24. Rc1 Be6 25. Rc2 d5 26. h4 a4
|
||||
27. Bf3 Qd4 28. e3 Qb6 29. d4 e4 30. Be2 Qb3 31. Kg2 g6
|
||||
32. Bd1 Kg7 33. Qc1 Qb6 34. Rd2 Bd7 35. Qc5 Qxc5 36. dxc5 Bc6
|
||||
37. Kf1 Kf6 38. Ke1 Ke5 39. Rc2 Rb5 40. Kd2 d4 41. exd4+ Kxd4
|
||||
42. Be2 Rxc5 43. Rxc5 Kxc5 44. Ke3 f5 45. g4 Kd5 46. gxf5 gxf5
|
||||
47.Kf4 Ke6 48. Bc4+ Kf6 49. b4 axb3 50. Bxb3 Bb5 51.a4 Ba6
|
||||
52.Bd5 Bc8 53.Bc6 Ke6 54.Bb5 Kd6 55. Bf1 Kc5 56.Bh3 Kb4
|
||||
57.Bxf5 Ba6 58.Bxe4 Kxa4 59.Ke5 Kb4 60. f4 Kc5 61.f5 Bc4 62.f6
|
||||
Bf7 63.Bf5 Kc6 64.Be6 Bg6 65.f7 Bxf7 66. Bxf7 Kd7 67.Kf6 Kd6
|
||||
68.h5 Kd7 69.Kg6 Ke7 70.Ba2 Ke8 71. Kxh6 Kf8 72.Kg6 Ke7 73.h6
|
||||
Kd6 74.h7 Kc5 75.h8=Q Kb4 76. Qd4+ Kb5 77.Bd5 Ka6 78.Qc5
|
||||
1/2-1/2
|
22
chessgames/Tests/1284086.pgn
Normal file
22
chessgames/Tests/1284086.pgn
Normal file
@@ -0,0 +1,22 @@
|
||||
[Event "Alicante"]
|
||||
[Site "Spain"]
|
||||
[Date "1992.??.??"]
|
||||
[EventDate "?"]
|
||||
[Round "7"]
|
||||
[Result "1/2-1/2"]
|
||||
[White "Stephen Boyd"]
|
||||
[Black "Torbjorn Glimbrant"]
|
||||
[ECO "C49"]
|
||||
[WhiteElo "2265"]
|
||||
[BlackElo "2235"]
|
||||
[PlyCount "91"]
|
||||
|
||||
1.e4 e5 2.Nf3 Nc6 3.Nc3 Nf6 4.Bb5 Bb4 5.O-O O-O 6.d3 d6 7.Bg5
|
||||
Bxc3 8.bxc3 Qe7 9.Re1 Nd8 10.d4 h6 11.Bc1 a6 12.Bd3 Bg4 13.h3
|
||||
Bd7 14.a4 a5 15.Nh4 Nc6 16.Nf5 Bxf5 17.exf5 Qd7 18.g4 exd4
|
||||
19.cxd4 Nxd4 20.Bb2 c5 21.Bxd4 cxd4 22.Bb5 Qc7 23.Qxd4 d5
|
||||
24.Re2 Rad8 25.Rae1 Rd6 26.Re7 Qxc2 27.Rxb7 Ne4 28.Re2 Qc1+
|
||||
29.Kg2 Qc8 30.Re7 Qd8 31.Qa7 Nf6 32.Rc7 d4 33.Ree7 d3 34.Rxf7
|
||||
Rxf7 35.Rxf7 d2 36.Rxg7+ Kh8 37.Be2 d1=Q 38.Bxd1 Rxd1 39.Rg6
|
||||
Qd5+ 40.Kg3 Rd3+ 41.Kh4 Rxh3+ 42.Kxh3 Qh1+ 43.Kg3 Nh5+ 44.gxh5
|
||||
Qf3+ 45.Kh2 Qg2+ 46.Kxg2 1/2-1/2
|
21
chessgames/Tests/1348060.pgn
Normal file
21
chessgames/Tests/1348060.pgn
Normal file
@@ -0,0 +1,21 @@
|
||||
[Event "Norwegian Championship"]
|
||||
[Site "Sandnes NOR"]
|
||||
[Date "2005.07.05"]
|
||||
[EventDate "2005.07.??"]
|
||||
[Round "5"]
|
||||
[Result "1-0"]
|
||||
[White "Magnus Carlsen"]
|
||||
[Black "Geir Sune Tallaksen Ostmoe"]
|
||||
[ECO "E15"]
|
||||
[WhiteElo "2528"]
|
||||
[BlackElo "2349"]
|
||||
[PlyCount "73"]
|
||||
|
||||
1. Nf3 Nf6 2. c4 e6 3. d4 b6 4. g3 Ba6 5. b3 b5 6. cxb5 Bxb5
|
||||
7. Bg2 d5 8. O-O Nbd7 9. Nc3 Ba6 10. Re1 Bd6 11. Bb2 O-O
|
||||
12. e4 Nxe4 13. Nxe4 dxe4 14. Rxe4 Bb7 15. Rh4 Be7 16. Rh3 Nf6
|
||||
17. Qe2 Bd5 18. Re1 Qb8 19. Ne5 Qb7 20. Bxd5 Qxd5 21. Qc2 c5
|
||||
22. Ng4 h6 23. Re5 Qf3 24. Nxh6+ gxh6 25. Rxh6 Kg7 26. Rg5+
|
||||
Kxh6 27. Bc1 cxd4 28. Rg4+ Qe3 29. Rh4+ Nh5 30. Rxh5+ Kxh5
|
||||
31. Qh7+ Kg4 32. fxe3 Rac8 33. Kg2 Rxc1 34. h3+ Kg5 35. Qg7+
|
||||
Kf5 36. g4+ Ke4 37. Qxd4# 1-0
|
31
chessgames/Tests/1427255.pgn
Normal file
31
chessgames/Tests/1427255.pgn
Normal file
@@ -0,0 +1,31 @@
|
||||
[Event "Youth - Experience"]
|
||||
[Site "Amsterdam NED"]
|
||||
[Date "2006.08.27"]
|
||||
[EventDate "2006.08.19"]
|
||||
[Round "8"]
|
||||
[Result "1/2-1/2"]
|
||||
[White "Ulf Andersson"]
|
||||
[Black "Daniel Stellwagen"]
|
||||
[ECO "A04"]
|
||||
[WhiteElo "2542"]
|
||||
[BlackElo "2575"]
|
||||
[PlyCount "175"]
|
||||
|
||||
1. Nf3 f5 2. d4 g6 3. g3 Bg7 4. Bg2 Nf6 5. O-O O-O 6. c4 d6
|
||||
7. Nc3 Qe8 8. d5 a5 9. Nd4 Na6 10. e4 fxe4 11. Nxe4 Nxe4
|
||||
12. Bxe4 Bh3 13. Re1 Nc5 14. Bh1 Qf7 15. Be3 Rae8 16. Qd2 b6
|
||||
17. b3 Kh8 18. Rad1 e5 19. dxe6 Nxe6 20. Bd5 Nxd4 21. Bxd4 Qd7
|
||||
22. a3 Bxd4 23. Qxd4+ Qg7 24. Qxg7+ Kxg7 25. Bc6 Rxe1+
|
||||
26. Rxe1 g5 27. f3 Bf5 28. Kf2 Kf6 29. b4 axb4 30. axb4 Be6
|
||||
31. Re4 Bf5 32. Rd4 Rf7 33. b5 Re7 34. Bd5 Be6 35. f4 Bxd5
|
||||
36. fxg5+ Kxg5 37. Rxd5+ Kg6 38. Kf3 Re1 39. h4 h5 40. Rg5+
|
||||
Kh6 41. g4 hxg4+ 42. Rxg4 Re5 43. Rd4 Rc5 44. Ke4 Kg6 45. Kd3
|
||||
Rh5 46. Rg4+ Kf6 47. Kd4 Ke6 48. Re4+ Kf6 49. Rg4 Ke6 50. Rf4
|
||||
Ke7 51. Ke4 Re5+ 52. Kf3 d5 53. Rd4 Re1 54. Rxd5 Rc1 55. Rd4
|
||||
Kf6 56. Ke4 Ke6 57. Kd3 Rd1+ 58. Kc3 Rc1+ 59. Kd2 Rh1 60. Re4+
|
||||
Kf6 61. Ke3 Rc1 62. Rg4 Kf5 63. Rg5+ Kf6 64. Kd4 Rh1 65. Rg4
|
||||
Ke6 66. Ke4 Re1+ 67. Kf3 Rc1 68. Ke3 Kf5 69. Rd4 Ke5 70. Rd5+
|
||||
Ke6 71. Kd3 Rd1+ 72. Ke4 Rh1 73. h5 Rh4+ 74. Kd3 Rh3+ 75. Kd4
|
||||
Rh4+ 76. Kc3 Rh3+ 77. Kb4 Rg3 78. Rd8 Rh3 79. Rh8 Kd7 80. h6
|
||||
c5+ 81. bxc6+ Kxc6 82. Rh7 Rh4 83. Kb3 Kc5 84. Rc7+ Kd6
|
||||
85. Rh7 Kc5 86. Rc7+ Kd6 87. Rb7 Kc6 88. Rh7 1/2-1/2
|
29
chessgames/Tests/1482551.pgn
Normal file
29
chessgames/Tests/1482551.pgn
Normal file
@@ -0,0 +1,29 @@
|
||||
[Event "Gibraltar Chess Festival"]
|
||||
[Site "Gibraltar ENG"]
|
||||
[Date "2008.01.23"]
|
||||
[EventDate "2008.01.22"]
|
||||
[Round "2"]
|
||||
[Result "1-0"]
|
||||
[White "Tim Jaksland"]
|
||||
[Black "Line Jin Jorgensen"]
|
||||
[ECO "C01"]
|
||||
[WhiteElo "2294"]
|
||||
[BlackElo "1867"]
|
||||
[PlyCount "149"]
|
||||
|
||||
1. e4 e6 2. d4 d5 3. exd5 exd5 4. Nf3 Nf6 5. Bd3 Bd6 6. O-O
|
||||
O-O 7. c4 c6 8. Nc3 Bg4 9. h3 Bh5 10. Re1 dxc4 11. Bxc4 Qc7
|
||||
12. g4 Bg6 13. Ne5 Nfd7 14. f4 Nxe5 15. dxe5 Bc5+ 16. Kg2 h6
|
||||
17. f5 Bh7 18. Qf3 Kh8 19. Bf4 b5 20. Bb3 Qb6 21. Rad1 a5
|
||||
22. a4 Ra7 23. Re2 b4 24. Ne4 Bd4 25. Rxd4 Qxd4 26. Rd2 Qb6
|
||||
27. Be3 Qc7 28. Bc5 Nd7 29. Rxd7 Qxd7 30. Bxf8 Qd4 31. Bc5
|
||||
Qxb2+ 32. Qf2 Qxf2+ 33. Kxf2 Rd7 34. Nd6 Bg8 35. Ke3 Re7
|
||||
36. Kf4 Rxe5 37. Kxe5 f6+ 38. Kd4 Bxb3 39. Bb6 Bxa4 40. Bxa5
|
||||
h5 41. gxh5 Bd1 42. h6 b3 43. hxg7+ Kxg7 44. Bc3 Kh6 45. Ke4
|
||||
Kh5 46. Bxf6 b2 47. Bxb2 Kh4 48. f6 Bb3 49. Ke5 Kxh3 50. f7
|
||||
Bxf7 51. Nxf7 c5 52. Nd6 c4 53. Kf4 c3 54. Bxc3 Kg2 55. Ne4
|
||||
Kh2 56. Kf3 Kg1 57. Nf2 Kh2 58. Be5+ Kg1 59. Bd6 Kf1 60. Bh2
|
||||
Ke1 61. Ne4 Kf1 62. Nd2+ Ke1 63. Ke3 Kd1 64. Kd3 Ke1 65. Bg3+
|
||||
Kd1 66. Bf2 Kc1 67. Nc4 Kd1 68. Nb2+ Kc1 69. Kc3 Kb1 70. Kb3
|
||||
Ka1 71. Be3 Kb1 72. Bf4 Ka1 73. Nc4 Kb1 74. Na3+ Ka1 75. Be5+
|
||||
1-0
|
18
chessgames/Tests/1588906.pgn
Normal file
18
chessgames/Tests/1588906.pgn
Normal file
@@ -0,0 +1,18 @@
|
||||
[Event "BCF-ch 87th"]
|
||||
[Site "Street ENG"]
|
||||
[Date "2000.08.09"]
|
||||
[EventDate "2000.07.31"]
|
||||
[Round "9"]
|
||||
[Result "0-1"]
|
||||
[White "Jack Rudd"]
|
||||
[Black "Martin Simons"]
|
||||
[ECO "B01"]
|
||||
[WhiteElo "2176"]
|
||||
[BlackElo "2226"]
|
||||
[PlyCount "40"]
|
||||
|
||||
1. e4 d5 2. exd5 Nf6 3. c4 e6 4. dxe6 Bxe6 5. d4 Bb4+ 6. Bd2
|
||||
Bxd2+ 7. Qxd2 Qe7 8. Qe2 Nc6 9. Nf3 O-O-O 10. d5 Rhe8 11. Kd1
|
||||
Nxd5 12. cxd5 Bxd5 13. Nfd2 Qf6 14. Qd3 Bxg2 15. Qg3 Bxh1
|
||||
16. Nc3 Bf3+ 17. Kc1 Re1+ 18. Kc2 Nd4+ 19. Kd3 Nb3+ 20. Kc2
|
||||
Nxa1# 0-1
|
21
chessgames/Tests/1775611.pgn
Normal file
21
chessgames/Tests/1775611.pgn
Normal file
@@ -0,0 +1,21 @@
|
||||
[Event "Isle of Man Masters"]
|
||||
[Site "Douglas IMN"]
|
||||
[Date "2014.10.11"]
|
||||
[EventDate "2014.10.04"]
|
||||
[Round "8.2"]
|
||||
[Result "0-1"]
|
||||
[White "Gabriel Sargissian"]
|
||||
[Black "Nigel Short"]
|
||||
[ECO "A70"]
|
||||
[WhiteElo "2690"]
|
||||
[BlackElo "2646"]
|
||||
[PlyCount "78"]
|
||||
|
||||
1. d4 Nf6 2. c4 e6 3. Nf3 c5 4. d5 exd5 5. cxd5 d6 6. Nc3 g6
|
||||
7. Bf4 a6 8. a4 Bg7 9. h3 O-O 10. e3 Ne8 11. Be2 Nd7 12. O-O
|
||||
Rb8 13. Nd2 Ne5 14. a5 f5 15. Bg3 Bd7 16. Qb3 b5 17. axb6 Rxb6
|
||||
18. Qc2 Bb5 19. Nxb5 axb5 20. Nb3 g5 21. Na5 f4 22. Bh2 Nc7
|
||||
23. Rfd1 Kh8 24. Qe4 Qf6 25. exf4 gxf4 26. Nb3 Na6 27. Nd2 c4
|
||||
28. Qb1 Nc5 29. Ne4 Nxe4 30. Qxe4 Rb7 31. Ra5 Nd7 32. b4 cxb3
|
||||
33. Bd3 Qh6 34. Qb4 Nc5 35. Bb1 Be5 36. Rxb5 Rg7 37. Be4 Nxe4
|
||||
38. Qxe4 Qxh3 39. Kh1 Qh5 0-1
|
19
chessgames/Tests/1799484.pgn
Normal file
19
chessgames/Tests/1799484.pgn
Normal file
@@ -0,0 +1,19 @@
|
||||
[Event "Russian Championship Superfinal"]
|
||||
[Site "Chita RUS"]
|
||||
[Date "2015.08.12"]
|
||||
[EventDate "2015.08.09"]
|
||||
[Round "4"]
|
||||
[Result "0-1"]
|
||||
[White "Peter Svidler"]
|
||||
[Black "Denis Khismatullin"]
|
||||
[ECO "B91"]
|
||||
[WhiteElo "2739"]
|
||||
[BlackElo "2642"]
|
||||
[PlyCount "58"]
|
||||
|
||||
1. e4 c5 2. Nc3 a6 3. Nge2 d6 4. g3 g6 5. d4 cxd4 6. Nxd4 Bg7
|
||||
7. Bg2 Nf6 8. b3 O-O 9. Bb2 Bd7 10. Qd2 Nc6 11. Nde2 b5
|
||||
12. O-O-O Ng4 13. Rdf1 Qa5 14. h3 Nf6 15. Kb1 b4 16. Nd1 Qc7
|
||||
17. Ne3 a5 18. f4 a4 19. e5 dxe5 20. fxe5 Nxe5 21. Bxa8 Rxa8
|
||||
22. Rf4 axb3 23. axb3 Qa7 24. Nd4 Nh5 25. Nd5 Bc6 26. Nxc6
|
||||
Qa2+ 27. Kc1 Qa1+ 28. Bxa1 Rxa1+ 29. Kb2 Nc4# 0-1
|
12
chessgames/save_games/20250116 - E gegen F - Runde 2.PGN
Normal file
12
chessgames/save_games/20250116 - E gegen F - Runde 2.PGN
Normal file
@@ -0,0 +1,12 @@
|
||||
[Event "Private Game"]
|
||||
[Site "Horb am Neckar, Germany"]
|
||||
[Date "2025.01.16"]
|
||||
[Round "2"]
|
||||
[White "E"]
|
||||
[Black "F"]
|
||||
[PlyCount "7"]
|
||||
[Result "*"]
|
||||
|
||||
|
||||
1. e3 e5 2. e4 f5 3. f3 g5
|
||||
4. g4 *
|
11
chessgames/save_games/20250116 - F gegen E - Runde 1
Normal file
11
chessgames/save_games/20250116 - F gegen E - Runde 1
Normal file
@@ -0,0 +1,11 @@
|
||||
[Event "Private Game"]
|
||||
[Site "Horb am Neckar, Germany"]
|
||||
[Date "2025.01.16"]
|
||||
[Round "1"]
|
||||
[White "F"]
|
||||
[Black "E"]
|
||||
[PlyCount "4"]
|
||||
[Result "*"]
|
||||
|
||||
|
||||
1. e3 e5 2. e4 f5 *
|
10
chessgames/save_games/20250116 - F gegen E - Runde 1.PGN
Normal file
10
chessgames/save_games/20250116 - F gegen E - Runde 1.PGN
Normal file
@@ -0,0 +1,10 @@
|
||||
[Event "Private Game"]
|
||||
[Site "Horb am Neckar, Germany"]
|
||||
[Date "2025.01.16"]
|
||||
[Round "1"]
|
||||
[White "F"]
|
||||
[Black "E"]
|
||||
[PlyCount "0"]
|
||||
[Result "*"]
|
||||
|
||||
*
|
@@ -0,0 +1,9 @@
|
||||
[Event "Private Game"]
|
||||
[Site "Horb am Neckar, Germany"]
|
||||
[Date "2025.01.16"]
|
||||
[Round "1"]
|
||||
[White "Player 1"]
|
||||
[Black "Player 2"]
|
||||
[PlyCount "0"]
|
||||
[Result "*"]
|
||||
*
|
@@ -0,0 +1,11 @@
|
||||
[Event "Private Game"]
|
||||
[Site "Horb am Neckar, Germany"]
|
||||
[Date "2025.01.16"]
|
||||
[Round "1"]
|
||||
[White "Player 2"]
|
||||
[Black "Player 1"]
|
||||
[PlyCount "3"]
|
||||
[Result "*"]
|
||||
|
||||
|
||||
1. e3 e6 2. f4 *
|
@@ -0,0 +1,11 @@
|
||||
[Event "Private Game"]
|
||||
[Site "Horb am Neckar, Germany"]
|
||||
[Date "2025.01.16"]
|
||||
[Round "1"]
|
||||
[White "Sebro"]
|
||||
[Black "Fabian"]
|
||||
[PlyCount "1"]
|
||||
[Result "*"]
|
||||
|
||||
|
||||
1. e3 *
|
2970
doc/Doxyfile
Normal file
2970
doc/Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
168
main.cpp
168
main.cpp
@@ -1,168 +0,0 @@
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <fstream>
|
||||
#include "Player/Player.hpp"
|
||||
#include "ChessPieces/Knight.hpp"
|
||||
#include "ChessPieces/Bishop.hpp"
|
||||
#include "ChessPieces/King.hpp"
|
||||
#include "ChessPieces/Pawn.hpp"
|
||||
#include "ChessPieces/Queen.hpp"
|
||||
#include "ChessPieces/Rook.hpp"
|
||||
#include "ChessPieces/ChessPiece.hpp"
|
||||
#include "Chessboard/Chessboard.hpp"
|
||||
#include "ChessPieces/ChessPiecePosition.hpp"
|
||||
#include "Chessboard/ChessboardVisualizerText.hpp"
|
||||
#include "Chessboard/ChessboardVisualizerGraphic.hpp"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
#ifdef _WIN32
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
#endif
|
||||
|
||||
std::cout << "Spieler A: ";
|
||||
std::string namePlayerA;
|
||||
getline(std::cin, namePlayerA);
|
||||
std::cout << "Spieler B: ";
|
||||
std::string namePlayerB;
|
||||
getline(std::cin, namePlayerB);
|
||||
|
||||
Player* playerA = new Player(namePlayerA);
|
||||
Player* playerB = new Player(namePlayerB);
|
||||
|
||||
Chessboard chessboard = Chessboard();
|
||||
chessboard.SetPlayers(playerA, playerB);
|
||||
|
||||
// set black chess pieces
|
||||
chessboard.SetChessPiece(new Rook{ChessPieceColor::Black, ChessPiecePosition{'A', 8}});
|
||||
chessboard.SetChessPiece(new Knight{ChessPieceColor::Black, ChessPiecePosition{'B', 8}});
|
||||
chessboard.SetChessPiece(new Bishop{ChessPieceColor::Black, ChessPiecePosition{'C', 8}});
|
||||
chessboard.SetChessPiece(new Queen{ChessPieceColor::Black, ChessPiecePosition{'D', 8}});
|
||||
chessboard.SetChessPiece(new King{ChessPieceColor::Black, ChessPiecePosition{'E', 8}});
|
||||
chessboard.SetChessPiece(new Bishop{ChessPieceColor::Black, ChessPiecePosition{'F', 8}});
|
||||
chessboard.SetChessPiece(new Knight{ChessPieceColor::Black, ChessPiecePosition{'G', 8}});
|
||||
chessboard.SetChessPiece(new Rook{ChessPieceColor::Black, ChessPiecePosition{'H', 8}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::Black, ChessPiecePosition{'A', 7}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::Black, ChessPiecePosition{'B', 7}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::Black, ChessPiecePosition{'C', 7}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::Black, ChessPiecePosition{'D', 7}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::Black, ChessPiecePosition{'E', 7}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::Black, ChessPiecePosition{'F', 7}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::Black, ChessPiecePosition{'G', 7}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::Black, ChessPiecePosition{'H', 7}});
|
||||
|
||||
// set white chess pieces
|
||||
chessboard.SetChessPiece(new Rook{ChessPieceColor::White, ChessPiecePosition{'A', 1}});
|
||||
chessboard.SetChessPiece(new Knight{ChessPieceColor::White, ChessPiecePosition{'B', 1}});
|
||||
chessboard.SetChessPiece(new Bishop{ChessPieceColor::White, ChessPiecePosition{'C', 1}});
|
||||
chessboard.SetChessPiece(new Queen{ChessPieceColor::White, ChessPiecePosition{'D', 1}});
|
||||
chessboard.SetChessPiece(new King{ChessPieceColor::White, ChessPiecePosition{'E', 1}});
|
||||
chessboard.SetChessPiece(new Bishop{ChessPieceColor::White, ChessPiecePosition{'F', 1}});
|
||||
chessboard.SetChessPiece(new Knight{ChessPieceColor::White, ChessPiecePosition{'G', 1}});
|
||||
chessboard.SetChessPiece(new Rook{ChessPieceColor::White, ChessPiecePosition{'H', 1}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::White, ChessPiecePosition{'A', 2}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::White, ChessPiecePosition{'B', 2}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::White, ChessPiecePosition{'C', 2}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::White, ChessPiecePosition{'D', 2}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::White, ChessPiecePosition{'E', 2}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::White, ChessPiecePosition{'F', 2}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::White, ChessPiecePosition{'G', 2}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::White, ChessPiecePosition{'H', 2}});
|
||||
|
||||
// Jetzt kann man Moves machen. Nach jedem Move müssen die ChessPieces aktualisiert werden.
|
||||
chessboard.UpdateChessPieces();
|
||||
|
||||
//ChessboardVisualizerText* visualizer = new ChessboardVisualizerText();
|
||||
ChessboardVisualizerGraphic* visualizer = new ChessboardVisualizerGraphic();
|
||||
visualizer->Draw(&chessboard);
|
||||
|
||||
// chessgames.com/1649097
|
||||
// https://www.chessgames.com/perl/chessgame?gid=1649097
|
||||
//
|
||||
//1258478 - Stalemate
|
||||
//std::ifstream input("C:\\Users\\Sebastian Brosch\\Desktop\\2767717.pgn");
|
||||
// std::ifstream input("C:\\Users\\Sebastian Brosch\\Desktop\\1258478.pgn");
|
||||
// //std::ifstream input("2767713.pgn");
|
||||
// //std::ifstream input("1482706.pgn");
|
||||
// //std::ifstream input("1693032.pgn");
|
||||
// //std::ifstream input("1272702.pgn");
|
||||
// //std::ifstream input("2446807.pgn");
|
||||
// //std::ifstream input("1884783.pgn");
|
||||
// std::regex moves_regex("([0-9]+.)(?:\n| )?([A-Za-z][A-Za-z0-9+#-=]+)(?:\n| )?([A-Za-z][A-Za-z0-9+#-]+)?");
|
||||
// std::smatch moves_matches;
|
||||
// std::string moves_content;
|
||||
// for (std::string line; getline(input, line);) {
|
||||
// if (line[0] == '[') {
|
||||
// // Info
|
||||
// } else {
|
||||
// moves_content.append((moves_content == "") ? "" : " ").append(line);
|
||||
// }
|
||||
// }
|
||||
// std::regex_search(moves_content, moves_matches, moves_regex);
|
||||
// std::vector<std::string> moves;
|
||||
|
||||
// for(std::sregex_iterator i = std::sregex_iterator(moves_content.begin(), moves_content.end(), moves_regex); i != std::sregex_iterator(); ++i) {
|
||||
// std::smatch m = *i;
|
||||
// if (m[2].str() != "") {
|
||||
// moves.push_back(m[2].str());
|
||||
// }
|
||||
// if (m[3].str() != "") {
|
||||
// moves.push_back(m[3].str());
|
||||
// }
|
||||
// }
|
||||
// int move_count = 0;
|
||||
// while (chessboard.IsCheckmate() == false) {
|
||||
// move_count++;
|
||||
// std::string move = moves.front();
|
||||
// moves.erase(moves.begin());
|
||||
// chessboard.MoveChessPiece(move);
|
||||
// visualizer->Draw(&chessboard);
|
||||
// std::cout << "SPIELZUG: " << move << " | " << move_count << std::endl;
|
||||
// if (moves.size() == 0) {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// std::cout << std::endl;
|
||||
// std::cout << "Game is over! - " << ((chessboard.GetOpponentPlayer()->GetColor() == ChessPieceColor::White) ? "White" : "Black") << " has won the game!" << std::endl;
|
||||
|
||||
// return 0;
|
||||
|
||||
|
||||
|
||||
while (chessboard.IsCheckmate() == false) {
|
||||
std::string move;
|
||||
std::cout << "Move [" << ((chessboard.GetCurrentPlayer()->GetColor() == ChessPieceColor::White) ? "White" : "Black") << "] : ";
|
||||
std::cin >> move;
|
||||
chessboard.MoveChessPiece(move);
|
||||
visualizer->Draw(&chessboard);
|
||||
}
|
||||
|
||||
std::cout << "Game is over! - " << chessboard.GetOpponentPlayer()->GetName() << " has won the game!" << std::endl;
|
||||
/**
|
||||
std::vector<std::vector<ChessPiece>> chessmatrix;
|
||||
|
||||
Chessboard chessboard;
|
||||
|
||||
if (argc == 2) {
|
||||
std::cout << "Spielstand" << std::endl;
|
||||
chessboard.loadBoard(std::string(argv[1]));
|
||||
} else {
|
||||
chessboard.setBoard(chessboard.getStartBoard());
|
||||
}
|
||||
|
||||
//chessboard.init();
|
||||
chessboard.draw();
|
||||
|
||||
while (true) {
|
||||
std::string move;
|
||||
std::cout << "Move [" << (chessboard.getTurnOrder() ? "white" : "black") << "]: ";
|
||||
std::cin >> move;
|
||||
|
||||
chessboard.move(move);
|
||||
chessboard.saveBoard();
|
||||
|
||||
}
|
||||
*/
|
||||
return 0;
|
||||
}
|
12
makefile
Normal file
12
makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
all:
|
||||
g++ -std=c++17 -o build/chess src/main.cpp src/ChessPieces/*.cpp src/Chessboard/*.cpp src/Controller/*.cpp src/Player/*.cpp src/Visualizer/*.cpp
|
||||
|
||||
run:
|
||||
./build/chess
|
||||
|
||||
clean:
|
||||
rm -f build/*
|
||||
rm -f -r doc/html
|
||||
|
||||
doc:
|
||||
doxygen doc/Doxyfile
|
4
run.ps1
4
run.ps1
@@ -1,2 +1,2 @@
|
||||
& "g++" -o chess main.cpp ChessPieces/*.cpp Chessboard/*.cpp Player/*.cpp
|
||||
./chess.exe
|
||||
& "g++" -std=c++17 -o build/chess.exe src/main.cpp src/ChessPieces/*.cpp src/Chessboard/*.cpp src/Controller/*.cpp src/Player/*.cpp src/Visualizer/*.cpp
|
||||
./build/chess.exe
|
3
run.sh
3
run.sh
@@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
g++ -o chess main.cpp ChessPieces/*.cpp Chessboard/*.cpp Player/*.cpp
|
||||
./chess
|
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"saves": [
|
||||
[
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[]
|
||||
],
|
||||
[
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[]
|
||||
],
|
||||
[
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[]
|
||||
]
|
||||
]
|
||||
}
|
@@ -5,13 +5,10 @@
|
||||
* @param move The move that uses the short algebraic notation.
|
||||
*/
|
||||
ChessPieceMove::ChessPieceMove(std::string move) {
|
||||
move = this->Normalize(move);
|
||||
this->_move = this->Normalize(move);
|
||||
|
||||
if (this->IsValidShortNotation(move)) {
|
||||
this->_move = move;
|
||||
if (this->IsValidShortNotation()) {
|
||||
this->ParseShortNotation();
|
||||
} else {
|
||||
throw std::invalid_argument("invalid move notation");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,3 +158,11 @@ bool ChessPieceMove::IsLongCastling() {
|
||||
bool ChessPieceMove::IsShortCastling() {
|
||||
return this->_castling == "0-0";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the move of the chess piece as string value.
|
||||
* @return The move of the chess piece as string value.
|
||||
*/
|
||||
std::string ChessPieceMove::ToString() {
|
||||
return (this->IsValidShortNotation()) ? this->_move : "";
|
||||
}
|
@@ -36,6 +36,7 @@ class ChessPieceMove {
|
||||
bool IsCheck();
|
||||
bool IsCheckmate();
|
||||
bool IsEnPassant();
|
||||
std::string ToString();
|
||||
};
|
||||
|
||||
#endif
|
@@ -34,7 +34,35 @@ std::set<ChessPiecePosition> King::GetNextPositions(Chessboard* chessboard, std:
|
||||
ChessPieceColor opponentColor = (this->GetColor() == ChessPieceColor::Black) ? ChessPieceColor::White : ChessPieceColor::Black;
|
||||
|
||||
if (chessboard->IsPositionUnderAttack(*nextPosition, opponentColor) == false) {
|
||||
positions.insert(*nextPosition);
|
||||
bool isUnderAttackAfterMove = false;
|
||||
|
||||
// Positions are ignored which are still under attack after the king has moved.
|
||||
// There are fields under attack which are in the shadow of the king.
|
||||
for (ChessPiece* chessPiece : chessboard->GetChessPieces()) {
|
||||
if (chessPiece && chessPiece->GetColor() != this->GetColor()) {
|
||||
if (chessPiece->GetNextPositions().count(this->GetPosition()) == 1) {
|
||||
if (chessPiece->IsPawn()) continue; // is checked by under attack
|
||||
|
||||
if (chessPiece->GetNextPositions(chessboard, {this->GetPosition(), *nextPosition}).count(*nextPosition) == 1) {
|
||||
isUnderAttackAfterMove = true;
|
||||
break;
|
||||
}
|
||||
} else if (chessPiece->IsKing()) {
|
||||
for (std::string nextMove : {"T1", "T1L1", "T1R1", "R1", "L1", "B1", "B1L1", "B1R1"}) {
|
||||
ChessPiecePosition* nextPositionKing = chessPiece->GetPosition().NextFromString(nextMove);
|
||||
|
||||
if (nextPositionKing && *nextPosition == *nextPositionKing) {
|
||||
isUnderAttackAfterMove = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isUnderAttackAfterMove == false) {
|
||||
positions.insert(*nextPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
96
src/ChessPieces/Pawn.cpp
Normal file
96
src/ChessPieces/Pawn.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#include "Pawn.hpp"
|
||||
|
||||
/**
|
||||
* Creates a new pawn with a specified color and position.
|
||||
* @param color The color of the pawn.
|
||||
* @param position The position of the pawn.
|
||||
*/
|
||||
Pawn::Pawn(ChessPieceColor color, ChessPiecePosition position) : ChessPiece(color, position) {
|
||||
this->_char = this->_CHAR_PAWN;
|
||||
this->_unicode = {"\u265F", "\u2659"};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all chess piece positions the pawn can move next.
|
||||
* The set of chess piece positions will be ignored, because the pawn has a fixed movement.
|
||||
* @param chessboard A pointer to the chessboard.
|
||||
* @param ignore A set of chess piece positions to be ignored.
|
||||
* @return A set of chess piece positions the pawn can move next.
|
||||
*/
|
||||
std::set<ChessPiecePosition> Pawn::GetNextPositions(Chessboard* chessboard, std::set<ChessPiecePosition> ignore) {
|
||||
std::set<ChessPiecePosition> positions;
|
||||
ChessPiecePosition currentPosition = this->GetPosition();
|
||||
ChessPiecePosition* nextPosition = ¤tPosition;
|
||||
std::vector<std::string> nextDiagonalPositions;
|
||||
std::string moveDifferenceOpponent;
|
||||
|
||||
if (this->GetColor() == ChessPieceColor::White) {
|
||||
nextDiagonalPositions = {"T1L1", "T1R1"};
|
||||
moveDifferenceOpponent = "B2";
|
||||
} else {
|
||||
nextDiagonalPositions = {"B1L1", "B1R1"};
|
||||
moveDifferenceOpponent = "T2";
|
||||
}
|
||||
|
||||
std::string stepVertical = nextDiagonalPositions[0].substr(0, 2);
|
||||
|
||||
// 3.7.1. The pawn may move forward to the square immediately in front of it on the same file, provided that this square is unoccupied.
|
||||
// 3.7.2. On its first move the pawn may move as in 3.7.1 or alternatively it may advance two squares along the same file, provided that both squares are unoccupied.
|
||||
for (int move = 1; move <= 2; move++) {
|
||||
if (nextPosition = nextPosition->NextFromString(stepVertical)) {
|
||||
if (chessboard->IsEmptyField(nextPosition) == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (move == 1 || (move == 2 && this->IsFirstMove())) {
|
||||
positions.insert(*nextPosition);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 3.7.3. the pawn may move to a square occupied by an opponent's piece diagonally in front of it on an adjacent file, capturing that piece.
|
||||
for (std::string moveDiagonal : nextDiagonalPositions) {
|
||||
nextPosition = ¤tPosition;
|
||||
nextPosition = nextPosition->NextFromString(moveDiagonal);
|
||||
|
||||
if (nextPosition && chessboard->IsEmptyField(nextPosition) == false) {
|
||||
ChessPiece* chessPiece = chessboard->GetChessPiece(nextPosition);
|
||||
|
||||
if (chessPiece->GetColor() != this->GetColor()) {
|
||||
positions.insert(*nextPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3.7.3.1. A pawn occupying a square on the same rank as and on an adjacent file to an opponent's pawn which has just advanced two squares
|
||||
// in one move from its original square may capture this opponent's pawn as though the latter had been moved only one square.
|
||||
// 3.7.3.2. This capture is only legal on the move following this advance and is called an "en passant" capture.
|
||||
if (chessboard->GetCountMoves() > 0) {
|
||||
std::pair<ChessPiecePosition, ChessPiecePosition> lastMovePositions = chessboard->GetLastMovePositions();
|
||||
std::string moveDifference = ChessPiecePosition::GetDifference(lastMovePositions.first, lastMovePositions.second);
|
||||
|
||||
for (std::string nextDiagonalPosition : nextDiagonalPositions) {
|
||||
nextPosition = ¤tPosition;
|
||||
std::string stepDiagonal = nextDiagonalPosition.substr(2, 2);
|
||||
nextPosition = nextPosition->NextFromString(stepDiagonal);
|
||||
|
||||
if (nextPosition && chessboard->IsEmptyField(nextPosition) == false) {
|
||||
ChessPiece* chessPiece = chessboard->GetChessPiece(nextPosition);
|
||||
|
||||
if (chessPiece->IsPawn() && chessPiece->GetColor() != this->GetColor()) {
|
||||
if (chessPiece->GetNumberOfMoves() == 1 && moveDifference == moveDifferenceOpponent && chessPiece->GetPosition() == lastMovePositions.second) {
|
||||
ChessPiecePosition* diagonalPosition = currentPosition.NextFromString(nextDiagonalPosition);
|
||||
|
||||
if (diagonalPosition && chessboard->IsEmptyField(diagonalPosition)) {
|
||||
positions.insert(*diagonalPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return positions;
|
||||
}
|
914
src/Chessboard/Chessboard.cpp
Normal file
914
src/Chessboard/Chessboard.cpp
Normal file
@@ -0,0 +1,914 @@
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <ctime>
|
||||
#include "../Chessboard/Chessboard.hpp"
|
||||
#include "../ChessPieces/Rook.hpp"
|
||||
#include "../ChessPieces/Queen.hpp"
|
||||
#include "../ChessPieces/Bishop.hpp"
|
||||
#include "../ChessPieces/Knight.hpp"
|
||||
#include "../ChessPieces/ChessPiece.hpp"
|
||||
#include "../ChessPieces/Knight.hpp"
|
||||
#include "../ChessPieces/Bishop.hpp"
|
||||
#include "../ChessPieces/King.hpp"
|
||||
#include "../ChessPieces/Pawn.hpp"
|
||||
#include "../ChessPieces/Queen.hpp"
|
||||
#include "../ChessPieces/Rook.hpp"
|
||||
|
||||
void Chessboard::SetStartingPosition() {
|
||||
|
||||
// black chess pieces
|
||||
this->SetChessPiece(new Rook(ChessPieceColor::Black, ChessPiecePosition("A8")));
|
||||
this->SetChessPiece(new Knight(ChessPieceColor::Black, ChessPiecePosition("B8")));
|
||||
this->SetChessPiece(new Bishop(ChessPieceColor::Black, ChessPiecePosition("C8")));
|
||||
this->SetChessPiece(new Queen(ChessPieceColor::Black, ChessPiecePosition("D8")));
|
||||
this->SetChessPiece(new King(ChessPieceColor::Black, ChessPiecePosition("E8")));
|
||||
this->SetChessPiece(new Bishop(ChessPieceColor::Black, ChessPiecePosition("F8")));
|
||||
this->SetChessPiece(new Knight(ChessPieceColor::Black, ChessPiecePosition("G8")));
|
||||
this->SetChessPiece(new Rook(ChessPieceColor::Black, ChessPiecePosition("H8")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::Black, ChessPiecePosition("A7")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::Black, ChessPiecePosition("B7")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::Black, ChessPiecePosition("C7")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::Black, ChessPiecePosition("D7")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::Black, ChessPiecePosition("E7")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::Black, ChessPiecePosition("F7")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::Black, ChessPiecePosition("G7")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::Black, ChessPiecePosition("H7")));
|
||||
|
||||
// white chess pieces
|
||||
this->SetChessPiece(new Rook(ChessPieceColor::White, ChessPiecePosition("A1")));
|
||||
this->SetChessPiece(new Knight(ChessPieceColor::White, ChessPiecePosition("B1")));
|
||||
this->SetChessPiece(new Bishop(ChessPieceColor::White, ChessPiecePosition("C1")));
|
||||
this->SetChessPiece(new Queen(ChessPieceColor::White, ChessPiecePosition("D1")));
|
||||
this->SetChessPiece(new King(ChessPieceColor::White, ChessPiecePosition("E1")));
|
||||
this->SetChessPiece(new Bishop(ChessPieceColor::White, ChessPiecePosition("F1")));
|
||||
this->SetChessPiece(new Knight(ChessPieceColor::White, ChessPiecePosition("G1")));
|
||||
this->SetChessPiece(new Rook(ChessPieceColor::White, ChessPiecePosition("H1")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::White, ChessPiecePosition("A2")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::White, ChessPiecePosition("B2")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::White, ChessPiecePosition("C2")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::White, ChessPiecePosition("D2")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::White, ChessPiecePosition("E2")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::White, ChessPiecePosition("F2")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::White, ChessPiecePosition("G2")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::White, ChessPiecePosition("H2")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current player.
|
||||
* @return A pointer to the current player.
|
||||
*/
|
||||
Player* Chessboard::GetCurrentPlayer() {
|
||||
return this->currentPlayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the history of all moves.
|
||||
* @return The history of all moves.
|
||||
*/
|
||||
std::vector<ChessPieceMove> Chessboard::GetHistoryMoves() {
|
||||
return this->_historyMoves;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the history of all positions.
|
||||
* @return The history of all positions.
|
||||
*/
|
||||
std::vector<std::pair<ChessPiecePosition, ChessPiecePosition>> Chessboard::GetHistoryPositions() {
|
||||
return this->_historyPositions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the opponent player.
|
||||
* @return A pointer to the opponent player.
|
||||
*/
|
||||
Player* Chessboard::GetOpponentPlayer() {
|
||||
if (this->GetCurrentPlayer()->GetColor() == ChessPieceColor::Black) {
|
||||
return this->GetPlayer(ChessPieceColor::White);
|
||||
} else {
|
||||
return this->GetPlayer(ChessPieceColor::Black);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a player by the specified color.
|
||||
* @return Player* A pointer to the player with the specified color.
|
||||
*/
|
||||
Player* Chessboard::GetPlayer(ChessPieceColor color) {
|
||||
if (color == ChessPieceColor::Black) {
|
||||
return std::get<ChessPieceColor::Black>(this->players);
|
||||
} else {
|
||||
return std::get<ChessPieceColor::White>(this->players);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Status whether moves have already been made.
|
||||
* @return Status whether moves have already been made.
|
||||
*/
|
||||
bool Chessboard::HasMoves() {
|
||||
return this->_historyMoves.size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the chessboard from a PGN file.
|
||||
* @param filePath The file path of the PGN file to load.
|
||||
* @return The status whether the PGN file was loaded successfully.
|
||||
*/
|
||||
std::string Chessboard::ImportFilePGN(std::string filePath) {
|
||||
std::ifstream pgnFile(filePath);
|
||||
std::regex rgxMetaInfo = std::regex("^[\\[]([A-Za-z]+) [\"](.*)[\"][\\]]$");
|
||||
std::regex rgxMoveInfo = std::regex("(?:([RNBQKP]?)([a-h]?)([1-8]?)(x?)([a-h])([1-8])((?:[=])?[QRBN])?|(O-O(?:-O)?)|(\\(=\\)))([+#!?]| e.p.)*");
|
||||
|
||||
if (pgnFile.is_open()) {
|
||||
Player* playerWhite;
|
||||
Player* playerBlack;
|
||||
int expectedNumberOfMoves = 0;
|
||||
std::vector<std::string> moves;
|
||||
|
||||
for(std::string line; getline(pgnFile, line);) {
|
||||
std::smatch parts;
|
||||
|
||||
if (std::regex_search(line, parts, rgxMetaInfo)) {
|
||||
std::string metaName = parts[1].str();
|
||||
std::string metaValue = parts[2].str();
|
||||
|
||||
if (metaName == "White") {
|
||||
playerWhite = new Player(metaValue);
|
||||
playerWhite->SetColor(ChessPieceColor::White);
|
||||
} else if (metaName == "Black") {
|
||||
playerBlack = new Player(metaValue);
|
||||
playerBlack->SetColor(ChessPieceColor::Black);
|
||||
} else if (metaName == "PlyCount") {
|
||||
expectedNumberOfMoves = std::stoi(metaValue);
|
||||
}
|
||||
} else {
|
||||
for (std::sregex_iterator rgxIterator = std::sregex_iterator(line.begin(), line.end(), rgxMoveInfo); rgxIterator != std::sregex_iterator(); ++rgxIterator) {
|
||||
parts = *rgxIterator;
|
||||
moves.push_back(parts[0].str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pgnFile.close();
|
||||
|
||||
// this was removed because it doesn't match all the time because of wrong data?
|
||||
// https://www.chessgames.com/nodejs/game/viewGamePGN?text=1&gid=2821644 (77 not 78)
|
||||
// if (expectedNumberOfMoves != moves.size()) {
|
||||
// return "moves doesn't match!";
|
||||
// }
|
||||
|
||||
this->players = {playerBlack, playerWhite};
|
||||
this->currentPlayer = playerWhite;
|
||||
|
||||
for (std::string move : moves) {
|
||||
std::string status = this->MoveChessPiece(move);
|
||||
if (status.empty() == false) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
} else {
|
||||
return "file not found!";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Status whether the king of the current player is in checkmate.
|
||||
* @return Status whether the king of the current player is in checkmate.
|
||||
*/
|
||||
bool Chessboard::IsCheckmate() {
|
||||
int numberOfAttackers = 0;
|
||||
|
||||
if (this->IsInCheck() == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ChessPiece* chessPieceKing = this->GetChessPieceKing(this->GetCurrentPlayer()->GetColor());
|
||||
|
||||
if (chessPieceKing == nullptr) {
|
||||
throw std::domain_error("king is missing");
|
||||
}
|
||||
|
||||
// it is not checkmate if the king can move to another position.
|
||||
if (chessPieceKing->GetNextPositions().size() > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ChessPiece* chessPieceOpponent : this->GetChessPieces()) {
|
||||
if (chessPieceOpponent->GetColor() == this->GetOpponentPlayer()->GetColor()) {
|
||||
if (chessPieceOpponent->GetNextPositions().count(chessPieceKing->GetPosition()) == 1) {
|
||||
bool isDefensibleAttack = false;
|
||||
numberOfAttackers++;
|
||||
|
||||
// the attacker can be removed directly by another chess piece.
|
||||
for (ChessPiece* chessPieceCurrent : this->GetChessPieces()) {
|
||||
if (chessPieceCurrent->GetColor() == this->GetCurrentPlayer()->GetColor()) {
|
||||
if (chessPieceCurrent->GetNextPositions().count(chessPieceOpponent->GetPosition()) == 1) {
|
||||
isDefensibleAttack = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the attacker is defensible.
|
||||
if (isDefensibleAttack == true) {
|
||||
std::cout << isDefensibleAttack << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if a chess piece can move between the attacker and king.
|
||||
std::string step = ChessPiecePosition::GetStep(chessPieceOpponent->GetPosition(), chessPieceKing->GetPosition());
|
||||
|
||||
// there is no direct way between attacker and king. so the attacker is the knight.
|
||||
// in this case we can not defend the attack by moving a chess piece between attacker and king.
|
||||
if (step.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ChessPiecePosition currentPosition = chessPieceOpponent->GetPosition();
|
||||
ChessPiecePosition* nextPosition = ¤tPosition;
|
||||
|
||||
while (nextPosition = nextPosition->NextFromString(step)) {
|
||||
if (*nextPosition == chessPieceKing->GetPosition()) break;
|
||||
|
||||
for (ChessPiece* chessPieceCurrent : this->GetChessPieces()) {
|
||||
if (chessPieceCurrent->GetColor() == this->GetCurrentPlayer()->GetColor()) {
|
||||
if (chessPieceCurrent->GetNextPositions().count(*nextPosition) == 1) {
|
||||
isDefensibleAttack = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isDefensibleAttack == false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return numberOfAttackers > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Status whether the king of the current player is in check.
|
||||
* @return Status whether the king of the current player is in check.
|
||||
*/
|
||||
bool Chessboard::IsInCheck() {
|
||||
ChessPieceColor currentPlayerColor = this->GetCurrentPlayer()->GetColor();
|
||||
ChessPiece* chessPieceKing = this->GetChessPieceKing(currentPlayerColor);
|
||||
|
||||
if (chessPieceKing == nullptr) {
|
||||
throw std::domain_error("king is missing");
|
||||
}
|
||||
|
||||
// 3.9 The king in check:
|
||||
// 3.9.1 The king is said to be "in check" if it is attacked by one or more of the opponent's pieces, even if such pieces are
|
||||
// constrained from moving to the square occupied by the king because they would then leave or place their own king in check.
|
||||
// 3.9.2 No piece can be moved that will either expose the king of the same colour to check or leave that king in check.
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
if (field.second->GetColor() == this->GetOpponentPlayer()->GetColor()) {
|
||||
if (field.second->GetNextPositions().count(chessPieceKing->GetPosition()) == 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Status whether the match ends with a draw because of stalemate.
|
||||
* @return Status whether the match ends with a draw because of stalemate.
|
||||
*/
|
||||
bool Chessboard::IsStalemate() {
|
||||
ChessPieceColor currentPlayerColor = this->GetCurrentPlayer()->GetColor();
|
||||
ChessPieceColor opponentPlayerColor = this->GetOpponentPlayer()->GetColor();
|
||||
ChessPiece* chessPieceKing = this->GetChessPieceKing(currentPlayerColor);
|
||||
|
||||
if (chessPieceKing == nullptr) {
|
||||
throw std::domain_error("king is missing");
|
||||
}
|
||||
|
||||
// 5.2.1 The game is drawn when the player to move has no legal move and his/her king is not in check.
|
||||
// The game is said to end in "stalemate". This immediately ends the game.
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
if (field.second->GetColor() == currentPlayerColor) {
|
||||
if (field.second->GetNextPositions().size() > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this->IsInCheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a chess piece on the chessboard.
|
||||
* If there is already a chess piece on the field, the chess piece will be deleted.
|
||||
* @param chesspiece A pointer to the chess piece which is to be set.
|
||||
*/
|
||||
void Chessboard::SetChessPiece(ChessPiece* chesspiece) {
|
||||
this->chessboard[chesspiece->GetPosition()] = chesspiece;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the move to the history.
|
||||
* @param move The move to be added to the history.
|
||||
*/
|
||||
void Chessboard::SetToHistory(ChessPieceMove move) {
|
||||
this->_historyMoves.push_back(move);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source and target position to the history.
|
||||
* @param fromPosition The source position to be added to the history.
|
||||
* @param toPosition The target position to be added to the history.
|
||||
*/
|
||||
void Chessboard::SetToHistory(ChessPiecePosition fromPosition, ChessPiecePosition toPosition) {
|
||||
this->_historyPositions.push_back({fromPosition, toPosition});
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches the current player.
|
||||
*/
|
||||
void Chessboard::SwitchCurrentPlayer() {
|
||||
this->currentPlayer = this->GetOpponentPlayer();
|
||||
}
|
||||
|
||||
void Chessboard::RemoveChessPiece(ChessPiecePosition position) {
|
||||
if (this->chessboard.count(position) == 1) {
|
||||
delete this->chessboard[position];
|
||||
this->chessboard.erase(position);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Chessboard::IsEmptyField(ChessPiecePosition* position) {
|
||||
return (this->chessboard.count(*position) == 0);
|
||||
}
|
||||
|
||||
ChessPiece* Chessboard::GetChessPiece(ChessPiecePosition* position) {
|
||||
return this->chessboard.at(*position);
|
||||
}
|
||||
|
||||
|
||||
bool Chessboard::IsDraw() {
|
||||
return this->draw.first == true && this->draw.second == true;
|
||||
}
|
||||
bool Chessboard::IsFinished() {
|
||||
return this->game_status.first == true || this->game_status.second == true;
|
||||
}
|
||||
|
||||
std::string Chessboard::MoveCastling(ChessPieceColor color, bool shortCastling) {
|
||||
ChessPiecePosition fromPositionKing = (color == ChessPieceColor::White) ? ChessPiecePosition("E1") : ChessPiecePosition("E8");
|
||||
ChessPiecePosition fromPositionRook = (color == ChessPieceColor::White) ? ChessPiecePosition(shortCastling ? "H1" : "A1") : ChessPiecePosition(shortCastling ? "H8" : "A8");
|
||||
ChessPiecePosition toPositionKing = (color == ChessPieceColor::White) ? ChessPiecePosition(shortCastling ? "G1" : "C1") : ChessPiecePosition(shortCastling ? "G8" : "C8");
|
||||
ChessPiecePosition toPositionRook = (color == ChessPieceColor::White) ? ChessPiecePosition(shortCastling ? "F1" : "D1") : ChessPiecePosition(shortCastling ? "F8" : "D8");
|
||||
|
||||
if (this->IsEmptyField(&fromPositionRook) || this->IsEmptyField(&fromPositionKing)) {
|
||||
return "Castling: Unknown chess piece position!";
|
||||
}
|
||||
|
||||
ChessPiece* chessPieceRook = this->GetChessPiece(&fromPositionRook);
|
||||
ChessPiece* chessPieceKing = this->GetChessPiece(&fromPositionKing);
|
||||
|
||||
if (chessPieceKing == nullptr || chessPieceRook == nullptr) {
|
||||
return "Castling: Chess pieces not found!";
|
||||
}
|
||||
|
||||
if (chessPieceKing->IsKing() == false || chessPieceRook->IsRook() == false) {
|
||||
return "Castling: Wrong chess pieces found!";
|
||||
}
|
||||
|
||||
if (chessPieceKing->IsFirstMove() == false || chessPieceRook->IsFirstMove() == false) {
|
||||
return "Castling: Chess pieces already moved!";
|
||||
}
|
||||
|
||||
std::string step = ChessPiecePosition::GetStep(chessPieceKing->GetPosition(), toPositionKing);
|
||||
ChessPiecePosition currentPosition = chessPieceKing->GetPosition();
|
||||
ChessPiecePosition* nextPosition = ¤tPosition;
|
||||
while (nextPosition = nextPosition->NextFromString(step)) {
|
||||
if (this->IsEmptyField(nextPosition)) {
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
if (field.second->GetColor() != color) {
|
||||
if (field.second->GetNextPositions().count(*nextPosition) == 0) {
|
||||
continue;
|
||||
} else {
|
||||
return "Castling: Field " + nextPosition->ToString() + " is under attack!";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nextPosition->ToString() == toPositionKing.ToString()) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return "Castling: Field " + nextPosition->ToString() + " is not empty!";
|
||||
}
|
||||
}
|
||||
|
||||
this->chessboard[toPositionKing] = chessPieceKing;
|
||||
this->chessboard.erase(chessPieceKing->GetPosition());
|
||||
this->SetToHistory(chessPieceKing->GetPosition(), toPositionKing);
|
||||
chessPieceKing->SetPosition(toPositionKing);
|
||||
this->chessboard[toPositionRook] = chessPieceRook;
|
||||
this->chessboard.erase(chessPieceRook->GetPosition());
|
||||
this->SetToHistory(chessPieceRook->GetPosition(), toPositionRook);
|
||||
chessPieceRook->SetPosition(toPositionRook);
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string Chessboard::MoveChessPiece(std::string move) {
|
||||
ChessPieceMove chessPieceMove = ChessPieceMove(move);
|
||||
|
||||
if (chessPieceMove.IsValidShortNotation() == false) {
|
||||
return move + " not valid!";
|
||||
}
|
||||
|
||||
// reset a started draw offer.
|
||||
if (this->draw.first == true && this->draw.second == false && chessPieceMove.IsDrawOffer() == false) {
|
||||
this->draw = {false, false};
|
||||
} else if (this->draw.second == true && this->draw.first == false && chessPieceMove.IsDrawOffer() == false) {
|
||||
this->draw = {false, false};
|
||||
}
|
||||
|
||||
if (chessPieceMove.IsShortCastling()) {
|
||||
std::string status = this->MoveCastling(this->GetCurrentPlayer()->GetColor(), true);
|
||||
this->draw = {false, false};
|
||||
if (status.empty() == false) {
|
||||
return status;
|
||||
}
|
||||
} else if (chessPieceMove.IsLongCastling()) {
|
||||
std::string status = this->MoveCastling(this->GetCurrentPlayer()->GetColor(), false);
|
||||
this->draw = {false, false};
|
||||
if (status.empty() == false) {
|
||||
return status;
|
||||
}
|
||||
} else if (chessPieceMove.IsDrawOffer()) {
|
||||
if (this->GetCurrentPlayer()->GetColor() == ChessPieceColor::White) {
|
||||
this->draw.second = true;
|
||||
} else {
|
||||
this->draw.first = true;
|
||||
}
|
||||
if (this->draw.first == true && this->draw.second == true) {
|
||||
this->game_status = {true, true};
|
||||
}
|
||||
} else {
|
||||
this->draw = {false, false};
|
||||
ChessPiece* chessPiece = nullptr;
|
||||
ChessPiecePosition toChessPiecePosition = ChessPiecePosition(chessPieceMove.GetToPositionFile(), chessPieceMove.GetToPositionRank());
|
||||
char fromPositionFile = chessPieceMove.GetFromPositionFile();
|
||||
int fromPositionRank = chessPieceMove.GetFromPositionRank();
|
||||
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
if (field.second->GetColor() == this->GetCurrentPlayer()->GetColor()) {
|
||||
if (field.second->GetChar() == chessPieceMove.GetChessPieceChar()) {
|
||||
if (field.second->GetNextPositions().count(toChessPiecePosition) == 1) {
|
||||
|
||||
if ((fromPositionFile >= 'a' && fromPositionFile <= 'h') && (fromPositionRank >= 1 && fromPositionRank <= 8)) {
|
||||
if ((field.second->GetPosition().GetFile() == std::toupper(fromPositionFile)) && (field.second->GetPosition().GetRank() == fromPositionRank)) {
|
||||
chessPiece = field.second;
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else if (fromPositionFile >= 'a' && fromPositionFile <= 'h') {
|
||||
if (field.second->GetPosition().GetFile() == std::toupper(fromPositionFile)) {
|
||||
chessPiece = field.second;
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else if (fromPositionRank >= 1 && fromPositionRank <= 8) {
|
||||
if (field.second->GetPosition().GetRank() == fromPositionRank) {
|
||||
chessPiece = field.second;
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
chessPiece = field.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chessPiece) {
|
||||
if (this->IsEmptyField(&toChessPiecePosition) == false) {
|
||||
this->RemoveChessPiece(toChessPiecePosition);
|
||||
this->chessboard[toChessPiecePosition] = this->chessboard[chessPiece->GetPosition()];
|
||||
this->chessboard.erase(chessPiece->GetPosition());
|
||||
this->SetToHistory(chessPiece->GetPosition(), toChessPiecePosition);
|
||||
chessPiece->SetPosition(toChessPiecePosition);
|
||||
} else {
|
||||
if (chessPiece->IsPawn()) {
|
||||
if (chessPiece->GetColor() == ChessPieceColor::White) {
|
||||
std::string difference = ChessPiecePosition::GetDifference(chessPiece->GetPosition(), toChessPiecePosition);
|
||||
|
||||
if (difference == "T1L1" || difference == "T1R1") {
|
||||
ChessPiecePosition currentPosition = toChessPiecePosition;
|
||||
ChessPiecePosition* nextPosition = ¤tPosition;
|
||||
|
||||
if (nextPosition = nextPosition->NextBottom()) {
|
||||
if (this->IsEmptyField(nextPosition) == false) {
|
||||
ChessPiece* chessPieceRemove = this->GetChessPiece(nextPosition);
|
||||
|
||||
if (chessPieceRemove->GetColor() != chessPiece->GetColor() && chessPieceRemove->IsPawn()) {
|
||||
this->chessboard[toChessPiecePosition] = this->chessboard[chessPiece->GetPosition()];
|
||||
this->chessboard.erase(chessPiece->GetPosition());
|
||||
this->SetToHistory(chessPiece->GetPosition(), toChessPiecePosition);
|
||||
chessPiece->SetPosition(toChessPiecePosition);
|
||||
this->RemoveChessPiece(chessPieceRemove->GetPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this->chessboard[toChessPiecePosition] = this->chessboard[chessPiece->GetPosition()];
|
||||
this->chessboard.erase(chessPiece->GetPosition());
|
||||
this->SetToHistory(chessPiece->GetPosition(), toChessPiecePosition);
|
||||
chessPiece->SetPosition(toChessPiecePosition);
|
||||
}
|
||||
} else if (chessPiece->GetColor() == ChessPieceColor::Black) {
|
||||
std::string difference = ChessPiecePosition::GetDifference(chessPiece->GetPosition(), toChessPiecePosition);
|
||||
|
||||
if (difference == "B1L1" || difference == "B1R1") {
|
||||
ChessPiecePosition currentPosition = toChessPiecePosition;
|
||||
ChessPiecePosition* nextPosition = ¤tPosition;
|
||||
|
||||
if (nextPosition = nextPosition->NextTop()) {
|
||||
if (this->IsEmptyField(nextPosition) == false) {
|
||||
ChessPiece* chessPieceRemove = this->GetChessPiece(nextPosition);
|
||||
|
||||
if (chessPieceRemove->GetColor() != chessPiece->GetColor() && chessPieceRemove->IsPawn()) {
|
||||
this->chessboard[toChessPiecePosition] = this->chessboard[chessPiece->GetPosition()];
|
||||
this->chessboard.erase(chessPiece->GetPosition());
|
||||
this->SetToHistory(chessPiece->GetPosition(), toChessPiecePosition);
|
||||
chessPiece->SetPosition(toChessPiecePosition);
|
||||
this->RemoveChessPiece(chessPieceRemove->GetPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this->chessboard[toChessPiecePosition] = this->chessboard[chessPiece->GetPosition()];
|
||||
this->chessboard.erase(chessPiece->GetPosition());
|
||||
this->SetToHistory(chessPiece->GetPosition(), toChessPiecePosition);
|
||||
chessPiece->SetPosition(toChessPiecePosition);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this->chessboard[toChessPiecePosition] = this->chessboard[chessPiece->GetPosition()];
|
||||
this->chessboard.erase(chessPiece->GetPosition());
|
||||
this->SetToHistory(chessPiece->GetPosition(), toChessPiecePosition);
|
||||
chessPiece->SetPosition(toChessPiecePosition);
|
||||
}
|
||||
}
|
||||
|
||||
if (chessPieceMove.GetPromotionChessPieceChar() != '\0') {
|
||||
ChessPieceColor color = chessPiece->GetColor();
|
||||
this->RemoveChessPiece(toChessPiecePosition);
|
||||
|
||||
switch (chessPieceMove.GetPromotionChessPieceChar()) {
|
||||
case 'R':
|
||||
this->chessboard[toChessPiecePosition] = new Rook(color, toChessPiecePosition);
|
||||
break;
|
||||
case 'B':
|
||||
this->chessboard[toChessPiecePosition] = new Bishop(color, toChessPiecePosition);
|
||||
break;
|
||||
case 'N':
|
||||
this->chessboard[toChessPiecePosition] = new Knight(color, toChessPiecePosition);
|
||||
break;
|
||||
case 'Q':
|
||||
this->chessboard[toChessPiecePosition] = new Queen(color, toChessPiecePosition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return "chess piece not found!";
|
||||
}
|
||||
}
|
||||
|
||||
this->SetToHistory(chessPieceMove);
|
||||
this->UpdateChessPieces();
|
||||
this->SwitchCurrentPlayer();
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
int Chessboard::GetCountMoves() {
|
||||
return this->_historyPositions.size();
|
||||
}
|
||||
|
||||
std::pair<ChessPiecePosition, ChessPiecePosition> Chessboard::GetLastMovePositions() {
|
||||
return this->_historyPositions.back();
|
||||
}
|
||||
|
||||
std::vector<ChessPiece*> Chessboard::GetChessPieces() {
|
||||
std::vector<ChessPiece*> chessPieces;
|
||||
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
chessPieces.push_back(field.second);
|
||||
}
|
||||
|
||||
return chessPieces;
|
||||
}
|
||||
|
||||
void Chessboard::SetPlayers(Player* playerA, Player* playerB) {
|
||||
this->players = {playerB, playerA};
|
||||
|
||||
this->GetPlayer(ChessPieceColor::White)->SetColor(ChessPieceColor::White);
|
||||
this->GetPlayer(ChessPieceColor::Black)->SetColor(ChessPieceColor::Black);
|
||||
this->currentPlayer = this->GetPlayer(ChessPieceColor::White);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the players to the chessboard.
|
||||
* This function also determines the starting player.
|
||||
* @param Player* playerA The first player.
|
||||
* @param Player* playerB The second player.
|
||||
*/
|
||||
void Chessboard::SetPlayersRdm(Player* playerA, Player* playerB) {
|
||||
std::random_device rngdevice;
|
||||
std::mt19937 generator(rngdevice());
|
||||
std::uniform_int_distribution<int> distr(0, 1);
|
||||
|
||||
if (distr(generator) == 0) { // 0 = A starts (white)
|
||||
this->players = {playerB, playerA};
|
||||
} else { // 1 = B starts (white)
|
||||
this->players = {playerA, playerB};
|
||||
}
|
||||
|
||||
this->GetPlayer(ChessPieceColor::White)->SetColor(ChessPieceColor::White);
|
||||
this->GetPlayer(ChessPieceColor::Black)->SetColor(ChessPieceColor::Black);
|
||||
this->currentPlayer = this->GetPlayer(ChessPieceColor::White);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update the next positions of all chess pieces.
|
||||
*/
|
||||
void Chessboard::UpdateChessPieces() {
|
||||
for (char chessPieceCode : {'B', 'N', 'P', 'Q', 'R', 'K'}) {
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
if (field.second->GetChar() == chessPieceCode) {
|
||||
field.second->UpdateNextPositions(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a given position is under attack.
|
||||
* @param ChessPiecePosition position The position which should be checked.
|
||||
* @param ChessPieceColor color The color that attacks (opponent color).
|
||||
* @return bool The status whether the given position is under attack.
|
||||
*/
|
||||
bool Chessboard::IsPositionUnderAttack(ChessPiecePosition position, ChessPieceColor color) {
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
if (field.second->IsPawn() == false && field.second->GetColor() == color && field.second->GetNextPositions().count(position) == 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
if (field.second->IsPawn() && field.second->GetColor() == color) {
|
||||
std::string difference = ChessPiecePosition::GetDifference(field.second->GetPosition(), position);
|
||||
if (color == ChessPieceColor::White && (difference == "T1L1" || difference == "T1R1")) {
|
||||
return true;
|
||||
} else if (color == ChessPieceColor::Black && (difference == "B1L1" || difference == "B1R1")) {
|
||||
return true;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Chessboard::~Chessboard() {
|
||||
delete this->players.first;
|
||||
delete this->players.second;
|
||||
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
delete field.second;
|
||||
}
|
||||
this->chessboard.clear();
|
||||
}
|
||||
|
||||
ChessPiece* Chessboard::GetChessPieceKing(ChessPieceColor color) {
|
||||
ChessPiece* chessPieceKing;
|
||||
|
||||
for (ChessPiece* chessPiece : this->GetChessPieces()) {
|
||||
if (chessPiece->IsKing() && chessPiece->GetColor() == color) {
|
||||
chessPieceKing = chessPiece;
|
||||
}
|
||||
}
|
||||
|
||||
return chessPieceKing;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Chessboard::ExportFilePGN(std::string filePath) {
|
||||
if (std::filesystem::exists(filePath)) {
|
||||
if (std::filesystem::is_directory(filePath)) {
|
||||
|
||||
filePath = this->GenerateExportFilePath(filePath);
|
||||
std::string player1 = this->GetPlayer(ChessPieceColor::White)->GetName();
|
||||
std::string player2 = this->GetPlayer(ChessPieceColor::Black)->GetName();
|
||||
std::string round;
|
||||
|
||||
// Regex-Pattern, um die Zahl nach "Runde " zu finden
|
||||
std::regex pattern(R"(\bRunde\s+(\d+))");
|
||||
std::smatch match;
|
||||
|
||||
if (std::regex_search(filePath, match, pattern)) {
|
||||
round = match[1]; // Die gefundene Zahl (Gruppe 1)
|
||||
}
|
||||
|
||||
std::ofstream file(filePath);
|
||||
if (file.is_open()) {
|
||||
file << GeneratePGNContent(GetTodaysDate("%Y.%m.%d"), player1, player2, round);
|
||||
file.close();
|
||||
} else {
|
||||
throw "File could not be created and opened";
|
||||
}
|
||||
} else {
|
||||
throw "Path exists but is not a directory";
|
||||
}
|
||||
} else {
|
||||
throw "Path could not be found";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Chessboard::GenerateExportFilePath(std::string& filePath) {
|
||||
if (this->GetCurrentSaveFilename().empty()) {
|
||||
std::string player1 = this->GetPlayer(ChessPieceColor::White)->GetName();
|
||||
std::string player2 = this->GetPlayer(ChessPieceColor::Black)->GetName();
|
||||
|
||||
std::string fileName = GetTodaysDate("%Y%m%d").append(" - ").append(player1).append(" gegen ").append(player2);
|
||||
|
||||
fileName.append(" - Runde ").append(GetRound(filePath, fileName));
|
||||
|
||||
this->SetCurrentSaveFilename(fileName);
|
||||
|
||||
filePath.append(fileName).append(".PGN");
|
||||
return filePath;
|
||||
} else {
|
||||
return filePath.append(this->GetCurrentSaveFilename()).append(".PGN");
|
||||
}
|
||||
}
|
||||
|
||||
std::string Chessboard::GetTodaysDate(std::string format) {
|
||||
// Hole aktuelle Zeit
|
||||
std::time_t now = std::time(nullptr);
|
||||
// Zerlege die Zeit in eine Struktur
|
||||
std::tm* localTime = std::localtime(&now);
|
||||
|
||||
// Formatiere das Datum
|
||||
std::ostringstream dateStream;
|
||||
dateStream << std::put_time(localTime, format.c_str());
|
||||
|
||||
return dateStream.str();
|
||||
}
|
||||
|
||||
// ToDo: Zählt noch nicht richtig
|
||||
std::string Chessboard::GetRound(const std::string& folderPath, const std::string& baseFileName) {
|
||||
size_t count = 0;
|
||||
|
||||
// Escape-Funktion für Regex
|
||||
auto escapeRegex = [](const std::string& str) {
|
||||
std::string escaped;
|
||||
for (char c : str) {
|
||||
if (std::string(".^$|()[]*+?\\").find(c) != std::string::npos) {
|
||||
escaped += '\\';
|
||||
}
|
||||
escaped += c;
|
||||
}
|
||||
return escaped;
|
||||
};
|
||||
|
||||
// Erstelle das Regex-Pattern
|
||||
std::string pattern = "^" + escapeRegex(baseFileName) + R"(\d+\.pgn$)";
|
||||
std::regex regexPattern(pattern, std::regex::icase); // Case-insensitive
|
||||
|
||||
std::cout << "Regex-Pattern: " << pattern << std::endl;
|
||||
|
||||
// Iteriere durch den Ordner
|
||||
for (const auto& entry : std::filesystem::directory_iterator(folderPath)) {
|
||||
if (entry.is_regular_file()) {
|
||||
std::string fileName = entry.path().filename().string();
|
||||
std::cout << "Prüfe Datei: " << fileName << std::endl;
|
||||
|
||||
if (std::regex_match(fileName, regexPattern)) {
|
||||
std::cout << "Datei passt: " << fileName << std::endl;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::to_string(count + 1);
|
||||
}
|
||||
|
||||
std::string Chessboard::GetWinner() {
|
||||
if (this->game_status.first == true && this->game_status.second == true) {
|
||||
return "";
|
||||
} else if (this->game_status.first == true) {
|
||||
return "Black";
|
||||
//return this->GetPlayer(ChessPieceColor::Black)->GetName();
|
||||
} else if (this->game_status.second == true) {
|
||||
return "White";
|
||||
//return this->GetPlayer(ChessPieceColor::White)->GetName();
|
||||
} else {
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
void Chessboard::SetWinner(Player* winner) {
|
||||
if (winner->GetColor() == ChessPieceColor::White) {
|
||||
this->game_status = {false, true};
|
||||
} else {
|
||||
this->game_status = {true, false};
|
||||
}
|
||||
}
|
||||
|
||||
std::string Chessboard::GeneratePGNContent(std::string today, std::string player1, std::string player2, std::string round) {
|
||||
return std::string("[Event \"Private Game\"]\n") // ersten vier werden nicht berücksichtigt
|
||||
.append("[Site \"Horb am Neckar, Germany\"]\n")
|
||||
.append("[Date \"").append(today).append("\"]\n")
|
||||
.append("[Round \"").append(round).append("\"]\n")
|
||||
.append("[White \"").append(player1).append("\"]\n")
|
||||
.append("[Black \"").append(player2).append("\"]\n")
|
||||
.append("[PlyCount \"").append(std::to_string(this->GetHistoryMoves().size())).append("\"]\n")
|
||||
.append("[Result \"").append(GetPGNResult()).append("\"]\n")
|
||||
.append("\n")
|
||||
.append(GenerateMoveList());
|
||||
}
|
||||
|
||||
std::string Chessboard::GenerateMoveList() {
|
||||
std::string result;
|
||||
std::vector<ChessPieceMove> moves = this->GetHistoryMoves();
|
||||
|
||||
if (this->HasMoves()) {
|
||||
for (size_t moveIndex = 0; moveIndex < moves.size() ; ++moveIndex) {
|
||||
if (moveIndex % 6 == 0) {
|
||||
result.append("\n");
|
||||
}
|
||||
if (moveIndex % 2 == 0) {
|
||||
result.append(std::to_string((moveIndex / 2) + 1)).append(".");
|
||||
}
|
||||
result.append(" ").append(moves[moveIndex].ToString()).append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
result.append(GetPGNResult());
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::pair<bool, bool> Chessboard::GetGameState() {
|
||||
return this->game_status;
|
||||
};
|
||||
|
||||
void Chessboard::SetGameState(std::pair<bool, bool> gameState) {
|
||||
this->game_status = gameState;
|
||||
};
|
||||
|
||||
std::string Chessboard::GetPGNResult() {
|
||||
std::pair<bool, bool> state = GetGameState();
|
||||
|
||||
if (state.first == true && state.second == true) {
|
||||
return std::string("1/2-1/2");
|
||||
} else if (state.first == true && state.second == false) {
|
||||
return std::string("0-1");
|
||||
} else if (state.first == false && state.second == true) {
|
||||
return std::string("1-0");
|
||||
} else {
|
||||
return std::string("*");
|
||||
}
|
||||
}
|
||||
|
||||
std::string Chessboard::GetCurrentSaveFilename() {
|
||||
return this->currentSaveFilename;
|
||||
}
|
||||
|
||||
void Chessboard::SetCurrentSaveFilename(std::string currentSaveFilename) {
|
||||
this->currentSaveFilename = currentSaveFilename;
|
||||
}
|
89
src/Chessboard/Chessboard.hpp
Normal file
89
src/Chessboard/Chessboard.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#ifndef Chessboard_H
|
||||
#define Chessboard_H
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <filesystem>
|
||||
#include "../Player/Player.hpp"
|
||||
#include "../ChessPieces/ChessPieceColor.hpp"
|
||||
#include "../ChessPieces/ChessPieceMove.hpp"
|
||||
#include "../ChessPieces/ChessPiecePosition.hpp"
|
||||
|
||||
class ChessPiece;
|
||||
|
||||
class Chessboard {
|
||||
private:
|
||||
inline static const std::string save_path = "chessgames/save_files/";
|
||||
|
||||
Player* winner = nullptr;
|
||||
std::string currentSaveFilename;
|
||||
|
||||
// false, false => Laufend
|
||||
// true, false => black win
|
||||
// false, true => white win
|
||||
// true, true => Draw/Stalmate
|
||||
std::pair<bool, bool> game_status = std::make_pair(false, false);
|
||||
|
||||
std::vector<ChessPieceMove> _historyMoves;
|
||||
std::vector<std::pair<ChessPiecePosition, ChessPiecePosition>> _historyPositions;
|
||||
std::map<ChessPiecePosition, ChessPiece*> chessboard;
|
||||
std::pair<Player*, Player*> players;
|
||||
std::pair<bool, bool> draw = std::make_pair(false, false);;
|
||||
Player* currentPlayer;
|
||||
void RemoveChessPiece(ChessPiecePosition position);
|
||||
|
||||
public:
|
||||
~Chessboard();
|
||||
std::vector<ChessPieceMove> GetHistoryMoves();
|
||||
std::vector<std::pair<ChessPiecePosition, ChessPiecePosition>> GetHistoryPositions();
|
||||
std::string GetTodaysDate(std::string format);
|
||||
void SetStartingPosition();
|
||||
void SetChessPiece(ChessPiece* chesspiece);
|
||||
bool IsDraw();
|
||||
bool IsEmptyField(ChessPiecePosition* position);
|
||||
ChessPiece* GetChessPiece(ChessPiecePosition* position);
|
||||
std::vector<ChessPiece*> GetChessPieces();
|
||||
void UpdateChessPieces();
|
||||
std::string MoveCastling(ChessPieceColor color, bool shortCastling);
|
||||
std::string MoveChessPiece(std::string move);
|
||||
void SetToHistory(ChessPieceMove move);
|
||||
void SetToHistory(ChessPiecePosition fromPosition, ChessPiecePosition toPosition);
|
||||
int GetCountMoves();
|
||||
bool HasMoves();
|
||||
std::pair<ChessPiecePosition, ChessPiecePosition> GetLastMovePositions();
|
||||
bool IsCheckmate();
|
||||
bool IsInCheck();
|
||||
bool IsStalemate();
|
||||
bool IsPositionUnderAttack(ChessPiecePosition position, ChessPieceColor color);
|
||||
Player* GetCurrentPlayer();
|
||||
Player* GetOpponentPlayer();
|
||||
void SetPlayersRdm(Player* playerA, Player* playerB);
|
||||
void SetPlayers(Player* playerA, Player* playerB);
|
||||
void SwitchCurrentPlayer();
|
||||
Player* GetPlayer(ChessPieceColor color);
|
||||
ChessPiece* GetChessPieceKing(ChessPieceColor color);
|
||||
std::string ImportFilePGN(std::string filePath);
|
||||
bool ExportFilePGN(std::string filePath);
|
||||
void SetWinner(Player* winner);
|
||||
std::string GeneratePGNContent(std::string today, std::string player1, std::string player2, std::string round);
|
||||
std::string GenerateMoveList();
|
||||
std::pair<bool, bool> GetGameState();
|
||||
void SetGameState(std::pair<bool, bool> gameState);
|
||||
std::string GetPGNResult();
|
||||
std::string GetRound(const std::string& folderPath, const std::string& baseFileName);
|
||||
std::string GetCurrentSaveFilename();
|
||||
void SetCurrentSaveFilename(std::string currentSaveFileName);
|
||||
std::string GenerateExportFilePath(std::string& filePath);
|
||||
std::string GetWinner();
|
||||
bool IsFinished();
|
||||
};
|
||||
|
||||
#endif
|
1
src/Chessboard/ChessboardVisualizer.cpp
Normal file
1
src/Chessboard/ChessboardVisualizer.cpp
Normal file
@@ -0,0 +1 @@
|
||||
//#include "../Chessboard/ChessboardVisualizer.hpp"
|
@@ -1,4 +1,4 @@
|
||||
#ifndef ChessboardVisualizer_H
|
||||
/*#ifndef ChessboardVisualizer_H
|
||||
#define ChessboardVisualizer_H
|
||||
|
||||
#include "../ChessPieces/ChessPiece.hpp"
|
||||
@@ -10,4 +10,4 @@ class ChessboardVisualizer {
|
||||
virtual void Draw(Chessboard* chessboard) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif*/
|
254
src/Controller/MenuController.cpp
Normal file
254
src/Controller/MenuController.cpp
Normal file
@@ -0,0 +1,254 @@
|
||||
#include "MenuController.hpp"
|
||||
#include "../Player/Player.hpp"
|
||||
#include "../Visualizer/BaseVisualizer.hpp"
|
||||
#include "../Visualizer/InstructionsVisualizer.hpp"
|
||||
#include "../Visualizer/ImportVisualizer.hpp"
|
||||
#include "../Visualizer/PlayingViewVisualizer.hpp"
|
||||
#include "../Visualizer/PlaySelectVisualizer.hpp"
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
MenuController::MenuController() {
|
||||
// Konstruktor, falls nötig
|
||||
}
|
||||
|
||||
MenuController::~MenuController() {
|
||||
// Destruktor, falls nötig
|
||||
}
|
||||
|
||||
void MenuController::HandlePlayingNavigation(std::string choice, Chessboard& chessboard, PlayingViewVisualizer& playView, bool isGameOver) {
|
||||
if (choice.empty() == false) {
|
||||
if (choice.at(0) == '$') {
|
||||
if (choice == "$0") {
|
||||
return;
|
||||
} else if (choice == "$1") {
|
||||
HandleThirdOption();
|
||||
} else if (choice == "$2") {
|
||||
chessboard.ExportFilePGN("chessgames/save_games/");
|
||||
} else if (choice == "$3") {
|
||||
if (isGameOver) {
|
||||
playView.SetMessage("Game is over! No moves allowed.");
|
||||
} else {
|
||||
chessboard.SetWinner(chessboard.GetOpponentPlayer());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isGameOver) {
|
||||
playView.SetMessage("Game is over! No moves allowed.");
|
||||
} else {
|
||||
playView.SetMessage(chessboard.MoveChessPiece(choice));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MenuController::HandleFirstOption() {
|
||||
PlaySelectVisualizer playerSelect(3);
|
||||
|
||||
std::string choiceA;
|
||||
std::string choiceB;
|
||||
|
||||
do {
|
||||
playerSelect.SetLabelPlayerName("first player");
|
||||
choiceA = playerSelect.ShowMenu();
|
||||
|
||||
if (choiceA.length() > 40) {
|
||||
choiceA.clear();
|
||||
}
|
||||
} while (choiceA.empty());
|
||||
|
||||
do {
|
||||
playerSelect.SetLabelPlayerName("second player");
|
||||
choiceB = playerSelect.ShowMenu();
|
||||
|
||||
if (choiceB.length() > 40) {
|
||||
choiceB.clear();
|
||||
};
|
||||
} while (choiceB.empty());
|
||||
|
||||
// Spieler initialisieren
|
||||
Player* playerA = new Player(choiceA);
|
||||
Player* playerB = new Player(choiceB);
|
||||
|
||||
// Schachbrett initialisieren
|
||||
Chessboard chessboard;
|
||||
chessboard.SetPlayersRdm(playerA, playerB);
|
||||
chessboard.SetStartingPosition();
|
||||
chessboard.UpdateChessPieces();
|
||||
|
||||
SetChessboard(&chessboard);
|
||||
|
||||
PlayingViewVisualizer playView(&chessboard, 4, 12);
|
||||
|
||||
std::string choiceChessboard;
|
||||
|
||||
do {
|
||||
while (!chessboard.IsCheckmate() && !chessboard.IsStalemate() && !chessboard.IsDraw() && chessboard.IsFinished() == false) {
|
||||
choiceChessboard = playView.ShowMenu();
|
||||
this->HandlePlayingNavigation(choiceChessboard, chessboard, playView, false);
|
||||
}
|
||||
|
||||
std::string winner = chessboard.GetWinner();
|
||||
choiceChessboard = "$0";
|
||||
|
||||
if (winner.empty()) {
|
||||
playView.SetMessage("Game is over! - Draw");
|
||||
} else {
|
||||
playView.SetMessage("Game is over! - " + winner + " has won the game!");
|
||||
}
|
||||
} while (choiceChessboard != "$0");
|
||||
|
||||
do {
|
||||
choiceChessboard = playView.ShowMenu();
|
||||
this->HandlePlayingNavigation(choiceChessboard, chessboard, playView, true);
|
||||
} while (choiceChessboard != "$0");
|
||||
|
||||
|
||||
// while (!chessboard.IsCheckmate() && !chessboard.IsStalemate() && !chessboard.IsDraw() && chessboard.IsFinished() == false) {
|
||||
// playView.DisplayElement();
|
||||
|
||||
// std::string input;
|
||||
// std::cout << "\x1B[u"; // Cursor-Positionierung
|
||||
// std::cin >> input;
|
||||
|
||||
// std::string command = ExtractAfterDollar(input);
|
||||
// if (!command.empty()) {
|
||||
// HandleCommandOptions(command);
|
||||
// if (command == "0") {
|
||||
// return;
|
||||
// }
|
||||
// } else {
|
||||
// std::string status = chessboard.MoveChessPiece(input);
|
||||
// if (status.empty() == false) {
|
||||
// playView.SetMessage(status);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// std::string winner = chessboard.GetWinner();
|
||||
|
||||
// if (winner.empty()) {
|
||||
// playView.SetMessage("Game is over! - Draw");
|
||||
// } else {
|
||||
// playView.SetMessage("Game is over! - " + winner + " has won the game!");
|
||||
// }
|
||||
|
||||
// while (true) {
|
||||
// playView.DisplayElement();
|
||||
// std::string input;
|
||||
// std::cout << "\x1B[u"; // Cursor-Positionierung
|
||||
// std::cin >> input;
|
||||
|
||||
// std::string command = ExtractAfterDollar(input);
|
||||
// if (command == "0") {
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
void MenuController::HandleSecondOption() {
|
||||
ImportVisualizer importSelect;
|
||||
|
||||
std::string filePath;
|
||||
|
||||
do {
|
||||
filePath = importSelect.ShowMenu();
|
||||
|
||||
if (std::filesystem::exists(filePath) == false) {
|
||||
filePath.clear();
|
||||
}
|
||||
} while (filePath.empty());
|
||||
|
||||
Chessboard chessboard;
|
||||
chessboard.SetStartingPosition();
|
||||
chessboard.UpdateChessPieces();
|
||||
SetChessboard(&chessboard);
|
||||
|
||||
std::string status = chessboard.ImportFilePGN(filePath);
|
||||
|
||||
PlayingViewVisualizer playView(&chessboard, 4, 12);
|
||||
playView.SetMessage(status);
|
||||
std::string choiceChessboard;
|
||||
|
||||
do {
|
||||
while (!chessboard.IsCheckmate() && !chessboard.IsStalemate() && !chessboard.IsDraw() && chessboard.IsFinished() == false) {
|
||||
choiceChessboard = playView.ShowMenu();
|
||||
this->HandlePlayingNavigation(choiceChessboard, chessboard, playView, false);
|
||||
}
|
||||
|
||||
std::string winner = chessboard.GetWinner();
|
||||
choiceChessboard = "$0";
|
||||
|
||||
if (winner.empty()) {
|
||||
playView.SetMessage("Game is over! - Draw");
|
||||
} else {
|
||||
playView.SetMessage("Game is over! - " + winner + " has won the game!");
|
||||
}
|
||||
} while (choiceChessboard != "$0");
|
||||
|
||||
do {
|
||||
choiceChessboard = playView.ShowMenu();
|
||||
this->HandlePlayingNavigation(choiceChessboard, chessboard, playView, true);
|
||||
} while (choiceChessboard != "$0");
|
||||
}
|
||||
|
||||
// ToDo:: Hier muss aus irgendeinem Grund immer zweimal die Eingabe abgeschickt werden. Why!?
|
||||
void MenuController::HandleThirdOption() {
|
||||
InstructionsVisualizer instructions;
|
||||
instructions.DrawView();
|
||||
}
|
||||
|
||||
// void MenuController::HandleCommandOptions(const std::string& command) {
|
||||
// if (command == "1") {
|
||||
// HandleThirdOption();
|
||||
// return;
|
||||
// } else if (command == "2") {
|
||||
// CHESSBOARD->ExportFilePGN("chessgames/save_games/");
|
||||
// std::cout << "Save game functionality is not implemented yet.\n";
|
||||
// } else if (command == "3") {
|
||||
// CHESSBOARD->SetWinner(CHESSBOARD->GetOpponentPlayer());
|
||||
// return;
|
||||
// } else if (command == "0") { // exit
|
||||
// return;
|
||||
// } else {
|
||||
// std::cout << "Invalid command. Please try again.\n";
|
||||
// }
|
||||
// }
|
||||
|
||||
// std::string MenuController::ExtractAfterDollar(const std::string& userInput) {
|
||||
// if (!userInput.empty() && userInput[0] == '$') {
|
||||
// return userInput.substr(1); // Rückgabe des Teils nach '$'
|
||||
// }
|
||||
// return ""; // Leerer String, wenn kein '$' am Anfang
|
||||
// }
|
||||
|
||||
// Chessboard* MenuController::GetChessboard() {
|
||||
// return CHESSBOARD;
|
||||
// }
|
||||
|
||||
void MenuController::SetChessboard(Chessboard* chessboard) {
|
||||
CHESSBOARD = chessboard;
|
||||
}
|
||||
|
||||
// std::string MenuController::trim(const std::string& str) {
|
||||
// size_t start = str.find_first_not_of(" \t\n\r\f\v");
|
||||
// if (start == std::string::npos) return ""; // Nur Leerzeichen
|
||||
// size_t end = str.find_last_not_of(" \t\n\r\f\v");
|
||||
// return str.substr(start, end - start + 1);
|
||||
// }
|
||||
|
||||
// std::vector<std::string> MenuController::split(const std::string& str, char delimiter, bool trimWhitespace) {
|
||||
// std::vector<std::string> tokens;
|
||||
// std::istringstream stream(str);
|
||||
// std::string token;
|
||||
|
||||
// while (std::getline(stream, token, delimiter)) {
|
||||
// if (trimWhitespace) {
|
||||
// token = trim(token); // Trimme die Tokens, falls gewünscht
|
||||
// }
|
||||
// tokens.push_back(token);
|
||||
// }
|
||||
|
||||
// return tokens;
|
||||
// }
|
29
src/Controller/MenuController.hpp
Normal file
29
src/Controller/MenuController.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef MENU_CONTROLLER_HPP
|
||||
#define MENU_CONTROLLER_HPP
|
||||
|
||||
#include "../Chessboard/Chessboard.hpp"
|
||||
#include "../Visualizer/PlayingViewVisualizer.hpp"
|
||||
#include <string>
|
||||
|
||||
class MenuController {
|
||||
private:
|
||||
std::string ExtractAfterDollar(const std::string& userInput);
|
||||
void HandlePlayingNavigation(std::string choice, Chessboard& chessboard, PlayingViewVisualizer& playView, bool isGameOver);
|
||||
|
||||
Chessboard* CHESSBOARD;
|
||||
|
||||
public:
|
||||
MenuController();
|
||||
~MenuController();
|
||||
|
||||
void HandleFirstOption();
|
||||
void HandleSecondOption();
|
||||
void HandleThirdOption();
|
||||
// void HandleCommandOptions(const std::string& command);
|
||||
// Chessboard* GetChessboard();
|
||||
void SetChessboard(Chessboard* chessboard);
|
||||
// std::string trim(const std::string& str);
|
||||
// std::vector<std::string> split(const std::string& str, char delimiter, bool trimWhitespace = false);
|
||||
};
|
||||
|
||||
#endif // MENU_CONTROLLER_HPP
|
281
src/Visualizer/BaseVisualizer.cpp
Normal file
281
src/Visualizer/BaseVisualizer.cpp
Normal file
@@ -0,0 +1,281 @@
|
||||
#include "BaseVisualizer.hpp"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
void BaseVisualizer::ClearTerminal() {
|
||||
#ifdef __linux__
|
||||
system("clear");
|
||||
#elif _WIN32
|
||||
system("cls");
|
||||
#else
|
||||
system("clear");
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<std::vector<std::string>>* BaseVisualizer::GetDisplayVector() {
|
||||
return &display_vector;
|
||||
}
|
||||
|
||||
size_t BaseVisualizer::CountVisibleCharacters(const std::string& str) {
|
||||
size_t count = 0;
|
||||
size_t i = 0;
|
||||
|
||||
while (i < str.size()) {
|
||||
if (str[i] == '\x1B' && i + 1 < str.size() && str[i + 1] == '[') {
|
||||
// ANSI-Escape-Sequenz erkennen und überspringen
|
||||
i += 2; // Überspringe '\x1B['
|
||||
while (i < str.size() && !std::isalpha(str[i])) {
|
||||
++i; // Fortsetzung der Sequenz überspringen
|
||||
}
|
||||
if (i < str.size() && std::isalpha(str[i])) {
|
||||
++i; // Buchstaben am Ende der Sequenz überspringen
|
||||
}
|
||||
} else {
|
||||
// UTF-8 Startbytes zählen (kein Fortsetzungsbyte)
|
||||
if ((str[i] & 0b11000000) != 0b10000000) {
|
||||
++count;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t BaseVisualizer::GetSumAllCharsFromVector(const std::vector<std::string>& vec) {
|
||||
size_t sum = 0;
|
||||
for (const std::string& str : vec) {
|
||||
sum += CountVisibleCharacters(str);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void BaseVisualizer::GenerateEmptyLine(const int lengthOfMenu, const bool single) {
|
||||
std::string result = "";
|
||||
for (int i = 0; i < lengthOfMenu; ++i) {
|
||||
if (i == 0) {
|
||||
result += ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE);
|
||||
} else if (i == lengthOfMenu-1) {
|
||||
result += ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE);
|
||||
} else {
|
||||
result += " ";
|
||||
}
|
||||
}
|
||||
display_vector.push_back({result});
|
||||
}
|
||||
|
||||
// ToDo: Auf Max länge bringen
|
||||
void BaseVisualizer::GenerateBoxMenuLine(const size_t length, const std::string& str, const bool single, const size_t padding) {
|
||||
std::string result = ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE) + std::string(padding, ' ') + str;
|
||||
while (CountVisibleCharacters(result) < length-1) {
|
||||
result += " ";
|
||||
}
|
||||
display_vector.push_back({result.append(((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE))});
|
||||
}
|
||||
|
||||
void BaseVisualizer::GenerateCenteredString(const size_t widthOfMenu, const std::string& str, const bool single) {
|
||||
std::string result = (single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE;
|
||||
|
||||
float newLength = widthOfMenu - CountVisibleCharacters(str) - 2;
|
||||
|
||||
int firstHalfLength = std::floor(newLength / 2);
|
||||
int secondHalfLength = std::ceil(newLength / 2);
|
||||
|
||||
for (int i = 0; i < firstHalfLength; ++i) {
|
||||
result += " ";
|
||||
}
|
||||
|
||||
result += str;
|
||||
|
||||
for (int i = 0; i < secondHalfLength; ++i) {
|
||||
result += " ";
|
||||
}
|
||||
|
||||
display_vector.push_back({result+ ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE)});
|
||||
}
|
||||
|
||||
void BaseVisualizer::DisplayElement() {
|
||||
for (const auto& row : display_vector) {
|
||||
for (const auto& cell : row) {
|
||||
std::cout << cell;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
size_t BaseVisualizer::CalculateMaxMenuWidth(const size_t longestStringLength, const size_t padding) {
|
||||
return longestStringLength + 2*padding + 2;
|
||||
}
|
||||
|
||||
void BaseVisualizer::GenerateTopBottomBorder(const size_t totalLength, const bool top, const bool single) {
|
||||
std::string result = (top) ? ((single) ? BaseVisualizer::TOP_LEFT_CORNER_SINGLE : BaseVisualizer::TOP_LEFT_CORNER) : ((single) ? BaseVisualizer::BOTTOM_LEFT_CORNER_SINGLE : BaseVisualizer::BOTTOM_LEFT_CORNER);
|
||||
for (size_t i = 0; i < totalLength-2; ++i) {
|
||||
result += (single) ? BaseVisualizer::HORIZONTAL_LINE_SINGLE : BaseVisualizer::HORIZONTAL_LINE;
|
||||
}
|
||||
display_vector.push_back({result + ((top) ? ((single) ? BaseVisualizer::TOP_RIGHT_CORNER_SINGLE : BaseVisualizer::TOP_RIGHT_CORNER) : ((single) ? BaseVisualizer::BOTTOM_RIGHT_CORNER_SINGLE : BaseVisualizer::BOTTOM_RIGHT_CORNER))});
|
||||
}
|
||||
|
||||
void BaseVisualizer::AddEmptyLines(const size_t lines, const size_t length, const bool sinlge) {
|
||||
for (size_t i = 0; i < lines; ++i) {
|
||||
BaseVisualizer::GenerateEmptyLine(length, sinlge);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseVisualizer::GenerateTableTopBottom(const size_t totalLength, const bool top, const bool single) {
|
||||
int firstHalfLength = std::floor(totalLength / 2);
|
||||
|
||||
std::string result = (top) ? ((single) ? BaseVisualizer::TOP_LEFT_CORNER_SINGLE : BaseVisualizer::TOP_LEFT_CORNER) : ((single) ? BaseVisualizer::BOTTOM_LEFT_CORNER_SINGLE : BaseVisualizer::BOTTOM_LEFT_CORNER);
|
||||
|
||||
for (size_t i = 0; i < firstHalfLength-1; ++i) {
|
||||
result += (single) ? BaseVisualizer::HORIZONTAL_LINE_SINGLE : BaseVisualizer::HORIZONTAL_LINE;
|
||||
}
|
||||
|
||||
result += (top) ? ((single) ? BaseVisualizer::TOP_CROSS_SINGLE : BaseVisualizer::TOP_CROSS) : ((single) ? BaseVisualizer::BOTTOM_CROSS_SINGLE : BaseVisualizer::BOTTOM_CROSS);
|
||||
|
||||
for (size_t i = 0; i < firstHalfLength-1; ++i) {
|
||||
result += (single) ? BaseVisualizer::HORIZONTAL_LINE_SINGLE : BaseVisualizer::HORIZONTAL_LINE;
|
||||
}
|
||||
|
||||
display_vector.push_back({result + ((top) ? ((single) ? BaseVisualizer::TOP_RIGHT_CORNER_SINGLE : BaseVisualizer::TOP_RIGHT_CORNER) : ((single) ? BaseVisualizer::BOTTOM_RIGHT_CORNER_SINGLE : BaseVisualizer::BOTTOM_RIGHT_CORNER))});
|
||||
}
|
||||
|
||||
// Todo: pair anstatt vector
|
||||
void BaseVisualizer::GenerateTableLine(const float length, const std::vector<std::string>& str, const bool single) {
|
||||
int firstHalfLength = std::floor(length / 2);
|
||||
std::string result = ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE);
|
||||
std::string temp;
|
||||
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
temp += " " + str[i];
|
||||
|
||||
while (CountVisibleCharacters(temp) < firstHalfLength-1) {
|
||||
temp += " ";
|
||||
}
|
||||
temp += ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE);
|
||||
result += temp;
|
||||
temp = "";
|
||||
}
|
||||
display_vector.push_back({result});
|
||||
}
|
||||
|
||||
void BaseVisualizer::GenerateTableSeperator(const float length, const bool single) {
|
||||
int firstHalfLength = std::floor(length / 2);
|
||||
std::string result = ((single) ? BaseVisualizer::RIGHT_CROSS_SINGLE : BaseVisualizer::RIGHT_CROSS);
|
||||
std::string temp;
|
||||
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
while (CountVisibleCharacters(temp) < firstHalfLength-1) {
|
||||
temp += ((single) ? BaseVisualizer::HORIZONTAL_LINE_SINGLE : BaseVisualizer::HORIZONTAL_LINE);
|
||||
}
|
||||
temp += (i != 1) ? ((single) ? BaseVisualizer::CROSS_SINGLE : BaseVisualizer::CROSS) : "";
|
||||
result += temp;
|
||||
temp = "";
|
||||
}
|
||||
result += ((single) ? BaseVisualizer::LEFT_CROSS_SINGLE : BaseVisualizer::LEFT_CROSS);
|
||||
|
||||
display_vector.push_back({result});
|
||||
}
|
||||
|
||||
void BaseVisualizer::GenerateBoxSeperator(const float length, const bool single) {
|
||||
std::string result = ((single) ? BaseVisualizer::RIGHT_CROSS_SINGLE : BaseVisualizer::RIGHT_CROSS);
|
||||
|
||||
while (CountVisibleCharacters(result) < length-1) {
|
||||
result += ((single) ? BaseVisualizer::HORIZONTAL_LINE_SINGLE : BaseVisualizer::HORIZONTAL_LINE);
|
||||
}
|
||||
|
||||
result += ((single) ? BaseVisualizer::LEFT_CROSS_SINGLE : BaseVisualizer::LEFT_CROSS);
|
||||
|
||||
display_vector.push_back({result});
|
||||
}
|
||||
|
||||
void BaseVisualizer::SetConsoleColor(Colors foreground, Colors background) {
|
||||
const std::string SEQ_FOREGROUND = "\x1b[3";
|
||||
const std::string SEQ_FOREGROUND_LIGHT = "\x1b[9";
|
||||
const std::string SEQ_BACKGROUND = "\x1b[4";
|
||||
const std::string SEQ_BACKGROUND_LIGHT = "\x1b[10";
|
||||
|
||||
// set foreground color
|
||||
switch (foreground) {
|
||||
case BLACK:
|
||||
case RED:
|
||||
case GREEN:
|
||||
case YELLOW:
|
||||
case BLUE:
|
||||
case MAGENTA:
|
||||
case CYAN:
|
||||
case WHITE:
|
||||
std::cout << SEQ_FOREGROUND << foreground << "m";
|
||||
break;
|
||||
case LIGHT_BLACK:
|
||||
case LIGHT_RED:
|
||||
case LIGHT_GREEN:
|
||||
case LIGHT_YELLOW:
|
||||
case LIGHT_BLUE:
|
||||
case LIGHT_MAGENTA:
|
||||
case LIGHT_CYAN:
|
||||
case LIGHT_WHITE:
|
||||
std::cout << SEQ_FOREGROUND_LIGHT << foreground << "m";
|
||||
break;
|
||||
case DEFAULT:
|
||||
default:
|
||||
std::cout << SEQ_FOREGROUND << foreground << "m";
|
||||
break;
|
||||
}
|
||||
|
||||
// set background color
|
||||
switch (background) {
|
||||
case BLACK:
|
||||
case RED:
|
||||
case GREEN:
|
||||
case YELLOW:
|
||||
case BLUE:
|
||||
case MAGENTA:
|
||||
case CYAN:
|
||||
case WHITE:
|
||||
std::cout << SEQ_BACKGROUND << background << "m";
|
||||
break;
|
||||
case LIGHT_BLACK:
|
||||
case LIGHT_RED:
|
||||
case LIGHT_GREEN:
|
||||
case LIGHT_YELLOW:
|
||||
case LIGHT_BLUE:
|
||||
case LIGHT_MAGENTA:
|
||||
case LIGHT_CYAN:
|
||||
case LIGHT_WHITE:
|
||||
std::cout << SEQ_BACKGROUND_LIGHT << background << "m";
|
||||
break;
|
||||
case DEFAULT:
|
||||
default:
|
||||
std::cout << SEQ_BACKGROUND << background << "m";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t BaseVisualizer::FindMaxLength(const std::vector<std::string> vec) {
|
||||
size_t max = 0;
|
||||
size_t currentLength = 0;
|
||||
for (const std::string& str : vec) {
|
||||
currentLength = CountVisibleCharacters(str);
|
||||
(currentLength > max) ? max = CountVisibleCharacters(str) : max;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
std::pair<int, int> BaseVisualizer::GetCursorPosition() {
|
||||
std::cout << "\033[6n"; // ANSI-Escape-Sequenz, um die Cursorposition abzufragen
|
||||
std::fflush(stdout); // Ausgabe sofort erzwingen
|
||||
|
||||
int row, col;
|
||||
|
||||
// Eingabe im Format "\033[row;colR" lesen
|
||||
char buf[32];
|
||||
if (std::fgets(buf, sizeof(buf), stdin)) {
|
||||
if (std::sscanf(buf, "\033[%d;%dR", &row, &col) != 2) {
|
||||
row = col = -1; // Fehlerbehandlung
|
||||
}
|
||||
} else {
|
||||
row = col = -1; // Fehlerbehandlung
|
||||
}
|
||||
|
||||
return std::pair<int, int>(row, col); // Rückgabe als Tupel
|
||||
};
|
100
src/Visualizer/BaseVisualizer.hpp
Normal file
100
src/Visualizer/BaseVisualizer.hpp
Normal file
@@ -0,0 +1,100 @@
|
||||
#ifndef BASEVISUALIZER_H
|
||||
#define BASEVISUALIZER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
enum Colors {
|
||||
BLACK = 0, RED = 1, GREEN = 2, YELLOW = 3, BLUE = 4, MAGENTA = 5, CYAN = 6, WHITE = 7,
|
||||
LIGHT_BLACK = 10, LIGHT_RED = 11, LIGHT_GREEN = 12, LIGHT_YELLOW = 13, LIGHT_BLUE = 14,
|
||||
LIGHT_MAGENTA = 15, LIGHT_CYAN = 16, LIGHT_WHITE = 17, DEFAULT = 9
|
||||
};
|
||||
|
||||
class BaseVisualizer {
|
||||
protected:
|
||||
inline static const std::string TOP_LEFT_CORNER = "\u2554";
|
||||
inline static const std::string TOP_RIGHT_CORNER = "\u2557";
|
||||
inline static const std::string HORIZONTAL_LINE = "\u2550";
|
||||
inline static const std::string VERTICAL_LINE = "\u2551";
|
||||
inline static const std::string BOTTOM_LEFT_CORNER = "\u255A";
|
||||
inline static const std::string BOTTOM_RIGHT_CORNER = "\u255D";
|
||||
inline static const std::string RIGHT_CROSS = "\u2560";
|
||||
inline static const std::string LEFT_CROSS = "\u2563";
|
||||
inline static const std::string CROSS = "\u256C";
|
||||
inline static const std::string TOP_CROSS = "\u2566";
|
||||
inline static const std::string BOTTOM_CROSS = "\u2569";
|
||||
|
||||
inline static const std::string TOP_LEFT_CORNER_SINGLE = "\u250C";
|
||||
inline static const std::string TOP_RIGHT_CORNER_SINGLE = "\u2510";
|
||||
inline static const std::string HORIZONTAL_LINE_SINGLE = "\u2500";
|
||||
inline static const std::string VERTICAL_LINE_SINGLE = "\u2502";
|
||||
inline static const std::string BOTTOM_LEFT_CORNER_SINGLE = "\u2514";
|
||||
inline static const std::string BOTTOM_RIGHT_CORNER_SINGLE = "\u2518";
|
||||
inline static const std::string RIGHT_CROSS_SINGLE = "\u251C";
|
||||
inline static const std::string LEFT_CROSS_SINGLE = "\u2524";
|
||||
inline static const std::string CROSS_SINGLE = "\u253C";
|
||||
inline static const std::string TOP_CROSS_SINGLE = "\u252C";
|
||||
inline static const std::string BOTTOM_CROSS_SINGLE = "\u2534";
|
||||
|
||||
const size_t MAX_MENU_WIDTH;
|
||||
const size_t PADDING;
|
||||
|
||||
std::vector<std::vector<std::string>> display_vector;
|
||||
|
||||
void GenerateEmptyLine(const int lengthOfMenu, const bool single);
|
||||
void GenerateBoxMenuLine(const size_t length, const std::string& str, const bool single, const size_t padding);
|
||||
void GenerateCenteredString(const size_t widthOfMenu, const std::string& str, const bool single);
|
||||
size_t CalculateMaxMenuWidth(const size_t longestStringLength, const size_t padding);
|
||||
size_t FindMaxLength(const std::vector<std::string> vec);
|
||||
void GenerateTopBottomBorder(const size_t totalLength, const bool top, const bool single);
|
||||
void AddEmptyLines(const size_t lines, const size_t length, const bool sinlge);
|
||||
void GenerateTableTopBottom(const size_t totalLength, const bool top, const bool single);
|
||||
void GenerateTableLine(const float length, const std::vector<std::string>& str, const bool single);
|
||||
void GenerateTableSeperator(const float length, const bool single);
|
||||
void GenerateBoxSeperator(const float length, const bool single);
|
||||
void SetConsoleColor(Colors foreground, Colors background);
|
||||
std::pair<int, int> GetCursorPosition();
|
||||
|
||||
static size_t GetSumAllCharsFromVector(const std::vector<std::string>& vec);
|
||||
static size_t CountVisibleCharacters(const std::string& str);
|
||||
|
||||
private:
|
||||
virtual void GenerateElement() = 0;
|
||||
|
||||
public:
|
||||
virtual ~BaseVisualizer() = default;
|
||||
static void ClearTerminal();
|
||||
void DisplayElement();
|
||||
std::vector<std::vector<std::string>>* GetDisplayVector();
|
||||
BaseVisualizer(size_t longestStringLength, size_t padding) : MAX_MENU_WIDTH(BaseVisualizer::CalculateMaxMenuWidth(longestStringLength, padding)), PADDING(padding) {}
|
||||
};
|
||||
|
||||
#endif //BASEVISUALIZER_H
|
||||
|
||||
/**
|
||||
*
|
||||
ChessboardVisualizer.cpp
|
||||
HistorieVisualizer.cpp
|
||||
CommandVisualizer.cpp
|
||||
|
||||
PlayVisualizer.cpp {
|
||||
ChessboardVisualizer.display_vector
|
||||
|
||||
|
||||
HistorieVisualizer.display_vector;
|
||||
|
||||
CommandVisualizer.display_vector;
|
||||
|
||||
st::cout << ChessboardVisualizer.display_vector[i] (isEmpty) ? << std:endl : << Padding << Menus.display_vector[i] << std:endl;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
166
src/Visualizer/ChessboardVisualizer.cpp
Normal file
166
src/Visualizer/ChessboardVisualizer.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
#include "ChessboardVisualizer.hpp"
|
||||
|
||||
size_t ChessboardVisualizer::GetMaxBoardWidth() {
|
||||
std::string temp;
|
||||
|
||||
temp.append(3, ' ');
|
||||
|
||||
temp += BaseVisualizer::TOP_LEFT_CORNER;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
for (int j = 0; j < 7; j++) {
|
||||
temp += BaseVisualizer::HORIZONTAL_LINE;
|
||||
}
|
||||
}
|
||||
temp += BaseVisualizer::TOP_RIGHT_CORNER;
|
||||
|
||||
return BaseVisualizer::CountVisibleCharacters(temp);
|
||||
}
|
||||
|
||||
void ChessboardVisualizer::GenerateTopBottomBorder(bool top, bool single) {
|
||||
std::string temp;
|
||||
|
||||
temp.append(3, ' '); // ToDo: Padding?
|
||||
|
||||
temp += (top)
|
||||
? ((single)
|
||||
? BaseVisualizer::TOP_LEFT_CORNER_SINGLE
|
||||
: BaseVisualizer::TOP_LEFT_CORNER)
|
||||
: ((single)
|
||||
? BaseVisualizer::BOTTOM_LEFT_CORNER_SINGLE
|
||||
: BaseVisualizer::BOTTOM_LEFT_CORNER);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
for (int j = 0; j < 7; j++) {
|
||||
temp += (single) ? BaseVisualizer::HORIZONTAL_LINE_SINGLE : BaseVisualizer::HORIZONTAL_LINE;
|
||||
}
|
||||
}
|
||||
display_vector.push_back({temp + ((top) ? ((single) ? BaseVisualizer::TOP_RIGHT_CORNER_SINGLE : BaseVisualizer::TOP_RIGHT_CORNER) : ((single) ? BaseVisualizer::BOTTOM_RIGHT_CORNER_SINGLE : BaseVisualizer::BOTTOM_RIGHT_CORNER))});
|
||||
}
|
||||
|
||||
void ChessboardVisualizer::GenerateElement() {
|
||||
BaseVisualizer::ClearTerminal();
|
||||
|
||||
GeneratePlayers();
|
||||
|
||||
GenerateChessboard();
|
||||
|
||||
//GenerateDisplayVector();
|
||||
}
|
||||
|
||||
void ChessboardVisualizer::GeneratePlayers() {
|
||||
std::string result;
|
||||
result.append(3, ' ');
|
||||
display_vector.push_back({result + CHESSBOARD->GetPlayer(ChessPieceColor::White)->GetName()
|
||||
+ " vs. " + CHESSBOARD->GetPlayer(ChessPieceColor::Black)->GetName()});
|
||||
}
|
||||
|
||||
void ChessboardVisualizer::GenerateChessboard() {
|
||||
std::vector<std::string> temp;
|
||||
for (int rank = 8; rank >= 1; rank--) {
|
||||
if (rank == 8) GenerateTopBottomBorder(true, true);
|
||||
for (int heightOfField = 0; heightOfField < 3; heightOfField++) {
|
||||
for (char file = 'A'; file <= 'H'; file++) {
|
||||
if (file == 'A') {
|
||||
temp.push_back((heightOfField == 1) ? " " + std::to_string(rank) + " " : std::string(3, ' '));
|
||||
temp.push_back(BaseVisualizer::VERTICAL_LINE_SINGLE);
|
||||
}
|
||||
|
||||
temp.push_back(GenerateBoardField(file, rank, heightOfField));
|
||||
|
||||
if (file == 'H') {
|
||||
temp.push_back(BaseVisualizer::VERTICAL_LINE_SINGLE);
|
||||
}
|
||||
}
|
||||
display_vector.push_back(temp);
|
||||
temp.clear();
|
||||
}
|
||||
if (rank == 1) {
|
||||
GenerateTopBottomBorder(false, true);
|
||||
GenerateFiles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string ChessboardVisualizer::GenerateBoardField(char file, int rank, int height) {
|
||||
ChessPiecePosition* position = new ChessPiecePosition(file, rank);
|
||||
if (height == 1 && !CHESSBOARD->IsEmptyField(position)) {
|
||||
ChessPiece* piece = CHESSBOARD->GetChessPiece(position);
|
||||
return std::string(3, ' ') + piece->GetUnicode() + std::string(3, ' ');
|
||||
}
|
||||
return std::string(7, ' ');
|
||||
}
|
||||
|
||||
void ChessboardVisualizer::GenerateFiles() {
|
||||
std::string temp;
|
||||
|
||||
for (char file = 'A'; file <= 'H'; file++) {
|
||||
if (file == 'A') {
|
||||
temp += (std::string(4, ' '));
|
||||
}
|
||||
|
||||
temp += (std::string(3, ' ') + std::string(1, file) + std::string(3, ' '));
|
||||
|
||||
if (file == 'H') {
|
||||
temp += " ";
|
||||
}
|
||||
}
|
||||
display_vector.push_back({temp});
|
||||
}
|
||||
|
||||
|
||||
// board[2] bis board[25] Feld des Schachbretts
|
||||
// in vectoren von 2 bis 25 index von 2 bis 9
|
||||
void ChessboardVisualizer::DisplayElement() {
|
||||
size_t size;
|
||||
std::string temp;
|
||||
for (int row = 0; row < display_vector.size(); ++row) {
|
||||
for (int column = 0; column < display_vector[row].size(); ++column) {
|
||||
if (row >= 2 && row <= 25 && column >= 2 && column <= 9) {
|
||||
bool isSecondRowOfField = (row % 3 == 2);
|
||||
bool isBlackWhite = (column % 2 == row % 2);
|
||||
|
||||
if ((row - 1) % 3 == 0) { // Change after 3 rows
|
||||
if (isSecondRowOfField) {
|
||||
this->SetConsoleColor(isBlackWhite ? WHITE : BLACK, isBlackWhite ? BLACK : WHITE);
|
||||
} else {
|
||||
this->SetConsoleColor(isBlackWhite ? BLACK : WHITE, isBlackWhite ? WHITE : BLACK);
|
||||
}
|
||||
} else {
|
||||
if (isSecondRowOfField) {
|
||||
this->SetConsoleColor(isBlackWhite ? BLACK : WHITE, isBlackWhite ? WHITE : BLACK);
|
||||
} else {
|
||||
this->SetConsoleColor(isBlackWhite ? WHITE : BLACK, isBlackWhite ? BLACK : WHITE);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << display_vector[row][column];
|
||||
this->SetConsoleColor(DEFAULT, DEFAULT);
|
||||
}
|
||||
this->SetConsoleColor(DEFAULT, DEFAULT);
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/*void ChessboardVisualizer::GenerateDisplayVector() {
|
||||
std::string temp;
|
||||
size_t size;
|
||||
|
||||
for (auto& row : draw_vector) {
|
||||
if (row.size() > 1) {
|
||||
for (const auto& element : row) {
|
||||
temp += element;
|
||||
}
|
||||
display_vector.push_back(FillStringToMaxLength(temp));
|
||||
temp = "";
|
||||
} else {
|
||||
display_vector.push_back(FillStringToMaxLength(row[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string ChessboardVisualizer::FillStringToMaxLength(std::string& str) {
|
||||
size_t size = BaseVisualizer::CountVisibleCharacters(str);
|
||||
return ((size == MAX_MENU_WIDTH)
|
||||
? str
|
||||
: str.append(std::string(MAX_MENU_WIDTH - size, ' ')));
|
||||
}*/
|
32
src/Visualizer/ChessboardVisualizer.hpp
Normal file
32
src/Visualizer/ChessboardVisualizer.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef CHESSBOARDVISUALIZER_HPP
|
||||
#define CHESSBOARDVISUALIZER_HPP
|
||||
|
||||
#include "BaseVisualizer.hpp"
|
||||
#include "../Chessboard/Chessboard.hpp"
|
||||
#include "../Chesspieces/Chesspiece.hpp"
|
||||
|
||||
class ChessboardVisualizer : public BaseVisualizer {
|
||||
|
||||
private:
|
||||
Chessboard* CHESSBOARD;
|
||||
std::vector<std::vector<std::string>> draw_vector;
|
||||
|
||||
static size_t GetMaxBoardWidth();
|
||||
|
||||
void GenerateTopBottomBorder(bool top, bool single);
|
||||
void GenerateElement() override;
|
||||
void GeneratePlayers();
|
||||
void GenerateChessboard();
|
||||
void GenerateFiles();
|
||||
std::string GenerateBoardField(char file, int rank, int height);
|
||||
void GenerateDisplayVector();
|
||||
std::string FillStringToMaxLength(std::string& str);
|
||||
|
||||
public:
|
||||
ChessboardVisualizer(Chessboard* chessboard, size_t padding) : BaseVisualizer(ChessboardVisualizer::GetMaxBoardWidth(), padding), CHESSBOARD(chessboard) {
|
||||
ChessboardVisualizer::GenerateElement();
|
||||
};
|
||||
void DisplayElement();
|
||||
};
|
||||
|
||||
#endif //CHESSBOARDVISUALIZER_HPP
|
20
src/Visualizer/CommandMenuVisualizer.cpp
Normal file
20
src/Visualizer/CommandMenuVisualizer.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "CommandMenuVisualizer.hpp"
|
||||
|
||||
// ToDo: Cursor wird nicht an die richtige Stelle gesetzt
|
||||
void CommandMenuVisualizer::GenerateElement() {
|
||||
BaseVisualizer::display_vector.push_back({" Commands"});
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, true, true);
|
||||
for (const auto& content : menuContent) {
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, content, true, PADDING);
|
||||
}
|
||||
BaseVisualizer::GenerateBoxSeperator(MAX_MENU_WIDTH, true);
|
||||
std::string str_temp = ((CHESSBOARD->GetCurrentPlayer()->GetColor() == ChessPieceColor::White) ? "White" : "Black");
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "Move [" + str_temp + "] : \x1B[s", true, PADDING);
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, false, true);
|
||||
display_vector.push_back({" "});
|
||||
BaseVisualizer::display_vector.push_back({std::string(" ").append(GetMessage())});
|
||||
}
|
||||
|
||||
std::string CommandMenuVisualizer::GetMessage() {
|
||||
return this->message;
|
||||
}
|
32
src/Visualizer/CommandMenuVisualizer.hpp
Normal file
32
src/Visualizer/CommandMenuVisualizer.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef COMMANDMENUVISUALIZER_HPP
|
||||
#define COMMANDMENUVISUALIZER_HPP
|
||||
|
||||
#include "BaseVisualizer.hpp"
|
||||
#include "../Chessboard/Chessboard.hpp"
|
||||
|
||||
class CommandMenuVisualizer : public BaseVisualizer {
|
||||
private:
|
||||
inline static const std::vector<std::string> menuContent = {
|
||||
"To execute command: $<command_no>",
|
||||
"",
|
||||
"1 - Instructions",
|
||||
"2 - Save",
|
||||
"3 - Resign",
|
||||
"",
|
||||
"0 - Exit",
|
||||
};
|
||||
|
||||
Chessboard* CHESSBOARD;
|
||||
|
||||
std::string message;
|
||||
|
||||
void GenerateElement() override;
|
||||
|
||||
public:
|
||||
CommandMenuVisualizer(Chessboard* chessboard, size_t padding, std::string msg) : BaseVisualizer(CommandMenuVisualizer::FindMaxLength(menuContent), padding), CHESSBOARD(chessboard), message(msg) {
|
||||
CommandMenuVisualizer::GenerateElement();
|
||||
}
|
||||
std::string GetMessage();
|
||||
};
|
||||
|
||||
#endif //COMMANDMENUVISUALIZER_HPP
|
52
src/Visualizer/HistorieVisualizer.cpp
Normal file
52
src/Visualizer/HistorieVisualizer.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "HistorieVisualizer.hpp"
|
||||
#include <algorithm>
|
||||
#include "../ChessPieces/ChessPieceMove.hpp"
|
||||
|
||||
void HistorieVisualizer::GenerateElement() {
|
||||
BaseVisualizer::display_vector.push_back({"Historie"});
|
||||
BaseVisualizer::GenerateTableTopBottom(MAX_MENU_WIDTH, true, true);
|
||||
|
||||
std::string playerName1 = HistorieVisualizer::PLAYER1;
|
||||
std::string playerName2 = HistorieVisualizer::PLAYER2;
|
||||
|
||||
if (playerName1.length() > 14) {
|
||||
playerName1 = playerName1.substr(0, 11) + "...";
|
||||
}
|
||||
if(playerName2.length() > 14) {
|
||||
playerName2 = playerName2.substr(0, 11) + "...";
|
||||
}
|
||||
|
||||
BaseVisualizer::GenerateTableLine(MAX_MENU_WIDTH, {playerName1, playerName2}, true);
|
||||
BaseVisualizer::GenerateTableSeperator(MAX_MENU_WIDTH, true);
|
||||
|
||||
std::vector<ChessPieceMove> moves = this->CHESSBOARD->GetHistoryMoves();
|
||||
|
||||
if (moves.size() % 2 == 0) {
|
||||
moves = std::vector<ChessPieceMove>(moves.end() - std::min<int>(moves.size(), 10), moves.end());
|
||||
} else {
|
||||
moves = std::vector<ChessPieceMove>(moves.end() - std::min<int>(moves.size(), 9), moves.end());
|
||||
}
|
||||
|
||||
std::vector<std::string> rowMoves;
|
||||
int rows = 0;
|
||||
|
||||
for (int moveIndex = 0; moveIndex < moves.size(); moveIndex++) {
|
||||
if (moveIndex % 2 == 0) rowMoves.clear();
|
||||
rowMoves.push_back(moves[moveIndex].ToString());
|
||||
|
||||
if (moveIndex % 2 == 1) {
|
||||
BaseVisualizer::GenerateTableLine(MAX_MENU_WIDTH, rowMoves, true);
|
||||
rows++;
|
||||
} else if (moveIndex == moves.size() - 1) {
|
||||
rowMoves.push_back("");
|
||||
BaseVisualizer::GenerateTableLine(MAX_MENU_WIDTH, rowMoves, true);
|
||||
rows++;
|
||||
}
|
||||
}
|
||||
|
||||
for (int rowIndex = rows; rowIndex < 5; rowIndex++) {
|
||||
BaseVisualizer::GenerateTableLine(MAX_MENU_WIDTH, {"", ""}, true);
|
||||
}
|
||||
|
||||
BaseVisualizer::GenerateTableTopBottom(MAX_MENU_WIDTH, false, true);
|
||||
}
|
27
src/Visualizer/HistorieVisualizer.hpp
Normal file
27
src/Visualizer/HistorieVisualizer.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef HISTORIEVISUALIZER_HPP
|
||||
#define HISTORIEVISUALIZER_HPP
|
||||
|
||||
#include "BaseVisualizer.hpp"
|
||||
#include "../Chessboard/Chessboard.hpp"
|
||||
|
||||
class HistorieVisualizer : public BaseVisualizer {
|
||||
private:
|
||||
const std::string PLAYER1;
|
||||
const std::string PLAYER2;
|
||||
|
||||
Chessboard* CHESSBOARD;
|
||||
|
||||
void GenerateElement() override;
|
||||
|
||||
public:
|
||||
HistorieVisualizer(Chessboard* chessbord,const size_t menuWidth, const size_t padding) :
|
||||
BaseVisualizer(menuWidth, padding),
|
||||
CHESSBOARD(chessbord),
|
||||
PLAYER1(chessbord->GetPlayer(ChessPieceColor::White)->GetName()),
|
||||
PLAYER2(chessbord->GetPlayer(ChessPieceColor::Black)->GetName())
|
||||
{
|
||||
HistorieVisualizer::GenerateElement();
|
||||
};
|
||||
};
|
||||
|
||||
#endif //HISTORIEVISUALIZER_HPP
|
36
src/Visualizer/ImportVisualizer.cpp
Normal file
36
src/Visualizer/ImportVisualizer.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include "ImportVisualizer.hpp"
|
||||
|
||||
void ImportVisualizer::GenerateElement() {
|
||||
// BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, true, false);
|
||||
// BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
// for (const auto& content : menuContent) {
|
||||
// BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, content, false, PADDING);
|
||||
// }
|
||||
// BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
// BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "You can get a lot of PGN files from chessgames.com.", false, PADDING);
|
||||
// BaseVisualizer::AddEmptyLines(5, MAX_MENU_WIDTH, false);
|
||||
// BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, false, false);
|
||||
}
|
||||
void ImportVisualizer::DrawView() {
|
||||
BaseVisualizer::ClearTerminal();
|
||||
this->display_vector.clear();
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, true, false);
|
||||
BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "Please enter a path to a PGN (Portable Game Notation) file:", false, PADDING);
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "\x1B[s", false, PADDING);
|
||||
BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "On https://chessgames.com/ you will find many more chess", false, PADDING);
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "games in PGN format, to import into TurboSchach.", false, PADDING);
|
||||
BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, false, false);
|
||||
BaseVisualizer::DisplayElement();
|
||||
std::cout << "\x1B[u";
|
||||
}
|
||||
|
||||
std::string ImportVisualizer::ShowMenu() {
|
||||
this->DrawView();
|
||||
std::string choice;
|
||||
std::getline(std::cin, choice);
|
||||
return choice;
|
||||
}
|
22
src/Visualizer/ImportVisualizer.hpp
Normal file
22
src/Visualizer/ImportVisualizer.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef ImportVisualizer_HPP
|
||||
#define ImportVisualizer_HPP
|
||||
|
||||
#include "BaseVisualizer.hpp"
|
||||
|
||||
class ImportVisualizer : public BaseVisualizer {
|
||||
private:
|
||||
inline static const std::vector<std::string> menuContent = {
|
||||
"Please enter the path to the PGN file:",
|
||||
"\x1B[s"
|
||||
};
|
||||
void GenerateElement() override;
|
||||
|
||||
public:
|
||||
ImportVisualizer() : BaseVisualizer(60, 4) {
|
||||
ImportVisualizer::GenerateElement();
|
||||
};
|
||||
std::string ShowMenu();
|
||||
void DrawView();
|
||||
};
|
||||
|
||||
#endif //INSTRUCTIONSVISUALIZER_HPP
|
20
src/Visualizer/InstructionsVisualizer.cpp
Normal file
20
src/Visualizer/InstructionsVisualizer.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "InstructionsVisualizer.hpp"
|
||||
|
||||
void InstructionsVisualizer::GenerateElement() {
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, true, false);
|
||||
BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
for (const auto& content : menuContent) {
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, content, false, PADDING);
|
||||
}
|
||||
BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "Press enter to continue: \x1B[s", false, PADDING);
|
||||
BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, false, false);
|
||||
}
|
||||
void InstructionsVisualizer::DrawView() {
|
||||
BaseVisualizer::ClearTerminal();
|
||||
BaseVisualizer::DisplayElement();
|
||||
std::cout << "\x1B[u";
|
||||
std::string choice;
|
||||
std::getline(std::cin, choice);
|
||||
}
|
60
src/Visualizer/InstructionsVisualizer.hpp
Normal file
60
src/Visualizer/InstructionsVisualizer.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#ifndef INSTRUCTIONSVISUALIZER_HPP
|
||||
#define INSTRUCTIONSVISUALIZER_HPP
|
||||
|
||||
#include "BaseVisualizer.hpp"
|
||||
|
||||
class InstructionsVisualizer : public BaseVisualizer {
|
||||
private:
|
||||
inline static const std::vector<std::string> menuContent = {
|
||||
"1. Algebraische Notation",
|
||||
"",
|
||||
"Um die Figuren auf dem Schachbrett zu bewegen, wird die kurze algebraische Notation",
|
||||
"FIDE-Handbuch (siehe Appendix C) unterstützt. Es werden die Schachfiguren sowohl in",
|
||||
"deutscher als auch in englischer Sprache unterstützt.",
|
||||
"",
|
||||
"┌───────────────────┬─────────┬──────────┐",
|
||||
"│ Schachfigur │ Deutsch │ Englisch │",
|
||||
"├───────────────────┼─────────┼──────────┤",
|
||||
"│ Bauer (Pawn) │ B │ P │",
|
||||
"│ Springer (Knight) │ S │ N │",
|
||||
"│ Läufer (Bishop) │ L │ B │",
|
||||
"│ Turm (Rook) │ T │ R │",
|
||||
"│ Dame (Queen) │ D │ Q │",
|
||||
"│ König (King) │ K │ K │",
|
||||
"└───────────────────┴─────────┴──────────┘",
|
||||
"",
|
||||
"Bei der kurzen Notation wird immer nur das Zielfeld eines Spielzuges genannt. Sollte",
|
||||
"der Ursprung nicht eindeutig sein kann auch die Spalte oder Zeile der zu bewegenden Figur",
|
||||
"genannt werden. So gibt der Spielzug 'dxe5' an dass der Bauer in der Spalte D auf das Feld",
|
||||
"E5 zieht. Das 'x' gibt an dass dabei eine Spielfigur des Gegeners geschlagen wird. Dies muss",
|
||||
"aber nicht zwingend angegeben werden. Der Bauer wird in den Spielzügen nicht benannt. Der",
|
||||
"Spielzug 'b4' ist daher der Zug eines Bauern auf das Feld B4. Alle anderen Schachfiguren werden",
|
||||
"im Zug mit ihrem entsprechenden Buchstaben genannt. So gibt der Spielzug 'Bc4' an dass der Läufer",
|
||||
"auf das Feld C4 gezogen wird.",
|
||||
"",
|
||||
"Beispiele:",
|
||||
"",
|
||||
" - (=) Angebot für ein Draw. Um das Spiel mit einem Draw zu beenden muss das Angebot direkt im",
|
||||
" nächsten Zug bestätigt werden.",
|
||||
" - b4 Der Bauer zieht auf das Feld B4.",
|
||||
" - Bc4 Der Läufer zieht auf das Feld C4.",
|
||||
" - 0-0 Kleine Rochade (Rochade am Königsflügel)",
|
||||
" - 0-0-0 Große Rochade (Rochade am Damenflügel)",
|
||||
" - d8Q Umwandlung: Der Bauer zieht auf D8 und wandelt sich zur Dame.",
|
||||
"",
|
||||
"2. PGN (Portable Game Notation)",
|
||||
"",
|
||||
"TurboSchach unterstützt das Datenformat PGN, welches zur Speicherung von Schachpartien verwendet",
|
||||
"wird. Auf der Website https://www.chessgames.com/ werden viele Schachpartien von offiziellen Turnieren",
|
||||
"im PGN-Format zur Verfügung gestellt. Diese Dateien können in TurboSchach importiert werden."
|
||||
};
|
||||
void GenerateElement() override;
|
||||
|
||||
public:
|
||||
InstructionsVisualizer() : BaseVisualizer(BaseVisualizer::FindMaxLength(menuContent), 4) {
|
||||
InstructionsVisualizer::GenerateElement();
|
||||
};
|
||||
void DrawView();
|
||||
};
|
||||
|
||||
#endif //INSTRUCTIONSVISUALIZER_HPP
|
43
src/Visualizer/PlaySelectVisualizer.cpp
Normal file
43
src/Visualizer/PlaySelectVisualizer.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "PlaySelectVisualizer.hpp"
|
||||
|
||||
void PlaySelectVisualizer::GenerateElement() {
|
||||
// BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, true, false);
|
||||
// BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
// for (const auto& content : menuContent) {
|
||||
// BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, content, false, PADDING);
|
||||
// }
|
||||
// BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
// BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, false, false);
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, int>> PlaySelectVisualizer::GetCursorPositions() {
|
||||
return this->cursorPositions;
|
||||
}
|
||||
|
||||
void PlaySelectVisualizer::AddToCursorPositions(const std::pair<int, int>& position) {
|
||||
this->cursorPositions.push_back(position);
|
||||
}
|
||||
void PlaySelectVisualizer::DrawView() {
|
||||
BaseVisualizer::ClearTerminal();
|
||||
this->display_vector.clear();
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, true, false);
|
||||
BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
if (this->labelPlayerName.empty()) {
|
||||
this->labelPlayerName = "player";
|
||||
}
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "Please enter a name for the " + this->labelPlayerName + ":", false, PADDING);
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "\x1B[s", false, PADDING);
|
||||
BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, false, false);
|
||||
BaseVisualizer::DisplayElement();
|
||||
std::cout << "\x1B[u";
|
||||
}
|
||||
std::string PlaySelectVisualizer::ShowMenu() {
|
||||
this->DrawView();
|
||||
std::string choice;
|
||||
std::getline(std::cin, choice);
|
||||
return choice;
|
||||
}
|
||||
void PlaySelectVisualizer::SetLabelPlayerName(std::string label) {
|
||||
this->labelPlayerName = label;
|
||||
}
|
30
src/Visualizer/PlaySelectVisualizer.hpp
Normal file
30
src/Visualizer/PlaySelectVisualizer.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef PLAYSELECTVISUALIZER_HPP
|
||||
#define PLAYSELECTVISUALIZER_HPP
|
||||
|
||||
#include "BaseVisualizer.hpp"
|
||||
|
||||
class PlaySelectVisualizer : public BaseVisualizer {
|
||||
private:
|
||||
std::string labelPlayerName;
|
||||
// ToDo: Exit
|
||||
inline static const std::vector<std::string> menuContent = {
|
||||
"Please enter your names! Enter your names with '&' seperated.",
|
||||
"",
|
||||
"Playernames: \x1B[s"
|
||||
};
|
||||
std::vector<std::pair<int, int>> cursorPositions;
|
||||
|
||||
|
||||
public:
|
||||
PlaySelectVisualizer(size_t padding) : BaseVisualizer(PlaySelectVisualizer::FindMaxLength(menuContent), padding) {
|
||||
PlaySelectVisualizer::GenerateElement();
|
||||
}
|
||||
void GenerateElement();
|
||||
void AddToCursorPositions(const std::pair<int, int>& position);
|
||||
std::vector<std::pair<int, int>> GetCursorPositions();
|
||||
void DrawView();
|
||||
std::string ShowMenu();
|
||||
void SetLabelPlayerName(std::string label);
|
||||
};
|
||||
|
||||
#endif //PLAYSELECTVISUALIZER_HPP
|
129
src/Visualizer/PlayingViewVisualizer.cpp
Normal file
129
src/Visualizer/PlayingViewVisualizer.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
#include "PlayingViewVisualizer.hpp"
|
||||
#include "ChessboardVisualizer.hpp"
|
||||
#include "HistorieVisualizer.hpp"
|
||||
#include "CommandMenuVisualizer.hpp"
|
||||
|
||||
|
||||
// ToDo: Beim Fenster größer ziehen verschiebt sich die Ansicht
|
||||
void PlayingViewVisualizer::GenerateElement() {
|
||||
position_vector.clear();
|
||||
display_vector.clear();
|
||||
ChessboardVisualizer chessboardVisualizer = ChessboardVisualizer(this->CHESSBOARD, 2);
|
||||
HistorieVisualizer historieVisualizer = HistorieVisualizer(this->CHESSBOARD, 32, 2);
|
||||
CommandMenuVisualizer cmdMenuVisualizer = CommandMenuVisualizer(this->CHESSBOARD, 2, this->GetMessage());
|
||||
|
||||
GeneratePositionVector(chessboardVisualizer.GetDisplayVector(), historieVisualizer.GetDisplayVector(), cmdMenuVisualizer.GetDisplayVector());
|
||||
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, true, false);
|
||||
BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
|
||||
std::vector<std::string> temp;
|
||||
|
||||
//((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE) + std::string(padding, ' ')
|
||||
|
||||
for (const auto& row : position_vector) {
|
||||
display_vector.push_back(row);
|
||||
}
|
||||
|
||||
BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, false, false);
|
||||
//size_t maxWidth = BaseVisualizer::FindMaxLength(chessboardVisualizer.display_vector);
|
||||
|
||||
}
|
||||
|
||||
void PlayingViewVisualizer::GeneratePositionVector(
|
||||
std::vector<std::vector<std::string>>* chessboard_display_vector,
|
||||
std::vector<std::vector<std::string>>* historie_display_vector,
|
||||
std::vector<std::vector<std::string>>* command_menu_display_vector)
|
||||
{
|
||||
for (size_t i = 0; i < chessboard_display_vector->size(); ++i) {
|
||||
size_t test;
|
||||
std::vector<std::string> temp;
|
||||
temp.push_back({BaseVisualizer::VERTICAL_LINE + " "});
|
||||
if (i == 0) {
|
||||
const std::string& first_element = chessboard_display_vector->at(i).at(0);
|
||||
temp.push_back(first_element);
|
||||
temp.push_back(std::string(62-BaseVisualizer::CountVisibleCharacters(first_element), ' '));
|
||||
} else if (chessboard_display_vector->at(i).size() > 1 && i != 0) {
|
||||
temp.insert(temp.end(), chessboard_display_vector->at(i).begin(), chessboard_display_vector->at(i).end());
|
||||
} else {
|
||||
temp.push_back(chessboard_display_vector->at(i).at(0));
|
||||
}
|
||||
|
||||
temp.push_back(std::string(DISTANCE_BETWEEN_ELEMENTS, ' '));
|
||||
|
||||
if (i < historie_display_vector->size()) {
|
||||
temp.push_back(historie_display_vector->at(i)[0]);
|
||||
} else if (i-3-historie_display_vector->size() < command_menu_display_vector->size()) {
|
||||
temp.push_back(command_menu_display_vector->at(i-3-historie_display_vector->size())[0]);
|
||||
//} else if (i-3-historie_display_vector->size()-command_menu_display_vector->size()-1 == 0 && !this->GetMessage().empty()) {
|
||||
//temp.push_back(this->GetMessage());
|
||||
} else {
|
||||
temp.push_back({"", ""});
|
||||
}
|
||||
|
||||
BaseVisualizer::GetSumAllCharsFromVector(temp);
|
||||
temp.push_back(std::string(MAX_MENU_WIDTH-BaseVisualizer::GetSumAllCharsFromVector(temp)-1, ' ') + BaseVisualizer::VERTICAL_LINE);
|
||||
|
||||
position_vector.push_back(temp);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayingViewVisualizer::DisplayElement() {
|
||||
PlayingViewVisualizer::GenerateElement();
|
||||
size_t size;
|
||||
std::string temp;
|
||||
for (int row = 0; row < display_vector.size(); ++row) {
|
||||
for (int column = 0; column < display_vector[row].size(); ++column) {
|
||||
if (row >= 4 && row <= 27 && column >= 3 && column <= 10) {
|
||||
bool isSecondRowOfField = ((row-1) % 3 == 2);
|
||||
bool isBlackWhite = ((column-1) % 2 == (row-1) % 2);
|
||||
|
||||
if ((row - 1) % 3 == 0) { // Change after 3 rows
|
||||
if (isSecondRowOfField) {
|
||||
this->SetConsoleColor(isBlackWhite ? BLACK : WHITE, isBlackWhite ? WHITE : BLACK);
|
||||
} else {
|
||||
this->SetConsoleColor(isBlackWhite ? WHITE : BLACK, isBlackWhite ? BLACK : WHITE);
|
||||
}
|
||||
} else {
|
||||
if (isSecondRowOfField) {
|
||||
this->SetConsoleColor(isBlackWhite ? WHITE : BLACK, isBlackWhite ? BLACK : WHITE);
|
||||
} else {
|
||||
this->SetConsoleColor(isBlackWhite ? BLACK : WHITE, isBlackWhite ? WHITE : BLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << display_vector[row][column];
|
||||
this->SetConsoleColor(DEFAULT, DEFAULT);
|
||||
}
|
||||
this->SetConsoleColor(DEFAULT, DEFAULT);
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::string PlayingViewVisualizer::GetMove() {
|
||||
return move;
|
||||
}
|
||||
|
||||
std::string PlayingViewVisualizer::GetMessage() {
|
||||
return this->message;
|
||||
}
|
||||
|
||||
void PlayingViewVisualizer::SetMessage(std::string message) {
|
||||
this->message = message;
|
||||
}
|
||||
|
||||
void PlayingViewVisualizer::DrawView() {
|
||||
BaseVisualizer::ClearTerminal();
|
||||
this->DisplayElement();
|
||||
std::cout << "\x1B[u";
|
||||
}
|
||||
|
||||
std::string PlayingViewVisualizer::ShowMenu() {
|
||||
this->DrawView();
|
||||
this->SetMessage("");
|
||||
std::string choice;
|
||||
std::getline(std::cin, choice);
|
||||
return choice;
|
||||
}
|
34
src/Visualizer/PlayingViewVisualizer.hpp
Normal file
34
src/Visualizer/PlayingViewVisualizer.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef PLAYINGVIEWVISUALIZER_HPP
|
||||
#define PLAYINGVIEWVISUALIZER_HPP
|
||||
|
||||
#include "BaseVisualizer.hpp"
|
||||
#include "../Chessboard/Chessboard.hpp"
|
||||
|
||||
class PlayingViewVisualizer : public BaseVisualizer {
|
||||
private:
|
||||
const size_t DISTANCE_BETWEEN_ELEMENTS;
|
||||
|
||||
Chessboard* CHESSBOARD;
|
||||
std::string move;
|
||||
std::string message = "";
|
||||
|
||||
std::vector<std::vector<std::string>> position_vector;
|
||||
|
||||
void GenerateElement();
|
||||
void GeneratePositionVector(
|
||||
std::vector<std::vector<std::string>>* chessboard_display_vector,
|
||||
std::vector<std::vector<std::string>>* historie_display_vector,
|
||||
std::vector<std::vector<std::string>>* command_menu_display_vector);
|
||||
|
||||
public:
|
||||
PlayingViewVisualizer(Chessboard* chessboard, size_t padding, size_t distance) :
|
||||
BaseVisualizer(110, padding), CHESSBOARD(chessboard), DISTANCE_BETWEEN_ELEMENTS(distance) {}
|
||||
void DisplayElement();
|
||||
std::string GetMove();
|
||||
std::string GetMessage();
|
||||
void SetMessage(std::string message);
|
||||
void DrawView();
|
||||
std::string ShowMenu();
|
||||
};
|
||||
|
||||
#endif //PLAYINGVIEWVISUALIZER_HPP
|
71
src/Visualizer/StartMenuVisualizer.cpp
Normal file
71
src/Visualizer/StartMenuVisualizer.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#include "StartMenuVisualizer.hpp"
|
||||
|
||||
void StartMenuVisualizer::GenerateElement() {
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, true, false);
|
||||
|
||||
BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
|
||||
for (const auto& str : StartMenuVisualizer::ACSII_ART_TURBO_SCHACH) {
|
||||
BaseVisualizer::GenerateCenteredString(MAX_MENU_WIDTH, str, false);
|
||||
}
|
||||
|
||||
BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
|
||||
BaseVisualizer::GenerateCenteredString(MAX_MENU_WIDTH, "Welcome to TurboSchach!", false);
|
||||
|
||||
BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
|
||||
BaseVisualizer::GenerateCenteredString(MAX_MENU_WIDTH, "Please select one of the menu options:", false);
|
||||
BaseVisualizer::GenerateCenteredString(MAX_MENU_WIDTH, "\x1B[s", false);
|
||||
|
||||
BaseVisualizer::AddEmptyLines(1, MAX_MENU_WIDTH, false);
|
||||
|
||||
// ToDo: Attribute zum direkten setzen des Types der Außenbegrenzung -> Allgemein in BaseVisualizer auch?
|
||||
// ToDo: Überarbeiten -> Extra Methode um Menus im Menu zu generieren
|
||||
BaseVisualizer::GenerateTopBottomBorder(24, true, true);
|
||||
BaseVisualizer::GenerateCenteredString(MAX_MENU_WIDTH, BaseVisualizer::display_vector[BaseVisualizer::display_vector.size()-1][0], false);
|
||||
BaseVisualizer::display_vector.erase(BaseVisualizer::display_vector.begin() + (BaseVisualizer::display_vector.size() - 2));
|
||||
|
||||
|
||||
for (const auto& str : StartMenuVisualizer::MENU_OPTIONS) {
|
||||
BaseVisualizer::GenerateBoxMenuLine(24, str, true, 1);
|
||||
BaseVisualizer::GenerateCenteredString(MAX_MENU_WIDTH, BaseVisualizer::display_vector[BaseVisualizer::display_vector.size()-1][0], false);
|
||||
BaseVisualizer::display_vector.erase(BaseVisualizer::display_vector.begin() + (BaseVisualizer::display_vector.size() - 2));
|
||||
|
||||
}
|
||||
|
||||
BaseVisualizer::GenerateTopBottomBorder(24, false, true);
|
||||
BaseVisualizer::GenerateCenteredString(MAX_MENU_WIDTH, BaseVisualizer::display_vector[BaseVisualizer::display_vector.size()-1][0], false);
|
||||
BaseVisualizer::display_vector.erase(BaseVisualizer::display_vector.begin() + (BaseVisualizer::display_vector.size() - 2));
|
||||
|
||||
|
||||
BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, false, false);
|
||||
}
|
||||
|
||||
int StartMenuVisualizer::GetSelectedOption() {
|
||||
return selectedOption;
|
||||
}
|
||||
|
||||
void StartMenuVisualizer::SetSelectedOption(int optionSelect) {
|
||||
selectedOption = selectedOption;
|
||||
};
|
||||
|
||||
void StartMenuVisualizer::DrawView() {
|
||||
BaseVisualizer::ClearTerminal();
|
||||
BaseVisualizer::DisplayElement();
|
||||
std::cout << "\x1B[u";
|
||||
}
|
||||
|
||||
StartMenuVisualizer::StartMenuOption StartMenuVisualizer::ShowMenu() {
|
||||
this->DrawView();
|
||||
std::string choice;
|
||||
std::getline(std::cin, choice);
|
||||
|
||||
if (choice == "1") return StartMenuOption::NewGame;
|
||||
if (choice == "2") return StartMenuOption::LoadGame;
|
||||
if (choice == "3") return StartMenuOption::Instructions;
|
||||
if (choice == "0") return StartMenuOption::Exit;
|
||||
return StartMenuOption::None;
|
||||
}
|
46
src/Visualizer/StartMenuVisualizer.hpp
Normal file
46
src/Visualizer/StartMenuVisualizer.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef STARTMENUVISUALIZER_H
|
||||
#define STARTMENUVISUALIZER_H
|
||||
|
||||
#include "BaseVisualizer.hpp"
|
||||
|
||||
class StartMenuVisualizer : public BaseVisualizer {
|
||||
private:
|
||||
inline static const std::vector<std::string> ACSII_ART_TURBO_SCHACH = {
|
||||
"████████╗██╗░░░██╗██████╗░██████╗░░█████╗░░██████╗░█████╗░██╗░░██╗░█████╗░░█████╗░██╗░░██╗",
|
||||
"╚══██╔══╝██║░░░██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗██║░░██║██╔══██╗██╔══██╗██║░░██║",
|
||||
"░░░██║░░░██║░░░██║██████╔╝██████╦╝██║░░██║╚█████╗░██║░░╚═╝███████║███████║██║░░╚═╝███████║",
|
||||
"░░░██║░░░██║░░░██║██╔══██╗██╔══██╗██║░░██║░╚═══██╗██║░░██╗██╔══██║██╔══██║██║░░██╗██╔══██║",
|
||||
"░░░██║░░░╚██████╔╝██║░░██║██████╦╝╚█████╔╝██████╔╝╚█████╔╝██║░░██║██║░░██║╚█████╔╝██║░░██║",
|
||||
"░░░╚═╝░░░░╚═════╝░╚═╝░░╚═╝╚═════╝░░╚════╝░╚═════╝░░╚════╝░╚═╝░░╚═╝╚═╝░░╚═╝░╚════╝░╚═╝░░╚═╝"
|
||||
};
|
||||
|
||||
inline static const std::vector<std::string> MENU_OPTIONS = {
|
||||
"1 - New Game",
|
||||
"2 - Load Game",
|
||||
"3 - Instructions",
|
||||
"",
|
||||
"0 - Exit"
|
||||
};
|
||||
|
||||
int selectedOption = -1;
|
||||
|
||||
void GenerateElement() override;
|
||||
|
||||
public:
|
||||
StartMenuVisualizer(size_t padding) : BaseVisualizer(BaseVisualizer::CountVisibleCharacters(StartMenuVisualizer::ACSII_ART_TURBO_SCHACH[0]), padding) {
|
||||
StartMenuVisualizer::GenerateElement();
|
||||
}
|
||||
enum StartMenuOption {
|
||||
NewGame,
|
||||
LoadGame,
|
||||
Instructions,
|
||||
Exit,
|
||||
None
|
||||
};
|
||||
int GetSelectedOption();
|
||||
void SetSelectedOption(int selectedOption);
|
||||
void DrawView();
|
||||
StartMenuOption ShowMenu();
|
||||
};
|
||||
|
||||
#endif //STARTMENUVISUALIZER_H
|
38
src/main.cpp
Normal file
38
src/main.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "./Controller/MenuController.hpp"
|
||||
#include "./Visualizer/StartMenuVisualizer.hpp"
|
||||
#include "./Visualizer/BaseVisualizer.hpp"
|
||||
#include "./Visualizer/PlaySelectVisualizer.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
#ifdef _WIN32
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
#endif
|
||||
|
||||
StartMenuVisualizer startMenu(3);
|
||||
MenuController menuController;
|
||||
StartMenuVisualizer::StartMenuOption optionStartMenu = StartMenuVisualizer::StartMenuOption::None;
|
||||
|
||||
do {
|
||||
switch (optionStartMenu = startMenu.ShowMenu()) {
|
||||
case StartMenuVisualizer::StartMenuOption::NewGame:
|
||||
menuController.HandleFirstOption();
|
||||
break;
|
||||
case StartMenuVisualizer::StartMenuOption::LoadGame:
|
||||
menuController.HandleSecondOption();
|
||||
break;
|
||||
case StartMenuVisualizer::StartMenuOption::Instructions:
|
||||
menuController.HandleThirdOption();
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
} while (optionStartMenu != StartMenuVisualizer::StartMenuOption::Exit);
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user