1
2 // game.c
3
4 // includes
5
6 #include "attack.h"
7 #include "board.h"
8 #include "fen.h"
9 #include "game.h"
10 #include "list.h"
11 #include "move.h"
12 #include "move_do.h"
13 #include "move_legal.h"
14 #include "piece.h"
15 #include "square.h"
16 #include "util.h"
17
18 // constants
19
20 static const bool UseSlowDebug = FALSE;
21
22 // variables
23
24 game_t Game[1];
25
26 // prototypes
27
28 static void game_update (game_t * game);
29 static int game_comp_status (const game_t * game);
30
31 // functions
32
33 // game_is_ok()
34
game_is_ok(const game_t * game)35 bool game_is_ok(const game_t * game) {
36
37 board_t board[1];
38 int pos, move;
39
40 if (game == NULL) return FALSE;
41
42 if (game->size < 0 || game->size > GameSize) return FALSE;
43 if (game->pos < 0 || game->pos > game->size) return FALSE;
44
45 // optional heavy DEBUG mode
46
47 if (!UseSlowDebug) return TRUE;
48
49 if (!board_is_ok(game->start_board)) return FALSE;
50
51 board_copy(board,game->start_board);
52
53 for (pos = 0; pos <= game->size; pos++) {
54
55 if (pos == game->pos) {
56 if (!board_equal(game->board,board)) return FALSE;
57 }
58
59 if (pos >= game->size) break;
60
61 if (game->key[pos] != board->key) return FALSE;
62
63 move = game->move[pos];
64 //if (!move_is_legal(move,board)); //huh??
65 if (!move_is_legal(move,board)) return FALSE;
66
67 move_do(board,move);
68 }
69
70 if (game->status != game_comp_status(game)) return FALSE;
71
72 return TRUE;
73 }
74
75 // game_clear()
76
game_clear(game_t * game)77 void game_clear(game_t * game) {
78
79 ASSERT(game!=NULL);
80
81 game_init(game,StartFen);
82 }
83
84 // game_init()
85
game_init(game_t * game,const char fen[])86 bool game_init(game_t * game, const char fen[]) {
87
88 ASSERT(game!=NULL);
89 ASSERT(fen!=NULL);
90
91 if (!board_from_fen(game->start_board,fen)) return FALSE;
92
93 game->size = 0;
94
95 board_copy(game->board,game->start_board);
96 game->pos = 0;
97
98 game_update(game);
99
100 return TRUE;
101 }
102
103 // game_status()
104
game_status(const game_t * game)105 int game_status(const game_t * game) {
106
107 ASSERT(game!=NULL);
108
109 return game->status;
110 }
111
112 // game_size()
113
game_size(const game_t * game)114 int game_size(const game_t * game) {
115
116 ASSERT(game!=NULL);
117
118 return game->size;
119 }
120
121 // game_pos()
122
game_pos(const game_t * game)123 int game_pos(const game_t * game) {
124
125 ASSERT(game!=NULL);
126
127 return game->pos;
128 }
129
130 // game_move()
131
game_move(const game_t * game,int pos)132 int game_move(const game_t * game, int pos) {
133
134 ASSERT(game!=NULL);
135 ASSERT(pos>=0&&pos<game->pos);
136
137 return game->move[pos];
138 }
139
140 // game_get_board()
141
game_get_board(const game_t * game,board_t * board)142 void game_get_board(const game_t * game, board_t * board) {
143 game_get_board_ex(game, board, -1);
144 }
145
146 // game_get_board_ex()
147
game_get_board_ex(const game_t * game,board_t * board,int pos)148 void game_get_board_ex(const game_t * game, board_t * board, int pos) {
149
150 int start;
151 int i;
152
153 ASSERT(game!=NULL);
154 ASSERT(board!=NULL);
155 ASSERT(pos==-1||(pos>=0&&pos<=game->size)); // HACK
156
157 if (pos < 0) pos = game->pos;
158
159 if (pos >= game->pos) { // forward from current position
160 start = game->pos;
161 board_copy(board,game->board);
162 } else { // backward => replay the whole game
163 start = 0;
164 board_copy(board,game->start_board);
165 }
166
167 for (i = start; i < pos; i++) move_do(board,game->move[i]);
168 }
169
170 // game_turn()
171
game_turn(const game_t * game)172 int game_turn(const game_t * game) {
173
174 ASSERT(game!=NULL);
175
176 return game->board->turn;
177 }
178
179 // game_move_nb()
180
game_move_nb(const game_t * game)181 int game_move_nb(const game_t * game) {
182
183 ASSERT(game!=NULL);
184
185 return game->board->move_nb;
186 }
187
188 // game_add_move()
189
game_add_move(game_t * game,int move)190 void game_add_move(game_t * game, int move) {
191
192 ASSERT(game!=NULL);
193 ASSERT(move_is_ok(move));
194
195 ASSERT(move_is_legal(move,game->board));
196
197 if (game->pos >= GameSize) my_fatal("game_add_move(): game overflow\n");
198
199 game->move[game->pos] = move;
200 game->key[game->pos] = game->board->key;
201
202 move_do(game->board,move);
203 game->pos++;
204
205 game->size = game->pos; // truncate game, HACK: before calling game_is_ok() in game_update()
206
207 game_update(game);
208 }
209
210 // game_rem_move()
211
game_rem_move(game_t * game)212 void game_rem_move(game_t * game) {
213
214 ASSERT(game!=NULL);
215
216 game_goto(game,game->pos-1);
217
218 game->size = game->pos; // truncate game
219 }
220
221 // game_goto()
222
game_goto(game_t * game,int pos)223 void game_goto(game_t * game, int pos) {
224
225 int i;
226
227 ASSERT(game!=NULL);
228 ASSERT(pos>=0&&pos<=game->size);
229
230 if (pos < game->pos) { // going backward => replay the whole game
231 board_copy(game->board,game->start_board);
232 game->pos = 0;
233 }
234
235 for (i = game->pos; i < pos; i++) move_do(game->board,game->move[i]);
236 ASSERT(i==pos);
237
238 game->pos = pos;
239
240 game_update(game);
241 }
242
243 // game_disp()
244
game_disp(const game_t * game)245 void game_disp(const game_t * game) {
246
247 board_t board[1];
248 int i, move;
249
250 ASSERT(game_is_ok(game));
251
252 board_copy(board,game->start_board);
253
254 board_disp(board);
255
256 for (i = 0; i < game->pos; i++) {
257
258 move = game->move[i];
259 move_disp(move,board);
260
261 move_do(board,move);
262 }
263
264 my_log("POLYGLOT\n");
265
266 board_disp(board);
267 }
268
269 // game_update()
270
game_update(game_t * game)271 static void game_update(game_t * game) {
272
273 ASSERT(game!=NULL);
274
275 game->status = game_comp_status(game);
276
277 ASSERT(game_is_ok(game));
278 }
279
280 // game_comp_status()
281
game_comp_status(const game_t * game)282 static int game_comp_status(const game_t * game) {
283
284 int i, n;
285 int wb, bb;
286 const board_t * board;
287 uint64 key;
288 int start;
289
290 ASSERT(game!=NULL);
291
292 // init
293
294 board = game->board;
295
296 // mate and stalemate
297
298 if (!board_can_play(board)) {
299 if (FALSE) {
300 } else if (is_in_check(board,Black)) { // HACK
301 return WHITE_MATES;
302 } else if (is_in_check(board,White)) { // HACK
303 return BLACK_MATES;
304 } else {
305 return STALEMATE;
306 }
307 }
308
309 // insufficient material
310
311 if (board->number[WhitePawn12] == 0
312 && board->number[BlackPawn12] == 0
313 && board->number[WhiteQueen12] == 0
314 && board->number[BlackQueen12] == 0
315 && board->number[WhiteRook12] == 0
316 && board->number[BlackRook12] == 0) {
317
318 if (board->number[WhiteBishop12]
319 + board->number[BlackBishop12]
320 + board->number[WhiteKnight12]
321 + board->number[BlackKnight12] <= 1) { // KK, KBK and KNK
322
323 return DRAW_MATERIAL;
324
325 } else if (board->number[WhiteBishop12] == 1
326 && board->number[BlackBishop12] == 1
327 && board->number[WhiteKnight12] == 0
328 && board->number[BlackKnight12] == 0) {
329
330 wb = board->list[White][1]; // HACK
331 bb = board->list[Black][1]; // HACK
332
333 if (square_colour(wb) == square_colour(bb)) { // KBKB
334 return DRAW_MATERIAL;
335 }
336 }
337 }
338
339 // 50-move rule
340
341 if (board->ply_nb >= 100) return DRAW_FIFTY;
342
343 // position repetition
344
345 key = board->key;
346 n = 0;
347
348 start = game->pos - board->ply_nb;
349 if (start < 0) start = 0;
350
351 for (i = game->pos-4; i >= start; i -= 2) {
352 if (game->key[i] == key) {
353 if (++n == 2) return DRAW_REPETITION;
354 }
355 }
356
357 return PLAYING;
358 }
359
360 // end of game.cpp
361
362