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