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 = &currentPosition;
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;
}