Chess Engine
C++ chess engine with movegen, bitboards, and Arduino-friendly docs
Loading...
Searching...
No Matches
board.cpp
Go to the documentation of this file.
1// board.c
2
3#include <iostream>
4
5//local
6#include "board.h"
7#include "board_data.h"
8#include "../util/bitboard.h"
9#include "../util/setup.h"
10#include "../util/hash_keys.h"
11
12bool isPieceListValid(const S_BOARD* pos) {
13 for (int piece = wP; piece <= bK; ++piece) {
14 if (pos->pceNum[piece] < 0 || pos->pceNum[piece] >= 10) return FALSE;
15 }
16
17 if (pos->pceNum[wK] != 1 || pos->pceNum[bK] != 1) return FALSE;
18
19 for (int piece = wP; piece <= bK; ++piece) {
20 for (int count = 0; count < pos->pceNum[piece]; ++count) {
21 const int square = pos->pList[piece][count];
22 if (!SqOnBoard(square)) return FALSE;
23 }
24 }
25 return true ;
26}
27
28bool isBoardStateValid(const S_BOARD* pos) {
29 int tempPceNum[13] = {0};
30 int tempBigPce[2] = {0};
31 int tempMajPce[2] = {0};
32 int tempMinPce[2] = {0};
33 int tempMaterial[2] = {0};
34
35 U64 tempPawns[3] = {0ULL, 0ULL, 0ULL};
36 tempPawns[WHITE] = pos->pawns[WHITE];
37 tempPawns[BLACK] = pos->pawns[BLACK];
38 tempPawns[BOTH] = pos->pawns[BOTH];
39
40 // check piece lists
41 for (int piece = wP; piece <= bK; ++piece) {
42 for (int idx = 0; idx < pos->pceNum[piece]; ++idx) {
43 const int sq120 = pos->pList[piece][idx];
44 ASSERT(pos->pieces[sq120] == piece);
45 }
46 }
47
48 // check piece count and other counters
49 for (int sq64 = 0; sq64 < 64; ++sq64) {
50 const int sq120 = SQ120(sq64);
51 const int piece = pos->pieces[sq120];
52 tempPceNum[piece]++;
53
54 const int color = pieceColor[piece];
55 if (isBigPiece[piece] == TRUE) tempBigPce[color]++;
56 if (isMinorPiece[piece] == TRUE) tempMinPce[color]++;
57 if (isMajorPiece[piece] == TRUE) tempMajPce[color]++;
58
59 tempMaterial[color] += pieceValue[piece];
60 }
61
62 for (int piece = wP; piece <= bK; ++piece) {
63 ASSERT(tempPceNum[piece] == pos->pceNum[piece]);
64 }
65
66 // check bitboards count
67 int popCount = CNT(tempPawns[WHITE]);
68 ASSERT(popCount == pos->pceNum[wP]);
69 popCount = CNT(tempPawns[BLACK]);
70 ASSERT(popCount == pos->pceNum[bP]);
71 popCount = CNT(tempPawns[BOTH]);
72 ASSERT(popCount == (pos->pceNum[bP] + pos->pceNum[wP]));
73
74 // check bitboards squares
75 while (tempPawns[WHITE]) {
76 const int sq64 = POP(&tempPawns[WHITE]);
77 ASSERT(pos->pieces[SQ120(sq64)] == wP);
78 }
79
80 while (tempPawns[BLACK]) {
81 const int sq64 = POP(&tempPawns[BLACK]);
82 ASSERT(pos->pieces[SQ120(sq64)] == bP);
83 }
84
85 while (tempPawns[BOTH]) {
86 const int sq64 = POP(&tempPawns[BOTH]);
87 const int p = pos->pieces[SQ120(sq64)];
88 ASSERT(p == bP || p == wP);
89 }
90
91 ASSERT(tempMaterial[WHITE] == pos->material[WHITE] && tempMaterial[BLACK] == pos->material[BLACK]);
92 ASSERT(tempMinPce[WHITE] == pos->minPce[WHITE] && tempMinPce[BLACK] == pos->minPce[BLACK]);
93 ASSERT(tempMajPce[WHITE] == pos->majPce[WHITE] && tempMajPce[BLACK] == pos->majPce[BLACK]);
94 ASSERT(tempBigPce[WHITE] == pos->bigPce[WHITE] && tempBigPce[BLACK] == pos->bigPce[BLACK]);
95
96 ASSERT(pos->side == WHITE || pos->side == BLACK);
98
99 ASSERT(pos->enPas == NO_SQ ||
100 (rankIndex120[pos->enPas] == RANK_6 && pos->side == WHITE) ||
101 (rankIndex120[pos->enPas] == RANK_3 && pos->side == BLACK));
102
103 ASSERT(pos->pieces[pos->KingSq[WHITE]] == wK);
104 ASSERT(pos->pieces[pos->KingSq[BLACK]] == bK);
105
106 ASSERT(pos->castlePerm >= 0 && pos->castlePerm <= 15);
107
109 return true;
110}
111
113 for (int index = 0; index < BRD_SQ_NUM; ++index) {
114 const int square = index;
115 const int piece = pos->pieces[index];
116
118 if (piece != OFFBOARD && piece != EMPTY) {
119 const int color = pieceColor[piece];
120 ASSERT(SideValid(color));
121
122 if (isBigPiece[piece] == TRUE) pos->bigPce[color]++;
123 if (isMinorPiece[piece] == TRUE) pos->minPce[color]++;
124 if (isMajorPiece[piece] == TRUE) pos->majPce[color]++;
125
126 pos->material[color] += pieceValue[piece];
127
128 ASSERT(pos->pceNum[piece] < 10 && pos->pceNum[piece] >= 0);
129 pos->pList[piece][pos->pceNum[piece]] = square;
130 pos->pceNum[piece]++;
131
132 if (piece == wK) pos->KingSq[WHITE] = square;
133 if (piece == bK) pos->KingSq[BLACK] = square;
134
135 if (piece == wP) {
136 SETBIT(pos->pawns[WHITE], SQ64(square));
137 SETBIT(pos->pawns[BOTH], SQ64(square));
138 } else if (piece == bP) {
139 SETBIT(pos->pawns[BLACK], SQ64(square));
140 SETBIT(pos->pawns[BOTH], SQ64(square));
141 }
142 }
143 }
144}
145
146int loadFEN(char* fen, S_BOARD* pos) {
147 ASSERT(fen != NULL);
148 ASSERT(pos != NULL);
149
150 int rank = RANK_8;
151 int file = FILE_A;
152 int piece = 0;
153 int runCount = 0;
154
155 resetBoardState(pos);
156
157 while ((rank >= RANK_1) && *fen) {
158 runCount = 1;
159 switch (*fen) {
160 case 'p': piece = bP; break;
161 case 'r': piece = bR; break;
162 case 'n': piece = bN; break;
163 case 'b': piece = bB; break;
164 case 'k': piece = bK; break;
165 case 'q': piece = bQ; break;
166 case 'P': piece = wP; break;
167 case 'R': piece = wR; break;
168 case 'N': piece = wN; break;
169 case 'B': piece = wB; break;
170 case 'K': piece = wK; break;
171 case 'Q': piece = wQ; break;
172
173 case '1': case '2': case '3': case '4':
174 case '5': case '6': case '7': case '8':
175 piece = EMPTY;
176 runCount = *fen - '0';
177 break;
178
179 case '/':
180 case ' ':
181 --rank;
182 file = FILE_A;
183 ++fen;
184 continue;
185
186 default:
187 printf("FEN error \n");
188 return -1;
189 }
190
191 for (int i = 0; i < runCount; ++i) {
192 const int sq64 = rank * 8 + file;
193 const int sq120 = SQ120(sq64);
194 if (piece != EMPTY) {
195 pos->pieces[sq120] = piece;
196 }
197 ++file;
198 }
199 ++fen;
200 }
201
202 ASSERT(*fen == 'w' || *fen == 'b');
203 pos->side = (*fen == 'w') ? WHITE : BLACK;
204 fen += 2;
205
206 for (int i = 0; i < 4; ++i) {
207 if (*fen == ' ') break;
208 switch (*fen) {
209 case 'K': pos->castlePerm |= WKCA; break;
210 case 'Q': pos->castlePerm |= WQCA; break;
211 case 'k': pos->castlePerm |= BKCA; break;
212 case 'q': pos->castlePerm |= BQCA; break;
213 default: break;
214 }
215 ++fen;
216 }
217 ++fen;
218
219 ASSERT(pos->castlePerm >= 0 && pos->castlePerm <= 15);
220
221 if (*fen != '-') {
222 const int fileIdx = fen[0] - 'a';
223 const int rankIdx = fen[1] - '1';
224
225 ASSERT(fileIdx >= FILE_A && fileIdx <= FILE_H);
226 ASSERT(rankIdx >= RANK_1 && rankIdx <= RANK_8);
227
228 pos->enPas = FR2SQ(fileIdx, rankIdx);
229 }
230
231 pos->posKey = generatePositionKeys(pos);
233 return 0;
234}
235
237 for (int index = 0; index < BRD_SQ_NUM; ++index) {
238 pos->pieces[index] = OFFBOARD;
239 }
240 for (int sq64 = 0; sq64 < 64; ++sq64) {
241 pos->pieces[SQ120(sq64)] = EMPTY;
242 }
243
244 for (int side = 0; side < 2; ++side) {
245 pos->bigPce[side] = 0;
246 pos->majPce[side] = 0;
247 pos->minPce[side] = 0;
248 pos->material[side] = 0;
249 }
250
251 for (int p = 0; p < 3; ++p) {
252 pos->pawns[p] = 0ULL;
253 }
254
255 for (int piece = 0; piece < 13; ++piece) {
256 pos->pceNum[piece] = 0;
257 }
258
259 pos->KingSq[WHITE] = pos->KingSq[BLACK] = NO_SQ;
260
261 pos->side = BOTH;
262 pos->enPas = NO_SQ;
263 pos->fiftyMove = 0;
264
265 pos->ply = 0;
266 pos->hisPly = 0;
267
268 pos->castlePerm = 0;
269 pos->posKey = 0ULL;
270}
271
272void printBoardState(const S_BOARD* pos) {
273 printf("\nGame Board:\n\n");
274
275 for (int rank = RANK_8; rank >= RANK_1; --rank) {
276 printf("%d ", rank + 1);
277 for (int file = FILE_A; file <= FILE_H; ++file) {
278 const int square = FR2SQ(file, rank);
279 const int piece = pos->pieces[square];
280 printf("%3c", pieceToCharacter[piece]);
281 }
282 printf("\n");
283 }
284
285 printf("\n ");
286 for (int file = FILE_A; file <= FILE_H; ++file) {
287 printf("%3c", 'a' + file);
288 }
289 printf("\n");
290
291 printf("side:%c\n", SideChar[pos->side]);
292 printf("enPas:%d\n", pos->enPas);
293 printf("castle:%c%c%c%c\n",
294 (pos->castlePerm & WKCA) ? 'K' : '-',
295 (pos->castlePerm & WQCA) ? 'Q' : '-',
296 (pos->castlePerm & BKCA) ? 'k' : '-',
297 (pos->castlePerm & BQCA) ? 'q' : '-');
298 printf("PosKey:%llX\n", pos->posKey);
299}
300
302 int tempPiecesArray[64];
303 int mirroredSide = pos->side ^ 1;
304 static const int swapPiece[13] = { EMPTY, bP, bN, bB, bR, bQ, bK, wP, wN, wB, wR, wQ, wK };
305 int mirroredCastlePerm = 0;
306 int mirroredEnPas = NO_SQ;
307
308 if (pos->castlePerm & WKCA) mirroredCastlePerm |= BKCA;
309 if (pos->castlePerm & WQCA) mirroredCastlePerm |= BQCA;
310 if (pos->castlePerm & BKCA) mirroredCastlePerm |= WKCA;
311 if (pos->castlePerm & BQCA) mirroredCastlePerm |= WQCA;
312
313 if (pos->enPas != NO_SQ) {
314 mirroredEnPas = SQ120(Mirror64[SQ64(pos->enPas)]);
315 }
316
317 for (int sq = 0; sq < 64; ++sq) {
318 tempPiecesArray[sq] = pos->pieces[SQ120(Mirror64[sq])];
319 }
320
321 resetBoardState(pos);
322
323 for (int sq = 0; sq < 64; ++sq) {
324 const int mapped = swapPiece[tempPiecesArray[sq]];
325 pos->pieces[SQ120(sq)] = mapped;
326 }
327
328 pos->side = mirroredSide;
329 pos->castlePerm = mirroredCastlePerm;
330 pos->enPas = mirroredEnPas;
331 pos->posKey = generatePositionKeys(pos);
332
335}
#define POP(b)
Definition bitboard.h:5
#define CNT(b)
Definition bitboard.h:6
bool isBoardStateValid(const S_BOARD *pos)
Performs a full internal consistency check of the board state.
Definition board.cpp:28
void resetBoardState(S_BOARD *pos)
Reset board to empty state.
Definition board.cpp:236
void mirrorBoardPosition(S_BOARD *pos)
Flip the board vertically, swapping colors and positions.
Definition board.cpp:301
int loadFEN(char *fen, S_BOARD *pos)
Parse a FEN string into the given board state.
Definition board.cpp:146
void updateListsMaterial(S_BOARD *pos)
Update piece lists, material counts, and pawn bitboards from scratch.
Definition board.cpp:112
bool isPieceListValid(const S_BOARD *pos)
Validate that piece list array is consistent with board state.
Definition board.cpp:12
void printBoardState(const S_BOARD *pos)
Print the board to stdout in a human-readable format.
Definition board.cpp:272
bool isMinorPiece[13]
bool isMajorPiece[13]
Definition board_data.cpp:9
int pieceColor[13]
Color of each piece type.
bool isBigPiece[13]
Lookup tables for piece attributes.
Definition board_data.cpp:8
char pieceToCharacter[]
Maps piece, side-to-move, rank and file to their character symbol.
Definition board_data.cpp:3
int pieceValue[13]
Material value of each piece type.
int Mirror64[64]
Square mirroring lookup from white's perspective.
char SideChar[]
Definition board_data.cpp:4
#define FR2SQ(f, r)
Definition defs.h:181
@ FILE_H
Definition defs.h:41
@ FILE_A
Definition defs.h:41
unsigned long long U64
Definition defs.h:26
@ bQ
Definition defs.h:40
@ wN
Definition defs.h:40
@ EMPTY
Definition defs.h:40
@ bN
Definition defs.h:40
@ wR
Definition defs.h:40
@ bP
Definition defs.h:40
@ bR
Definition defs.h:40
@ bB
Definition defs.h:40
@ wB
Definition defs.h:40
@ bK
Definition defs.h:40
@ wP
Definition defs.h:40
@ wK
Definition defs.h:40
@ wQ
Definition defs.h:40
@ WHITE
Definition defs.h:44
@ BOTH
Definition defs.h:44
@ BLACK
Definition defs.h:44
#define BRD_SQ_NUM
Definition defs.h:29
#define SQ64(sq120)
Definition defs.h:182
@ WQCA
Definition defs.h:59
@ BQCA
Definition defs.h:59
@ WKCA
Definition defs.h:59
@ BKCA
Definition defs.h:59
#define SQ120(sq64)
Definition defs.h:183
@ RANK_8
Definition defs.h:42
@ RANK_1
Definition defs.h:42
@ RANK_6
Definition defs.h:42
@ RANK_3
Definition defs.h:42
#define ASSERT(n)
Definition defs.h:14
#define SETBIT(bb, sq)
Definition defs.h:185
@ NO_SQ
Definition defs.h:54
@ OFFBOARD
Definition defs.h:54
@ FALSE
Definition defs.h:57
@ TRUE
Definition defs.h:57
U64 generatePositionKeys(const S_BOARD *board)
Generates a Zobrist hash key for the given board position.
Definition hash_keys.cpp:5
int rankIndex120[BRD_SQ_NUM]
Definition setup.cpp:27
int pList[13][10]
Definition defs.h:127
int pieces[BRD_SQ_NUM]
Definition defs.h:102
int castlePerm
Definition defs.h:114
int pceNum[13]
Definition defs.h:118
int majPce[2]
Definition defs.h:120
int enPas
Definition defs.h:108
U64 pawns[3]
Definition defs.h:103
int KingSq[2]
Definition defs.h:105
int fiftyMove
Definition defs.h:109
int bigPce[2]
Definition defs.h:119
U64 posKey
Definition defs.h:116
int side
Definition defs.h:107
int hisPly
Definition defs.h:112
int ply
Definition defs.h:111
int material[2]
Definition defs.h:122
int minPce[2]
Definition defs.h:121
int PceValidEmptyOffbrd(const int pce)
Checks if the given piece code is empty, valid, or OFFBOARD.
Definition validate.cpp:25
int SqOnBoard(const int sq)
Checks if a given square index refers to a valid on-board square.
Definition validate.cpp:29
int SideValid(const int side)
Checks if the given side identifier is valid.
Definition validate.cpp:34