175 lines
7.6 KiB
C++

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