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