342 lines
9.9 KiB
C++
342 lines
9.9 KiB
C++
#include <memory>
|
|
#include <set>
|
|
#include "../Chessboard/Chessboard.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::InitializeStartBoard() {
|
|
Chessboard::InitializeBoard(defaultBoard);
|
|
}
|
|
|
|
void Chessboard::InitializeBoard(std::set<Board_ChessPiece> board) {
|
|
for (const auto& piece : board) {
|
|
ChessPiecePosition pos = ChessPiecePosition(piece.position.first, piece.position.second);
|
|
ChessPieceColor color = (piece.color == 0) ? ChessPieceColor::Black : ChessPieceColor::White;
|
|
|
|
switch (piece.type) {
|
|
case 'R':
|
|
SetChessPiece(new Rook(color, pos));
|
|
break;
|
|
case 'N':
|
|
SetChessPiece(new Knight(color, pos));
|
|
break;
|
|
case 'B':
|
|
SetChessPiece(new Bishop(color, pos));
|
|
break;
|
|
case 'Q':
|
|
SetChessPiece(new Queen(color, pos));
|
|
break;
|
|
case 'K':
|
|
SetChessPiece(new King(color, pos));
|
|
break;
|
|
case 'P':
|
|
SetChessPiece(new Pawn(color, pos));
|
|
break;
|
|
default:
|
|
std::cout << "Invalid ChessPieceType!" << std::endl;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Chessboard::SetChessPiece(ChessPiece* chesspiece) {
|
|
this->chessboard[chesspiece->GetPosition()] = chesspiece;
|
|
}
|
|
|
|
/*void Chessboard::SetChessPiece(std::unique_ptr<ChessPiece> piece) {
|
|
this->chessboard[piece->GetPosition()] = piece.release();
|
|
}*/
|
|
|
|
bool Chessboard::IsEmptyField(ChessPiecePosition* position) {
|
|
return (this->chessboard.count(*position) == 0);
|
|
}
|
|
|
|
ChessPiece* Chessboard::GetChessPiece(ChessPiecePosition* position) {
|
|
return this->chessboard.at(*position);
|
|
}
|
|
|
|
void Chessboard::MoveChessPiece(std::string move) {
|
|
if (move.length() == 5) {
|
|
ChessPiecePosition* fromPosition = new ChessPiecePosition(move.substr(0, 2));
|
|
ChessPiecePosition* toPosition = new ChessPiecePosition(move.substr(3, 2));
|
|
|
|
ChessPiece* piece = this->GetChessPiece(fromPosition);
|
|
|
|
if (piece->GetColor() != this->GetCurrentPlayer()->GetColor()) {
|
|
return; // wrong player
|
|
}
|
|
|
|
if (piece->GetNextPositions().count(*toPosition) == 1) {
|
|
this->chessboard[*toPosition] = this->chessboard[*fromPosition];
|
|
this->chessboard.erase(*fromPosition);
|
|
piece->SetPosition(*toPosition);
|
|
this->SetToHistory(*fromPosition, *toPosition);
|
|
} else {
|
|
return; // wrong or invalid move
|
|
}
|
|
}
|
|
|
|
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 == false) {
|
|
return true;
|
|
}
|
|
|
|
// 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;
|
|
deniable = false;
|
|
|
|
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->GetColor() == color && field.second->GetNextPositions().count(position) == 1) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
Chessboard::~Chessboard() {
|
|
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;
|
|
}
|