--- /dev/null
+\r
+// game.c\r
+\r
+// includes\r
+\r
+#include "attack.h"\r
+#include "board.h"\r
+#include "fen.h"\r
+#include "game.h"\r
+#include "list.h"\r
+#include "move.h"\r
+#include "move_do.h"\r
+#include "move_legal.h"\r
+#include "piece.h"\r
+#include "square.h"\r
+#include "util.h"\r
+\r
+// constants\r
+\r
+static const bool UseSlowDebug = FALSE;\r
+\r
+// variables\r
+\r
+game_t Game[1];\r
+\r
+// prototypes\r
+\r
+static void game_update (game_t * game);\r
+static int game_comp_status (const game_t * game);\r
+\r
+// functions\r
+\r
+// game_is_ok()\r
+\r
+bool game_is_ok(const game_t * game) {\r
+\r
+ board_t board[1];\r
+ int pos, move;\r
+\r
+ if (game == NULL) return FALSE;\r
+\r
+ if (game->size < 0 || game->size > GameSize) return FALSE;\r
+ if (game->pos < 0 || game->pos > game->size) return FALSE;\r
+\r
+ // optional heavy DEBUG mode\r
+\r
+ if (!UseSlowDebug) return TRUE;\r
+\r
+ if (!board_is_ok(game->start_board)) return FALSE;\r
+\r
+ board_copy(board,game->start_board);\r
+\r
+ for (pos = 0; pos <= game->size; pos++) {\r
+\r
+ if (pos == game->pos) {\r
+ if (!board_equal(game->board,board)) return FALSE;\r
+ }\r
+\r
+ if (pos >= game->size) break;\r
+\r
+ if (game->key[pos] != board->key) return FALSE;\r
+\r
+ move = game->move[pos];\r
+ //if (!move_is_legal(move,board)); //huh??\r
+ if (!move_is_legal(move,board)) return FALSE; \r
+\r
+ move_do(board,move);\r
+ }\r
+\r
+ if (game->status != game_comp_status(game)) return FALSE;\r
+\r
+ return TRUE;\r
+}\r
+\r
+// game_clear()\r
+\r
+void game_clear(game_t * game) {\r
+\r
+ ASSERT(game!=NULL);\r
+\r
+ game_init(game,StartFen);\r
+}\r
+\r
+// game_init()\r
+\r
+bool game_init(game_t * game, const char fen[]) {\r
+\r
+ ASSERT(game!=NULL);\r
+ ASSERT(fen!=NULL);\r
+\r
+ if (!board_from_fen(game->start_board,fen)) return FALSE;\r
+\r
+ game->size = 0;\r
+\r
+ board_copy(game->board,game->start_board);\r
+ game->pos = 0;\r
+\r
+ game_update(game);\r
+\r
+ return TRUE;\r
+}\r
+\r
+// game_status()\r
+\r
+int game_status(const game_t * game) {\r
+\r
+ ASSERT(game!=NULL);\r
+\r
+ return game->status;\r
+}\r
+\r
+// game_size()\r
+\r
+int game_size(const game_t * game) {\r
+\r
+ ASSERT(game!=NULL);\r
+\r
+ return game->size;\r
+}\r
+\r
+// game_pos()\r
+\r
+int game_pos(const game_t * game) {\r
+\r
+ ASSERT(game!=NULL);\r
+\r
+ return game->pos;\r
+}\r
+\r
+// game_move()\r
+\r
+int game_move(const game_t * game, int pos) {\r
+\r
+ ASSERT(game!=NULL);\r
+ ASSERT(pos>=0&&pos<game->pos);\r
+\r
+ return game->move[pos];\r
+}\r
+\r
+// game_get_board()\r
+\r
+void game_get_board(const game_t * game, board_t * board) {\r
+ game_get_board_ex(game, board, -1);\r
+}\r
+\r
+// game_get_board_ex()\r
+\r
+void game_get_board_ex(const game_t * game, board_t * board, int pos) {\r
+\r
+ int start;\r
+ int i;\r
+\r
+ ASSERT(game!=NULL);\r
+ ASSERT(board!=NULL);\r
+ ASSERT(pos==-1||(pos>=0&&pos<=game->size)); // HACK\r
+\r
+ if (pos < 0) pos = game->pos;\r
+\r
+ if (pos >= game->pos) { // forward from current position\r
+ start = game->pos;\r
+ board_copy(board,game->board);\r
+ } else { // backward => replay the whole game\r
+ start = 0;\r
+ board_copy(board,game->start_board);\r
+ }\r
+\r
+ for (i = start; i < pos; i++) move_do(board,game->move[i]);\r
+}\r
+\r
+// game_turn()\r
+\r
+int game_turn(const game_t * game) {\r
+\r
+ ASSERT(game!=NULL);\r
+\r
+ return game->board->turn;\r
+}\r
+\r
+// game_move_nb()\r
+\r
+int game_move_nb(const game_t * game) {\r
+\r
+ ASSERT(game!=NULL);\r
+\r
+ return game->board->move_nb;\r
+}\r
+\r
+// game_add_move()\r
+\r
+void game_add_move(game_t * game, int move) {\r
+\r
+ ASSERT(game!=NULL);\r
+ ASSERT(move_is_ok(move));\r
+\r
+ ASSERT(move_is_legal(move,game->board));\r
+\r
+ if (game->pos >= GameSize) my_fatal("game_add_move(): game overflow\n");\r
+\r
+ game->move[game->pos] = move;\r
+ game->key[game->pos] = game->board->key;\r
+\r
+ move_do(game->board,move);\r
+ game->pos++;\r
+\r
+ game->size = game->pos; // truncate game, HACK: before calling game_is_ok() in game_update()\r
+\r
+ game_update(game);\r
+}\r
+\r
+// game_rem_move()\r
+\r
+void game_rem_move(game_t * game) {\r
+\r
+ ASSERT(game!=NULL);\r
+\r
+ game_goto(game,game->pos-1);\r
+\r
+ game->size = game->pos; // truncate game\r
+}\r
+\r
+// game_goto()\r
+\r
+void game_goto(game_t * game, int pos) {\r
+\r
+ int i;\r
+\r
+ ASSERT(game!=NULL);\r
+ ASSERT(pos>=0&&pos<=game->size);\r
+\r
+ if (pos < game->pos) { // going backward => replay the whole game\r
+ board_copy(game->board,game->start_board);\r
+ game->pos = 0;\r
+ }\r
+\r
+ for (i = game->pos; i < pos; i++) move_do(game->board,game->move[i]);\r
+ ASSERT(i==pos);\r
+\r
+ game->pos = pos;\r
+\r
+ game_update(game);\r
+}\r
+\r
+// game_disp()\r
+\r
+void game_disp(const game_t * game) {\r
+\r
+ board_t board[1];\r
+ int i, move;\r
+\r
+ ASSERT(game_is_ok(game));\r
+\r
+ board_copy(board,game->start_board);\r
+\r
+ board_disp(board);\r
+\r
+ for (i = 0; i < game->pos; i++) {\r
+\r
+ move = game->move[i];\r
+ move_disp(move,board);\r
+\r
+ move_do(board,move);\r
+ }\r
+\r
+ my_log("POLYGLOT\n");\r
+\r
+ board_disp(board);\r
+}\r
+\r
+// game_update()\r
+\r
+static void game_update(game_t * game) {\r
+\r
+ ASSERT(game!=NULL);\r
+\r
+ game->status = game_comp_status(game);\r
+\r
+ ASSERT(game_is_ok(game));\r
+}\r
+\r
+// game_comp_status()\r
+\r
+static int game_comp_status(const game_t * game) {\r
+\r
+ int i, n;\r
+ int wb, bb;\r
+ const board_t * board;\r
+ uint64 key;\r
+ int start;\r
+\r
+ ASSERT(game!=NULL);\r
+\r
+ // init\r
+\r
+ board = game->board;\r
+\r
+ // mate and stalemate\r
+\r
+ if (!board_can_play(board)) {\r
+ if (FALSE) {\r
+ } else if (is_in_check(board,Black)) { // HACK\r
+ return WHITE_MATES;\r
+ } else if (is_in_check(board,White)) { // HACK\r
+ return BLACK_MATES;\r
+ } else {\r
+ return STALEMATE;\r
+ }\r
+ }\r
+\r
+ // insufficient material\r
+\r
+ if (board->number[WhitePawn12] == 0\r
+ && board->number[BlackPawn12] == 0\r
+ && board->number[WhiteQueen12] == 0\r
+ && board->number[BlackQueen12] == 0\r
+ && board->number[WhiteRook12] == 0\r
+ && board->number[BlackRook12] == 0) {\r
+\r
+ if (board->number[WhiteBishop12]\r
+ + board->number[BlackBishop12]\r
+ + board->number[WhiteKnight12]\r
+ + board->number[BlackKnight12] <= 1) { // KK, KBK and KNK\r
+\r
+ return DRAW_MATERIAL;\r
+\r
+ } else if (board->number[WhiteBishop12] == 1\r
+ && board->number[BlackBishop12] == 1\r
+ && board->number[WhiteKnight12] == 0\r
+ && board->number[BlackKnight12] == 0) {\r
+\r
+ wb = board->list[White][1]; // HACK\r
+ bb = board->list[Black][1]; // HACK\r
+\r
+ if (square_colour(wb) == square_colour(bb)) { // KBKB\r
+ return DRAW_MATERIAL;\r
+ }\r
+ }\r
+ }\r
+\r
+ // 50-move rule\r
+\r
+ if (board->ply_nb >= 100) return DRAW_FIFTY;\r
+\r
+ // position repetition\r
+\r
+ key = board->key;\r
+ n = 0;\r
+\r
+ start = game->pos - board->ply_nb;\r
+ if (start < 0) start = 0;\r
+\r
+ for (i = game->pos-4; i >= start; i -= 2) {\r
+ if (game->key[i] == key) {\r
+ if (++n == 2) return DRAW_REPETITION;\r
+ }\r
+ }\r
+\r
+ return PLAYING;\r
+}\r
+\r
+// end of game.cpp\r
+\r