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