1
2 // board.cpp
3
4 // includes
5
6 #include <cstdio>
7
8 #include "attack.h"
9 #include "board.h"
10 #include "colour.h"
11 #include "fen.h"
12 #include "hash.h"
13 #include "list.h"
14 #include "move.h"
15 #include "move_do.h"
16 #include "move_gen.h"
17 #include "move_legal.h"
18 #include "piece.h"
19 #include "util.h"
20
21 // constants
22
23 static const bool UseSlowDebug = false;
24
25 // functions
26
27 // board_is_ok()
28
board_is_ok(const board_t * board)29 bool board_is_ok(const board_t * board) {
30
31 int sq, piece;
32 int colour, pos;
33 int king, rook;
34
35 if (board == NULL) return false;
36
37 // optional heavy DEBUG mode
38
39 if (!UseSlowDebug) return true;
40
41 // squares
42
43 for (sq = 0; sq < SquareNb; sq++) {
44 piece = board->square[sq];
45 if (square_is_ok(sq)) {
46 pos = board->pos[sq];
47 if (piece == Empty) {
48 if (pos != -1) return false;
49 } else {
50 if (pos < 0) return false;
51 if (board->list[piece_colour(piece)][pos] != sq) return false;
52 }
53 } else {
54 if (piece != Knight64) return false;
55 }
56 }
57
58 // white piece list
59
60 colour = White;
61 pos = 0;
62
63 if (board->list_size[colour] <= 0 || board->list_size[colour] > 16) return false;
64
65 sq = board->list[colour][pos];
66 if (sq == SquareNone) return false;
67 if (board->pos[sq] != pos) return false;
68 piece = board->square[sq];
69 if (!colour_equal(piece,colour) || !piece_is_king(piece)) return false;
70
71 for (pos++; pos < board->list_size[colour]; pos++) {
72 sq = board->list[colour][pos];
73 if (sq == SquareNone) return false;
74 if (board->pos[sq] != pos) return false;
75 if (!colour_equal(board->square[sq],colour)) return false;
76 }
77
78 sq = board->list[colour][pos];
79 if (sq != SquareNone) return false;
80
81 // black piece list
82
83 colour = Black;
84 pos = 0;
85
86 if (board->list_size[colour] <= 0 || board->list_size[colour] > 16) return false;
87
88 sq = board->list[colour][pos];
89 if (sq == SquareNone) return false;
90 if (board->pos[sq] != pos) return false;
91 piece = board->square[sq];
92 if (!colour_equal(piece,colour) || !piece_is_king(piece)) return false;
93
94 for (pos++; pos < board->list_size[colour]; pos++) {
95 sq = board->list[colour][pos];
96 if (sq == SquareNone) return false;
97 if (board->pos[sq] != pos) return false;
98 if (!colour_equal(board->square[sq],colour)) return false;
99 }
100
101 sq = board->list[colour][pos];
102 if (sq != SquareNone) return false;
103
104 // TODO: material
105
106 if (board->number[WhiteKing12] != 1) return false;
107 if (board->number[BlackKing12] != 1) return false;
108
109 if (!colour_is_ok(board->turn)) return false;
110
111 // castling status
112
113 if (board->castle[White][SideH] != SquareNone) {
114
115 king = board->list[White][0];
116 if (king < A1 || king > H1) return false;
117 if (board->square[king] != WhiteKing256) return false;
118
119 rook = board->castle[White][SideH];
120 if (rook < A1 || rook > H1) return false;
121 if (board->square[rook] != WhiteRook256) return false;
122
123 if (rook <= king) return false;
124 }
125
126 if (board->castle[White][SideA] != SquareNone) {
127
128 king = board->list[White][0];
129 if (king < A1 || king > H1) return false;
130 if (board->square[king] != WhiteKing256) return false;
131
132 rook = board->castle[White][SideA];
133 if (rook < A1 || rook > H1) return false;
134 if (board->square[rook] != WhiteRook256) return false;
135
136 if (rook >= king) return false;
137 }
138
139 if (board->castle[Black][SideH] != SquareNone) {
140
141 king = board->list[Black][0];
142 if (king < A8 || king > H8) return false;
143 if (board->square[king] != BlackKing256) return false;
144
145 rook = board->castle[Black][SideH];
146 if (rook < A8 || rook > H8) return false;
147 if (board->square[rook] != BlackRook256) return false;
148
149 if (rook <= king) return false;
150 }
151
152 if (board->castle[Black][SideA] != SquareNone) {
153
154 king = board->list[Black][0];
155 if (king < A8 || king > H8) return false;
156 if (board->square[king] != BlackKing256) return false;
157
158 rook = board->castle[Black][SideA];
159 if (rook < A8 || rook > H8) return false;
160 if (board->square[rook] != BlackRook256) return false;
161
162 if (rook >= king) return false;
163 }
164
165 return true;
166 }
167
168 // board_clear()
169
board_clear(board_t * board)170 void board_clear(board_t * board) {
171
172 int file, rank, sq;
173 int colour, pos;
174 int piece;
175
176 ASSERT(board!=NULL);
177
178 // edge squares
179
180 for (sq = 0; sq < SquareNb; sq++) {
181 board->square[sq] = Knight64; // HACK: uncoloured knight
182 board->pos[sq] = -1;
183 }
184
185 // empty squares
186
187 for (rank = 0; rank < 8; rank++) {
188 for (file = 0; file < 8; file++) {
189 sq = square_make(file,rank);
190 board->square[sq] = Empty;
191 }
192 }
193
194 // piece lists
195
196 for (colour = 0; colour < 3; colour++) {
197 for (pos = 0; pos < 32; pos++) { // HACK
198 board->list[colour][pos] = SquareNone;
199 }
200 board->list_size[colour] = 0;
201 }
202
203 // material
204
205 for (piece = 0; piece < 12; piece++) {
206 board->number[piece] = 0;
207 }
208
209 // rest
210
211 board->turn = ColourNone;
212 board->castle[White][SideH] = SquareNone;
213 board->castle[White][SideA] = SquareNone;
214 board->castle[Black][SideH] = SquareNone;
215 board->castle[Black][SideA] = SquareNone;
216 board->ep_square = SquareNone;
217
218 board->ply_nb = 0;
219 board->move_nb = 0;
220
221 board->key = 0;
222 }
223
224 // board_start()
225
board_start(board_t * board)226 void board_start(board_t * board) {
227
228 ASSERT(board!=NULL);
229
230 if (!board_from_fen(board,StartFen)) { ASSERT(false); }
231 }
232
233 // board_copy()
234
board_copy(board_t * dst,const board_t * src)235 void board_copy(board_t * dst, const board_t * src) {
236
237 ASSERT(dst!=NULL);
238 ASSERT(board_is_ok(src));
239
240 *dst = *src;
241 }
242
243 // board_equal()
244
board_equal(const board_t * board_1,const board_t * board_2)245 bool board_equal(const board_t * board_1, const board_t * board_2) {
246
247 int sq_64, sq;
248
249 ASSERT(board_is_ok(board_1));
250 ASSERT(board_is_ok(board_2));
251
252 // fast comparison
253
254 if (board_1->key != board_2->key) return false;
255
256 // slow comparison
257
258 for (sq_64 = 0; sq_64 < 64; sq_64++) {
259 sq = square_from_64(sq_64);
260 if (board_1->square[sq] != board_2->square[sq]) return false;
261 }
262
263 if (board_1->turn != board_2->turn) return false;
264 if (board_1->castle[White][SideH] != board_2->castle[White][SideH]) return false;
265 if (board_1->castle[White][SideA] != board_2->castle[White][SideA]) return false;
266 if (board_1->castle[Black][SideH] != board_2->castle[Black][SideH]) return false;
267 if (board_1->castle[Black][SideA] != board_2->castle[Black][SideA]) return false;
268 if (board_1->ep_square != board_2->ep_square) return false;
269
270 return true;
271 }
272
273 // board_init_list()
274
board_init_list(board_t * board)275 void board_init_list(board_t * board) {
276
277 int sq_64, sq, piece;
278 int colour, pos;
279
280 ASSERT(board!=NULL);
281
282 // init
283
284 for (sq_64 = 0; sq_64 < 64; sq_64++) {
285 sq = square_from_64(sq_64);
286 board->pos[sq] = -1;
287 }
288
289 for (piece = 0; piece < 12; piece++) board->number[piece] = 0;
290
291 // white piece list
292
293 colour = White;
294 pos = 0;
295
296 for (sq_64 = 0; sq_64 < 64; sq_64++) {
297 sq = square_from_64(sq_64);
298 piece = board->square[sq];
299 ASSERT(pos>=0&&pos<=16);
300 if (colour_equal(piece,colour) && piece_is_king(piece)) {
301 board->pos[sq] = pos;
302 board->list[colour][pos] = sq;
303 pos++;
304 board->number[piece_to_12(piece)]++;
305 }
306 }
307 ASSERT(pos==1);
308
309 for (sq_64 = 0; sq_64 < 64; sq_64++) {
310 sq = square_from_64(sq_64);
311 piece = board->square[sq];
312 ASSERT(pos>=0&&pos<=16);
313 if (colour_equal(piece,colour) && !piece_is_king(piece)) {
314 board->pos[sq] = pos;
315 board->list[colour][pos] = sq;
316 pos++;
317 board->number[piece_to_12(piece)]++;
318 }
319 }
320
321 ASSERT(pos>=1&&pos<=16);
322 board->list[colour][pos] = SquareNone;
323 board->list_size[colour] = pos;
324
325 // black piece list
326
327 colour = Black;
328 pos = 0;
329
330 for (sq_64 = 0; sq_64 < 64; sq_64++) {
331 sq = square_from_64(sq_64);
332 piece = board->square[sq];
333 ASSERT(pos>=0&&pos<=16);
334 if (colour_equal(piece,colour) && piece_is_king(piece)) {
335 board->pos[sq] = pos;
336 board->list[colour][pos] = sq;
337 pos++;
338 board->number[piece_to_12(piece)]++;
339 }
340 }
341 ASSERT(pos==1);
342
343 for (sq_64 = 0; sq_64 < 64; sq_64++) {
344 sq = square_from_64(sq_64);
345 piece = board->square[sq];
346 ASSERT(pos>=1&&pos<=16);
347 if (colour_equal(piece,colour) && !piece_is_king(piece)) {
348 board->pos[sq] = pos;
349 board->list[colour][pos] = sq;
350 pos++;
351 board->number[piece_to_12(piece)]++;
352 }
353 }
354
355 ASSERT(pos>=1&&pos<=16);
356 board->list[colour][pos] = SquareNone;
357 board->list_size[colour] = pos;
358
359 // hash key
360
361 board->key = hash_key(board);
362 }
363
364 // board_flags()
365
board_flags(const board_t * board)366 int board_flags(const board_t * board) {
367
368 int flags;
369
370 flags = 0;
371
372 if (board->castle[White][SideH] != SquareNone) flags |= 1 << 0;
373 if (board->castle[White][SideA] != SquareNone) flags |= 1 << 1;
374 if (board->castle[Black][SideH] != SquareNone) flags |= 1 << 2;
375 if (board->castle[Black][SideA] != SquareNone) flags |= 1 << 3;
376
377 return flags;
378 }
379
380 // board_can_play()
381
board_can_play(const board_t * board)382 bool board_can_play(const board_t * board) {
383
384 list_t list[1];
385 int i, move;
386
387 ASSERT(board_is_ok(board));
388
389 gen_moves(list,board);
390
391 for (i = 0; i < list_size(list); i++) {
392 move = list_move(list,i);
393 if (pseudo_is_legal(move,board)) return true;
394 }
395
396 return false; // no legal move
397 }
398
399 // board_mobility()
400
board_mobility(const board_t * board)401 int board_mobility(const board_t * board) {
402
403 list_t list[1];
404
405 ASSERT(board_is_ok(board));
406
407 gen_legal_moves(list,board);
408
409 return list_size(list);
410 }
411
412 // board_is_check()
413
board_is_check(const board_t * board)414 bool board_is_check(const board_t * board) {
415
416 ASSERT(board_is_ok(board));
417
418 return is_in_check(board,board->turn);
419 }
420
421 // board_is_mate()
422
board_is_mate(const board_t * board)423 bool board_is_mate(const board_t * board) {
424
425 ASSERT(board_is_ok(board));
426
427 if (!board_is_check(board)) return false;
428 if (board_can_play(board)) return false;
429
430 return true;
431 }
432
433 // board_is_stalemate()
434
board_is_stalemate(const board_t * board)435 bool board_is_stalemate(const board_t * board) {
436
437 ASSERT(board_is_ok(board));
438
439 if (board_is_check(board)) return false;
440 if (board_can_play(board)) return false;
441
442 return true;
443 }
444
445 // king_pos()
446
king_pos(const board_t * board,int colour)447 int king_pos(const board_t * board, int colour) {
448
449 ASSERT(board_is_ok(board));
450 ASSERT(colour_is_ok(colour));
451
452 return board->list[colour][0];
453 }
454
455 // end of board.cpp
456
457