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