31namespace move_predicates {
33constexpr int NSQUARES = 8;
34constexpr int kWPHomeRank = 1;
35constexpr int kBPHomeRank = NSQUARES - 2;
37inline bool valid_king(squareT sqFrom, squareT sqTo) {
38 unsigned distRank = 1 + (sqTo / NSQUARES) - (sqFrom / NSQUARES);
39 unsigned distFyle = 1 + (sqTo % NSQUARES) - (sqFrom % NSQUARES);
40 return distRank <= 2 && distFyle <= 2;
43inline bool valid_knight(squareT sqFrom, squareT sqTo) {
44 int distRank = (sqTo / NSQUARES) - (sqFrom / NSQUARES);
45 int distFyle = (sqTo % NSQUARES) - (sqFrom % NSQUARES);
46 int distProduct = distRank * distFyle;
47 return (distProduct == 2 || distProduct == -2);
50inline int valid_slider(squareT sqFrom, squareT sqTo, pieceT pieceType) {
51 assert(pieceType == QUEEN || pieceType == ROOK || pieceType == BISHOP);
53 int distRank = (sqTo / NSQUARES) - (sqFrom / NSQUARES);
54 int distFyle = (sqTo % NSQUARES) - (sqFrom % NSQUARES);
58 bool isDiagonal =
false;
61 }
else if (distFyle == 0) {
63 }
else if (distFyle == distRank) {
64 sqStep = NSQUARES + 1;
66 }
else if (distFyle == -distRank) {
67 sqStep = NSQUARES - 1;
72 if (pieceType == ROOK && isDiagonal)
74 if (pieceType == BISHOP && !isDiagonal)
80inline bool attack_pawn(squareT sqFrom, squareT sqTo, colorT pieceCol) {
81 int distRank = (sqTo / NSQUARES) - (sqFrom / NSQUARES);
82 int distFyle = (sqTo % NSQUARES) - (sqFrom % NSQUARES);
83 if (pieceCol == WHITE && distRank != 1)
85 if (pieceCol == BLACK && distRank != -1)
88 return (distFyle == 1 || distFyle == -1);
91template <
typename TFunc>
92bool attack_slider(squareT sqFrom, squareT sqTo, pieceT pieceType,
94 int sqStep = valid_slider(sqFrom, sqTo, pieceType);
102 for (
int sq = sqFrom + sqStep; sq != sqTo; sq += sqStep) {
123template <
typename TFunc>
124bool attack(squareT sqFrom, squareT sqTo, pieceT pieceCol, pieceT pieceType,
128 return valid_king(sqFrom, sqTo);
130 return valid_knight(sqFrom, sqTo);
132 return attack_pawn(sqFrom, sqTo, pieceCol);
136 return attack_slider(sqFrom, sqTo, pieceType, isOccupied);
139template <
typename TFunc>
140inline bool pseudo_advance_pawn(squareT sqFrom, squareT sqTo, colorT pieceCol,
142 if ((sqTo % NSQUARES) != (sqFrom % NSQUARES)
146 int fromRank = sqFrom / NSQUARES;
147 int distRank = (sqTo / NSQUARES) - fromRank;
148 if (pieceCol == WHITE)
149 return distRank == 1 || (distRank == 2 && fromRank == kWPHomeRank &&
150 !isOccupied(sqFrom + NSQUARES));
152 return distRank == -1 || (distRank == -2 && fromRank == kBPHomeRank &&
153 !isOccupied(sqFrom - NSQUARES));
156template <
typename TFunc>
157bool pseudo(squareT sqFrom, squareT sqTo, colorT pieceCol, pieceT pieceType,
160 if (pieceType == PAWN &&
161 pseudo_advance_pawn(sqFrom, sqTo, pieceCol, isOccupied))
164 return attack(sqFrom, sqTo, pieceCol, pieceType, isOccupied);
182template <
typename TFunc>
183inline std::pair<pieceT, squareT>
opens_ray(squareT sqFrom, squareT sqTo,
184 squareT sqRay, TFunc isOccupied) {
185 assert(sqRay != sqFrom);
187 int fyleFrom = sqFrom % NSQUARES;
188 int distFyle = (sqRay % NSQUARES) - fyleFrom;
189 int distRank = (sqRay / NSQUARES) - (sqFrom / NSQUARES);
200 if (fyleFrom == 0 || fyleFrom == (NSQUARES - 1))
201 return {INVALID_PIECE, 0};
207 }
else if (distFyle == distRank) {
208 sqStep = NSQUARES + 1;
211 }
else if (distFyle == -distRank) {
212 sqStep = NSQUARES - 1;
213 fyleEdge = NSQUARES - 1;
216 return {INVALID_PIECE, 0};
219 if (sqFrom > sqRay) {
221 fyleEdge = NSQUARES - 1 - fyleEdge;
224 for (
int sq = sqFrom + sqStep; sq != sqRay; sq += sqStep) {
225 if (sq == sqTo || isOccupied(sq))
226 return {INVALID_PIECE, 0};
229 for (
int sq = sqFrom - sqStep; sq < NSQUARES * NSQUARES; sq -= sqStep) {
230 if (sq < 0 || sq == sqTo)
234 return {pt,
static_cast<squareT
>(sq)};
236 if ((sq % NSQUARES) == fyleEdge)
239 return {INVALID_PIECE, 0};
248inline bool blocks_ray(squareT sqFrom, squareT sqTo, squareT sqBlock) {
249 return !move_predicates::attack_slider(sqFrom, sqTo, QUEEN,
250 [&](
auto sq) {
return sq == sqBlock; });
Chess board constants, piece helpers, square geometry, and directions.
bool attack(squareT sqFrom, squareT sqTo, pieceT pieceCol, pieceT pieceType, TFunc isOccupied)
Validate an ATTACK move, that is if a piece placed at sqFrom can capture an enemy piece at sqTo.
Definition move_predicates.h:124
std::pair< pieceT, squareT > opens_ray(squareT sqFrom, squareT sqTo, squareT sqRay, TFunc isOccupied)
Given a pseudo-legal move, this functions return the type and the location of the piece that can poss...
Definition move_predicates.h:183
bool blocks_ray(squareT sqFrom, squareT sqTo, squareT sqBlock)
Checks if there is a valid ray from sqFrom to sqTo and if a piece on sqBlock would block that ray.
Definition move_predicates.h:248