308 lines
9.9 KiB
C++
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 = ¤tPosition;
|
|
|
|
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 = ¤tPosition;
|
|
|
|
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 = ¤tPosition;
|
|
|
|
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));
|
|
}
|
|
}
|