308 lines
9.9 KiB
C++

#include "../ChessPieces/ChessPiece.hpp"
#include "../Chessboard/Chessboard.hpp"
/**
* Creates a new chess piece with a specific color and position.
* @param color The color of the chess piece.
* @param position The position of the chess piece.
*/
ChessPiece::ChessPiece(ChessPieceColor color, ChessPiecePosition position) {
this->SetColor(color);
this->SetPosition(position);
}
/**
* Gets the char symbol of the chess piece.
* @return The char symbol of the chess piece.
*/
char ChessPiece::GetChar() {
return this->_char;
}
/**
* Gets the color of the chess piece.
* @return The color of the chess piece.
*/
ChessPieceColor ChessPiece::GetColor() {
return this->_color;
}
/**
* Gets a set of all positions along the diagonal.
* @param chessboard A pointer to the chessboard.
* @param ignore A set if chess piece positions to be ignored.
* @return A set of all positions along the diagonal.
*/
std::set<ChessPiecePosition> ChessPiece::GetDiagonalPositions(Chessboard* chessboard, std::set<ChessPiecePosition> ignore) {
std::set<ChessPiecePosition> positions;
ChessPiecePosition currentPosition = this->GetPosition();
for (std::string direction : {"T1L1", "T1R1", "B1L1", "B1R1"}) {
ChessPiecePosition* nextPosition = &currentPosition;
while (nextPosition = nextPosition->NextFromString(direction)) {
if (chessboard->IsEmptyField(nextPosition) || ignore.count(*nextPosition) == 1) {
// 3.5. When making these moves, the bishop, rook or queen may not move over any intervening pieces.
positions.insert(*nextPosition);
} else {
ChessPiece* chessPiece = chessboard->GetChessPiece(nextPosition);
// 3.1. It is not permitted to move a piece to a square occupied by a piece of the same colour.
// 3.1.1. If a piece moves to a square occupied by an opponent's piece the latter is captured and removed from the chessboard as part of the same move.
if (chessPiece && chessPiece->GetColor() != this->GetColor()) {
positions.insert(*nextPosition);
}
break;
}
}
}
return positions;
}
/**
* Gets a set of all positions along the file.
* @param chessboard A pointer to the chessboard.
* @param ignore A set if chess piece positions to be ignored.
* @return A set of all positions along the file.
*/
std::set<ChessPiecePosition> ChessPiece::GetFilePositions(Chessboard* chessboard, std::set<ChessPiecePosition> ignore) {
std::set<ChessPiecePosition> positions;
ChessPiecePosition currentPosition = this->GetPosition();
for (std::string direction : {"T1", "B1"}) {
ChessPiecePosition* nextPosition = &currentPosition;
while (nextPosition = nextPosition->NextFromString(direction)) {
if (chessboard->IsEmptyField(nextPosition) || ignore.count(*nextPosition) == 1) {
// 3.5. When making these moves, the bishop, rook or queen may not move over any intervening pieces.
positions.insert(*nextPosition);
} else {
ChessPiece* chessPiece = chessboard->GetChessPiece(nextPosition);
// 3.1. It is not permitted to move a piece to a square occupied by a piece of the same colour.
// 3.1.1. If a piece moves to a square occupied by an opponent's piece the latter is captured and removed from the chessboard as part of the same move.
if (chessPiece && chessPiece->GetColor() != this->GetColor()) {
positions.insert(*nextPosition);
}
break;
}
}
}
return positions;
}
/**
* Gets a set of all positions the chess piece can move next.
* @return A set of all positions the chess piece can move next.
*/
std::set<ChessPiecePosition> ChessPiece::GetNextPositions() {
return this->_positions_next;
}
/**
* Gets the number of moves of the chess piece.
* @return The number of moves of the chess piece.
*/
int ChessPiece::GetNumberOfMoves() {
int positions = this->_positions.size();
return (positions < 2) ? 0 : positions - 1;
}
/**
* Gets the position of the chess piece.
* @return The position of the chess piece.
* @throws std::out_of_range Thrown if the history of positions was not initialized properly.
*/
ChessPiecePosition ChessPiece::GetPosition() {
if (this->_positions.empty() == false) {
return this->_positions.back();
} else {
throw std::out_of_range("history was not initialized properly.");
}
}
/**
* Gets a set of all positions along the rank.
* @param chessboard A pointer to the chessboard.
* @param ignore A set if chess piece positions to be ignored.
* @return A set of all positions along the rank.
*/
std::set<ChessPiecePosition> ChessPiece::GetRankPositions(Chessboard* chessboard, std::set<ChessPiecePosition> ignore) {
std::set<ChessPiecePosition> positions;
ChessPiecePosition currentPosition = this->GetPosition();
for (std::string direction : {"L1", "R1"}) {
ChessPiecePosition* nextPosition = &currentPosition;
while (nextPosition = nextPosition->NextFromString(direction)) {
if (chessboard->IsEmptyField(nextPosition) || ignore.count(*nextPosition) == 1) {
// 3.5. When making these moves, the bishop, rook or queen may not move over any intervening pieces.
positions.insert(*nextPosition);
} else {
ChessPiece* chessPiece = chessboard->GetChessPiece(nextPosition);
// 3.1. It is not permitted to move a piece to a square occupied by a piece of the same colour.
// 3.1.1. If a piece moves to a square occupied by an opponent's piece the latter is captured and removed from the chessboard as part of the same move.
if (chessPiece && chessPiece->GetColor() != this->GetColor()) {
positions.insert(*nextPosition);
}
break;
}
}
}
return positions;
}
/**
* Gets the unicode symbol of the chess piece depending on the internal color.
* @return The unicode symbol of the chess piece.
*/
std::string ChessPiece::GetUnicode() {
return this->GetUnicode(this->GetColor());
}
/**
* Gets the unicode symbol of the chess piece depending on the given color.
* @param color The color of the chess piece.
* @return The unicode symbol of the chess piece.
*/
std::string ChessPiece::GetUnicode(ChessPieceColor color) {
if (color == ChessPieceColor::Black) {
return std::get<ChessPieceColor::Black>(this->_unicode);
} else {
return std::get<ChessPieceColor::White>(this->_unicode);
}
}
/**
* Status whether the chess piece is a bishop.
* @return Status whether the chess piece is a bishop.
*/
bool ChessPiece::IsBishop() {
return this->GetChar() == this->_CHAR_BISHOP;
}
/**
* Status whether the chess piece can still be moved the first time.
* @return Status whether the chess piece can still be moved the first time.
*/
bool ChessPiece::IsFirstMove() {
return this->_positions.size() == 1;
}
/**
* Status whether the chess piece is a king.
* @return Status whether the chess piece is a king.
*/
bool ChessPiece::IsKing() {
return this->GetChar() == this->_CHAR_KING;
}
/**
* Status whether the chess piece is a knight.
* @return Status whether the chess piece is a knight.
*/
bool ChessPiece::IsKnight() {
return this->GetChar() == this->_CHAR_KNIGHT;
}
/**
* Status whether the chess piece is a pawn.
* @return Status whether the chess piece is a pawn.
*/
bool ChessPiece::IsPawn() {
return this->GetChar() == this->_CHAR_PAWN;
}
/**
* Status whether the chess piece is a protective chess piece for the king.
* Any movement of a protective chess piece would lead to a checkmate.
* @param chessboard A pointer to the chessboard.
* @return Status whether the chess piece is a protective chess piece for the king.
*/
bool ChessPiece::IsProtective(Chessboard* chessboard) {
if (this->IsKing()) {
return false;
}
ChessPiece* chessPieceKing = chessboard->GetChessPieceKing(this->GetColor());
// A chess piece is a protective chess piece if the chess piece exposes the king to an enemy chess piece after any movement.
// So we get all chess piece positions of the opponents chess pieces with and without the current chess piece.
// If any opponents chess piece can reach the king after movement the current chess piece is a protective chess piece.
for (ChessPiece* chessPiece : chessboard->GetChessPieces()) {
if (chessPiece->GetColor() != this->GetColor()) {
std::set<ChessPiecePosition> positionsStay = chessPiece->GetNextPositions(chessboard, {});
std::set<ChessPiecePosition> positionsMove = chessPiece->GetNextPositions(chessboard, {this->GetPosition()});
if (positionsStay.count(chessPieceKing->GetPosition()) == 0 && positionsMove.count(chessPieceKing->GetPosition()) == 1) {
return true;
}
}
}
return false;
}
/**
* Status whether the chess piece is a queen.
* @return Status whether the chess piece is a queen.
*/
bool ChessPiece::IsQueen() {
return this->GetChar() == this->_CHAR_QUEEN;
}
/**
* Status whether the chess piece is a rook.
* @return Status whether the chess piece is a rook.
*/
bool ChessPiece::IsRook() {
return this->GetChar() == this->_CHAR_ROOK;
}
/**
* Sets the color of the chess piece.
* @param color The color of the chess piece.
*/
void ChessPiece::SetColor(ChessPieceColor color) {
this->_color = color;
}
/**
* Sets a set of all positions the chess piece can move next.
* @param positions A set of all positions the chess piece can move next.
*/
void ChessPiece::SetNextPositions(std::set<ChessPiecePosition> positions) {
this->_positions_next = positions;
}
/**
* Sets the current position of the chess piece.
* @param position The current position to be set in the chess piece.
*/
void ChessPiece::SetPosition(ChessPiecePosition position) {
this->_positions.push_back(position);
}
/**
* Updates the internal positions to which the chess piece can move next.
* @param chessboard A pointer to the chessboard.
*/
void ChessPiece::UpdateNextPositions(Chessboard* chessboard) {
if (this->IsProtective(chessboard)) {
this->SetNextPositions({});
} else {
this->SetNextPositions(this->GetNextPositions(chessboard));
}
}