1 
2 // board.c
3 
4 // includes
5 
6 #include <stdio.h>
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 // board_disp()
456 
board_disp(const board_t * board)457 void board_disp(const board_t * board) {
458 
459    int file, rank, sq;
460    int piece, c;
461    char fen[256];
462    char row[9];
463    char line[256];
464 
465    ASSERT(board!=NULL);
466 
467    if (!board_to_fen(board,fen,256)) ASSERT(FALSE);
468    my_log("POLYGLOT FEN %s\n",fen);
469    my_log("POLYGLOT *** CURRENT BOARD ***\n");
470 
471    for (rank = 7; rank >= 0; rank--) {
472 
473       for (file = 0; file < 8; file++) {
474 
475          sq = square_make(file,rank);
476          piece = board->square[sq];
477 
478          c = (piece != Empty) ? piece_to_char(piece) : '-';
479          row[file]=c;
480       }
481       row[8]='\0';
482       snprintf(line,sizeof(line),"POLYGLOT %s\n",row);
483       line[sizeof(line)-1]='\0';
484       my_log(line);
485    }
486 
487    my_log("POLYGLOT %s to play\n",(colour_is_black(board->turn))?"black":"white");
488    my_log("POLYGLOT\n");
489 }
490 
491 // end of board.cpp
492 
493