Alter version number to 2.0.4
[polyglot.git] / board.c
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
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
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
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
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
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_has_queen()
274
275 bool board_has_queen(const board_t * board, int colour) {
276
277    int sq_64, sq, piece;
278
279    ASSERT(board!=NULL);
280
281    for (sq_64 = 0; sq_64 < 64; sq_64++) {
282       sq = square_from_64(sq_64);
283       piece = board->square[sq];
284       if (colour_equal(piece,colour) && piece_is_queen(piece)) {
285          return TRUE;
286       }
287    }
288    return FALSE;
289 }
290
291 // board_init_list()
292
293 void board_init_list(board_t * board) {
294
295    int sq_64, sq, piece;
296    int colour, pos;
297
298    ASSERT(board!=NULL);
299
300    // init
301
302    for (sq_64 = 0; sq_64 < 64; sq_64++) {
303       sq = square_from_64(sq_64);
304       board->pos[sq] = -1;
305    }
306
307    for (piece = 0; piece < 12; piece++) board->number[piece] = 0;
308
309    // white piece list
310
311    colour = White;
312    pos = 0;
313
314    for (sq_64 = 0; sq_64 < 64; sq_64++) {
315       sq = square_from_64(sq_64);
316       piece = board->square[sq];
317       ASSERT(pos>=0&&pos<=16);
318       if (colour_equal(piece,colour) && piece_is_king(piece)) {
319          board->pos[sq] = pos;
320          board->list[colour][pos] = sq;
321          pos++;
322          board->number[piece_to_12(piece)]++;
323       }
324    }
325    ASSERT(pos==1);
326
327    for (sq_64 = 0; sq_64 < 64; sq_64++) {
328       sq = square_from_64(sq_64);
329       piece = board->square[sq];
330       ASSERT(pos>=0&&pos<=16);
331       if (colour_equal(piece,colour) && !piece_is_king(piece)) {
332          board->pos[sq] = pos;
333          board->list[colour][pos] = sq;
334          pos++;
335          board->number[piece_to_12(piece)]++;
336       }
337    }
338
339    ASSERT(pos>=1&&pos<=16);
340    board->list[colour][pos] = SquareNone;
341    board->list_size[colour] = pos;
342
343    // black piece list
344
345    colour = Black;
346    pos = 0;
347
348    for (sq_64 = 0; sq_64 < 64; sq_64++) {
349       sq = square_from_64(sq_64);
350       piece = board->square[sq];
351       ASSERT(pos>=0&&pos<=16);
352       if (colour_equal(piece,colour) && piece_is_king(piece)) {
353          board->pos[sq] = pos;
354          board->list[colour][pos] = sq;
355          pos++;
356          board->number[piece_to_12(piece)]++;
357       }
358    }
359    ASSERT(pos==1);
360
361    for (sq_64 = 0; sq_64 < 64; sq_64++) {
362       sq = square_from_64(sq_64);
363       piece = board->square[sq];
364       ASSERT(pos>=1&&pos<=16);
365       if (colour_equal(piece,colour) && !piece_is_king(piece)) {
366          board->pos[sq] = pos;
367          board->list[colour][pos] = sq;
368          pos++;
369          board->number[piece_to_12(piece)]++;
370       }
371    }
372
373    ASSERT(pos>=1&&pos<=16);
374    board->list[colour][pos] = SquareNone;
375    board->list_size[colour] = pos;
376
377    // hash key
378
379    board->key = hash_key(board);
380 }
381
382 // board_flags()
383
384 int board_flags(const board_t * board) {
385
386    int flags;
387
388    flags = 0;
389
390    if (board->castle[White][SideH] != SquareNone) flags |= 1 << 0;
391    if (board->castle[White][SideA] != SquareNone) flags |= 1 << 1;
392    if (board->castle[Black][SideH] != SquareNone) flags |= 1 << 2;
393    if (board->castle[Black][SideA] != SquareNone) flags |= 1 << 3;
394
395    return flags;
396 }
397
398 // board_can_play()
399
400 bool board_can_play(const board_t * board) {
401
402    list_t list[1];
403    int i, move;
404
405    ASSERT(board_is_ok(board));
406
407    gen_moves(list,board);
408
409    for (i = 0; i < list_size(list); i++) {
410       move = list_move(list,i);
411       if (pseudo_is_legal(move,board)) return TRUE;
412    }
413
414    return FALSE; // no legal move
415 }
416
417 // board_mobility()
418
419 int board_mobility(const board_t * board) {
420
421    list_t list[1];
422
423    ASSERT(board_is_ok(board));
424
425    gen_legal_moves(list,board);
426
427    return list_size(list);
428 }
429
430 // board_is_check()
431
432 bool board_is_check(const board_t * board) {
433
434    ASSERT(board_is_ok(board));
435
436    return is_in_check(board,board->turn);
437 }
438
439 // board_is_mate()
440
441 bool board_is_mate(const board_t * board) {
442
443    ASSERT(board_is_ok(board));
444
445    if (!board_is_check(board)) return FALSE;
446    if (board_can_play(board)) return FALSE;
447
448    return TRUE;
449 }
450
451 // board_is_stalemate()
452
453 bool board_is_stalemate(const board_t * board) {
454
455    ASSERT(board_is_ok(board));
456
457    if (board_is_check(board)) return FALSE;
458    if (board_can_play(board)) return FALSE;
459
460    return TRUE;
461 }
462
463 // king_pos()
464
465 int king_pos(const board_t * board, int colour) {
466
467    ASSERT(board_is_ok(board));
468    ASSERT(colour_is_ok(colour));
469
470    return board->list[colour][0];
471 }
472
473 // board_disp()
474
475 void board_disp(const board_t * board) {
476
477    int file, rank, sq;
478    int piece, c;
479    char fen[256];
480    char row[9];
481    char line[256];
482
483    ASSERT(board!=NULL);
484
485    if (!board_to_fen(board,fen,256)) ASSERT(FALSE);
486    my_log("POLYGLOT FEN %s\n",fen);
487    my_log("POLYGLOT *** CURRENT BOARD ***\n");
488
489    for (rank = 7; rank >= 0; rank--) {
490
491       for (file = 0; file < 8; file++) {
492
493          sq = square_make(file,rank);
494          piece = board->square[sq];
495
496          c = (piece != Empty) ? piece_to_char(piece) : '-';
497          row[file]=c;
498       }
499       row[8]='\0';
500       snprintf(line,sizeof(line),"POLYGLOT %s\n",row);
501       line[sizeof(line)-1]='\0';
502       my_log(line);
503    }
504
505    my_log("POLYGLOT %s to play\n",(colour_is_black(board->turn))?"black":"white");
506    my_log("POLYGLOT\n");
507 }
508
509 // end of board.cpp
510