Add forgotten files 1.4.70b
[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_init_list()
274
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
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
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
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
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
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
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
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
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