In the last post, I wrote about assertions. Today, I will talk about how the engine detects attacked squares.
An attacked square is a square that a piece can move to and capture a piece, whether a piece is on that square or not. In military terms, it is the attack radius of a piece. Each piece has a way of moving around the chess board, and is determines whether a square is attacked, or not.
Examples of piece movements are as seen below:
Square Attacked By
Square Attacked By determines whether a square is being attacked by an opposing piece. First of all, we need to determine the movement of each piece on the board. Let's look at the 12*10 mailbox:
Using square 55 as the reference square, if a black knight wants to move, it will land at squares 34, 36, 43, 47, 63, 67, 74, & 76, and if a white piece is on any of these squares, the square is attacked and the piece is captured by the black knight. In order to repeat this when the piece is in another square, we store the number of (consecutive) squares it is going to land in arrays for each of the pieces.
// attack.c
const int KnightDirection[8] = {-8, -19, -21, -12, 8, 19, 21, 12};
const int RookDirection[4] = {-1, -10, 1, 10};
const int BishopDirection[4] = {-11, -9, 11, 9};
const int KingDirection[8] = {-1, -10, 1, 10, -11, -9, 11, 9};
Next is the SqAttacked function:
int SqAttacked(const int sq, const int side, const S_BOARD *pos) {
int piece, index, temp_sq, dir;
// Check for pawns
if (side == WHITE) {
if (pos->pieces[sq - 11] == wP || pos->pieces[sq - 9] == wP) {
return TRUE;
}
} else {
if (pos->pieces[sq + 11] == bP || pos->pieces[sq + 9] == bP) {
return TRUE;
}
}
// Check for knights
for (index = 0; index < 8; index++) {
piece = pos->pieces[sq + KnightDirection[index]];
if (IsKnight(piece) && PieceColour[piece] == side) {
return TRUE;
}
}
// Check for rooks and queens
for (index = 0; index < 4; index++) {
dir = RookDirection[index];
temp_sq = sq + dir;
piece = pos->pieces[temp_sq];
while (piece != OFFBOARD) {
if (piece != EMPTY) {
if (IsRookQueen(piece) && PieceColour[piece] == side) {
return TRUE;
}
break;
}
temp_sq += dir;
piece = pos->pieces[temp_sq];
}
}
// Check for bishops and queens
for (index = 0; index < 4; index++) {
dir = BishopDirection[index];
temp_sq = sq + dir;
piece = pos->pieces[temp_sq];
while (piece != OFFBOARD) {
if (piece != EMPTY) {
if (IsBishopQueen(piece) && PieceColour[piece] == side) {
return TRUE;
}
break;
}
temp_sq += dir;
piece = pos->pieces[temp_sq];
}
}
// Check for kings
for (index = 0; index < 8; index++) {
piece = pos->pieces[sq + KingDirection[index]];
if (IsKing(piece) && PieceColour[piece] == side) {
return TRUE;
}
}
return FALSE;
}
For top to bottom....
Pawns: If the
sideisWHITE, the square looks down(-), and if thesideisBLACK, the square looks up(+). The next condition is to check the 11th or 9th square in that direction. If a pawn of that colour is in the position to attack thesq, then it isTRUE.Knights: For each value per its
indexon theKnightDirectionarray, we got thepieceon that square. Then, the engine checks whether the piece is a knight and if the colour of the piece is the same with the attacking side. If it passes the check, then it isTRUE.Rooks and Queens: This is now different because they are sliding pieces and they need to keep going until they find the piece with the right colour. The
diris theRookDirection[index], thetemp_sqis the square gotten after countingdirfromsq, andpieceis what is ontemp_sq. While thepieceis notOFFBOARD, if it's notEMPTY(empty square), the engine checks whether it's a rook or queen of the attacking side. If it passes the check, then it isTRUE, and the loop is broken. If not, thetemp_sqgoes to another square by adding the value ofdir, and check thepieceon that square.Bishops and Queens: Same as Rooks and Queens, but uses
BishopDirectionandisBishopQueeninstead.Kings: Because of how the king moves, the target
sqchecks whether a king is within one square of it's position in all directions. Basically, it's the same thing as the Knights loop.
If all these checks are not true, then the function returns FALSE.
To test this function, the following instructions are written in the engine's main file:
#include <stdio.h>
#include <stdlib.h>
#include "defs.h"
#define FEN_1 "8/3q1p2/8/5P2/4Q3/8/8/8 w - - 0 1"
void ShowSQAttackedBySide(const int side, const S_BOARD *pos) {
int rank = 0;
int file = 0;
int sq = 0;
printf("\n\nSquares attacked by: %c\n", SideChar[side]);
for (rank = RANK_8; rank >= RANK_1; --rank) {
for (file = FILE_A; file <= FILE_H; file++) {
sq = FR2SQ(file, rank);
if (SqAttacked(sq, side, pos) == TRUE) {
printf("X");
} else {
printf("-");
}
}
printf("\n");
}
printf("\n\n");
}
int main() {
S_BOARD board[1];
ParseFen(FEN_1, board);
PrintBoard(board);
printf("\nSquares attacked by White:\n");
ShowSQAttackedBySide(WHITE, board);
printf("\nSquares attacked by Black:\n");
ShowSQAttackedBySide(BLACK, board);
return 0;
}
Once you compile the program and run it, it will give you this:
So yeah. That's it for now
If you haven't read the previous article, click here so that you can follow along and if you want to see the code, you can click here to view the Github repo.
Until the next commit....bye 👋





Top comments (0)