Add forgotten files 1.4.70b
[polyglot.git] / game.cpp
1 \r
2 // game.cpp\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, int pos) {\r
143 \r
144    int start;\r
145    int i;\r
146 \r
147    ASSERT(game!=NULL);\r
148    ASSERT(board!=NULL);\r
149    ASSERT(pos==-1||(pos>=0&&pos<=game->size)); // HACK\r
150 \r
151    if (pos < 0) pos = game->pos;\r
152 \r
153    if (pos >= game->pos) { // forward from current position\r
154       start = game->pos;\r
155       board_copy(board,game->board);\r
156    } else { // backward => replay the whole game\r
157       start = 0;\r
158       board_copy(board,game->start_board);\r
159    }\r
160 \r
161    for (i = start; i < pos; i++) move_do(board,game->move[i]);\r
162 }\r
163 \r
164 // game_turn()\r
165 \r
166 int game_turn(const game_t * game) {\r
167 \r
168    ASSERT(game!=NULL);\r
169 \r
170    return game->board->turn;\r
171 }\r
172 \r
173 // game_move_nb()\r
174 \r
175 int game_move_nb(const game_t * game) {\r
176 \r
177    ASSERT(game!=NULL);\r
178 \r
179    return game->board->move_nb;\r
180 }\r
181 \r
182 // game_add_move()\r
183 \r
184 void game_add_move(game_t * game, int move) {\r
185 \r
186    ASSERT(game!=NULL);\r
187    ASSERT(move_is_ok(move));\r
188 \r
189    ASSERT(move_is_legal(move,game->board));\r
190 \r
191    if (game->pos >= GameSize) my_fatal("game_add_move(): game overflow\n");\r
192 \r
193    game->move[game->pos] = move;\r
194    game->key[game->pos] = game->board->key;\r
195 \r
196    move_do(game->board,move);\r
197    game->pos++;\r
198 \r
199    game->size = game->pos; // truncate game, HACK: before calling game_is_ok() in game_update()\r
200 \r
201    game_update(game);\r
202 }\r
203 \r
204 // game_rem_move()\r
205 \r
206 void game_rem_move(game_t * game) {\r
207 \r
208    ASSERT(game!=NULL);\r
209 \r
210    game_goto(game,game->pos-1);\r
211 \r
212    game->size = game->pos; // truncate game\r
213 }\r
214 \r
215 // game_goto()\r
216 \r
217 void game_goto(game_t * game, int pos) {\r
218 \r
219    int i;\r
220 \r
221    ASSERT(game!=NULL);\r
222    ASSERT(pos>=0&&pos<=game->size);\r
223 \r
224    if (pos < game->pos) { // going backward => replay the whole game\r
225       board_copy(game->board,game->start_board);\r
226       game->pos = 0;\r
227    }\r
228 \r
229    for (i = game->pos; i < pos; i++) move_do(game->board,game->move[i]);\r
230    ASSERT(i==pos);\r
231 \r
232    game->pos = pos;\r
233 \r
234    game_update(game);\r
235 }\r
236 \r
237 // game_disp()\r
238 \r
239 void game_disp(const game_t * game) {\r
240 \r
241    board_t board[1];\r
242    int i, move;\r
243 \r
244    ASSERT(game_is_ok(game));\r
245 \r
246    board_copy(board,game->start_board);\r
247 \r
248    board_disp(board);\r
249 \r
250    for (i = 0; i < game->pos; i++) {\r
251 \r
252       move = game->move[i];\r
253       move_disp(move,board);\r
254 \r
255       move_do(board,move);\r
256    }\r
257 \r
258    my_log("POLYGLOT\n");\r
259 \r
260    board_disp(board);\r
261 }\r
262 \r
263 // game_update()\r
264 \r
265 static void game_update(game_t * game) {\r
266 \r
267    ASSERT(game!=NULL);\r
268 \r
269    game->status = game_comp_status(game);\r
270 \r
271    ASSERT(game_is_ok(game));\r
272 }\r
273 \r
274 // game_comp_status()\r
275 \r
276 static int game_comp_status(const game_t * game) {\r
277 \r
278    int i, n;\r
279    int wb, bb;\r
280    const board_t * board;\r
281    uint64 key;\r
282    int start;\r
283 \r
284    ASSERT(game!=NULL);\r
285 \r
286    // init\r
287 \r
288    board = game->board;\r
289 \r
290    // mate and stalemate\r
291 \r
292    if (!board_can_play(board)) {\r
293       if (false) {\r
294       } else if (is_in_check(board,Black)) { // HACK\r
295          return WHITE_MATES;\r
296       } else if (is_in_check(board,White)) { // HACK\r
297          return BLACK_MATES;\r
298       } else {\r
299          return STALEMATE;\r
300       }\r
301    }\r
302 \r
303    // insufficient material\r
304 \r
305    if (board->number[WhitePawn12]  == 0\r
306     && board->number[BlackPawn12]  == 0\r
307     && board->number[WhiteQueen12] == 0\r
308     && board->number[BlackQueen12] == 0\r
309     && board->number[WhiteRook12]  == 0\r
310     && board->number[BlackRook12]  == 0) {\r
311 \r
312       if (board->number[WhiteBishop12]\r
313         + board->number[BlackBishop12]\r
314         + board->number[WhiteKnight12]\r
315         + board->number[BlackKnight12] <= 1) { // KK, KBK and KNK\r
316 \r
317          return DRAW_MATERIAL;\r
318 \r
319       } else if (board->number[WhiteBishop12] == 1\r
320               && board->number[BlackBishop12] == 1\r
321               && board->number[WhiteKnight12] == 0\r
322               && board->number[BlackKnight12] == 0) {\r
323 \r
324          wb = board->list[White][1]; // HACK\r
325          bb = board->list[Black][1]; // HACK\r
326 \r
327          if (square_colour(wb) == square_colour(bb)) { // KBKB\r
328             return DRAW_MATERIAL;\r
329          }\r
330       }\r
331    }\r
332 \r
333    // 50-move rule\r
334 \r
335    if (board->ply_nb >= 100) return DRAW_FIFTY;\r
336 \r
337    // position repetition\r
338 \r
339    key = board->key;\r
340    n = 0;\r
341 \r
342    start = game->pos - board->ply_nb;\r
343    if (start < 0) start = 0;\r
344 \r
345    for (i = game->pos-4; i >= start; i -= 2) {\r
346       if (game->key[i] == key) {\r
347          if (++n == 2) return DRAW_REPETITION;\r
348       }\r
349    }\r
350 \r
351    return PLAYING;\r
352 }\r
353 \r
354 // end of game.cpp\r
355 \r