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