bool board_equal(const board_t * board_1, const board_t * board_2) { int sq_64, sq; ASSERT(board_is_ok(board_1)); ASSERT(board_is_ok(board_2)); // fast comparison if (board_1->key != board_2->key) return false; // slow comparison for (sq_64 = 0; sq_64 < 64; sq_64++) { sq = square_from_64(sq_64); if (board_1->square[sq] != board_2->square[sq]) return false; } if (board_1->turn != board_2->turn) return false; if (board_1->castle[White][SideH] != board_2->castle[White][SideH]) return false; if (board_1->castle[White][SideA] != board_2->castle[White][SideA]) return false; if (board_1->castle[Black][SideH] != board_2->castle[Black][SideH]) return false; if (board_1->castle[Black][SideA] != board_2->castle[Black][SideA]) return false; if (board_1->ep_square != board_2->ep_square) return false; return true; }
void move_undo_null(board_t * board, const undo_t * undo) { ASSERT(board!=NULL); ASSERT(undo!=NULL); ASSERT(board_is_legal(board)); ASSERT(!board_is_check(board)); // update board info board->turn = undo->turn; board->ep_square = undo->ep_square; board->ply_nb = undo->ply_nb; board->cap_sq = undo->cap_sq; board->key = undo->key; // update key stack ASSERT(board->sp>0); board->sp--; // debug ASSERT(board_is_ok(board)); }
int king_pos(const board_t * board, int colour) { ASSERT(board_is_ok(board)); ASSERT(colour_is_ok(colour)); return board->list[colour][0]; }
bool is_in_check(const board_t * board, int colour) { ASSERT(board_is_ok(board)); ASSERT(colour_is_ok(colour)); return is_attacked(board,king_pos(board,colour),colour_opp(colour)); }
void filter_legal(list_t * list, const board_t * board) { int pos; int i, move, value; ASSERT(list_is_ok(list)); ASSERT(board_is_ok(board)); pos = 0; for (i = 0; i < list_size(list); i++) { ASSERT(pos>=0&&pos<=i); move = list_move(list,i); value = list_value(list,i); if (pseudo_is_legal(move,board)) { list->move[pos] = move; list->value[pos] = value; pos++; } } ASSERT(pos>=0&&pos<=list_size(list)); list->size = pos; }
bool piece_attack(const board_t * board, int piece, int from, int to) { int delta; int inc, sq; ASSERT(board_is_ok(board)); ASSERT(piece_is_ok(piece)); ASSERT(square_is_ok(from)); ASSERT(square_is_ok(to)); delta = to - from; ASSERT(delta_is_ok(delta)); if ((piece & DELTA_MASK(delta)) == 0) return false; // no pseudo-attack if (!piece_is_slider(piece)) return true; inc = DELTA_INC(delta); ASSERT(inc_is_ok(inc)); for (sq = from+inc; sq != to; sq += inc) { ASSERT(square_is_ok(sq)); if (board->square[sq] != Empty) return false; // blocker } return true; }
void board_copy(board_t * dst, const board_t * src) { ASSERT(dst!=NULL); ASSERT(board_is_ok(src)); *dst = *src; }
bool board_is_stalemate(const board_t * board) { ASSERT(board_is_ok(board)); if (board_is_check(board)) return false; if (board_can_play(board)) return false; return true; }
int board_mobility(const board_t * board) { list_t list[1]; ASSERT(board_is_ok(board)); gen_legal_moves(list,board); return list_size(list); }
bool move_is_pseudo(int move, const board_t * board) { list_t list[1]; ASSERT(move_is_ok(move)); ASSERT(board_is_ok(board)); gen_moves(list,board); return list_contain(list,move); }
static bool move_is_legal_debug(int move, const board_t * board) { list_t list[1]; ASSERT(move_is_ok(move)); ASSERT(board_is_ok(board)); gen_legal_moves(list,board); return list_contain(list,move); }
bool move_is_legal(int move, const board_t * board) { bool legal; ASSERT(move_is_ok(move)); ASSERT(board_is_ok(board)); legal = move_is_pseudo(move,board) && pseudo_is_legal(move,board); ASSERT(legal==move_is_legal_debug(move,board)); return legal; }
void move_do_null(board_t * board, undo_t * undo) { int sq; ASSERT(board!=NULL); ASSERT(undo!=NULL); ASSERT(board_is_legal(board)); ASSERT(!board_is_check(board)); // initialise undo undo->turn = board->turn; undo->ep_square = board->ep_square; undo->ply_nb = board->ply_nb; undo->cap_sq = board->cap_sq; undo->moving_piece = board->moving_piece; undo->key = board->key; // update key stack ASSERT(board->sp<StackSize); board->stack[board->sp++] = board->key; // update turn board->turn = COLOUR_OPP(board->turn); board->key ^= RANDOM_64(RandomTurn); // update en-passant square sq = board->ep_square; if (sq != SquareNone) { board->key ^= RANDOM_64(RandomEnPassant+SQUARE_FILE(sq)-FileA); board->ep_square = SquareNone; } // update move number board->ply_nb = 0; // HACK: null move is considered as a conversion // update last square board->cap_sq = SquareNone; board->moving_piece = PieceNone256; // debug ASSERT(board_is_ok(board)); }
bool pseudo_is_legal(int move, const board_t * board) { board_t new_board[1]; ASSERT(move_is_ok(move)); ASSERT(board_is_ok(board)); ASSERT(move_is_pseudo(move,board)); board_copy(new_board,board); move_do(new_board,move); return !is_in_check(new_board,colour_opp(new_board->turn)); }
int move_from_san(const char string[], const board_t * board) { char s[256]; int move; ASSERT(string!=NULL); ASSERT(board_is_ok(board)); san_to_lan(string,board,s,256); move = move_from_lan(s,board); ASSERT(!UseSlowDebug||move==move_from_san_debug(string,board)); return move; }
bool board_can_play(const board_t * board) { list_t list[1]; int i, move; ASSERT(board_is_ok(board)); gen_moves(list,board); for (i = 0; i < list_size(list); i++) { move = list_move(list,i); if (pseudo_is_legal(move,board)) return true; } return false; // no legal move }
int move_from_san_debug(const char string[], const board_t * board) { list_t list[1]; int i, move; char move_string[256]; ASSERT(string!=NULL); ASSERT(board_is_ok(board)); gen_legal_moves(list,board); for (i = 0; i < list_size(list); i++) { move = list_move(list,i); if (!move_to_san(move,board,move_string,256)) ASSERT(false); if (my_string_equal(move_string,string)) return move; } return MoveNone; }
bool line_to_san(const move_t line[], const board_t * board, char string[], int size) { board_t new_board[1]; int pos; int move; char move_string[256]; ASSERT(line_is_ok(line)); ASSERT(board_is_ok(board)); ASSERT(string!=NULL); ASSERT(size>=StringSize); // init string[0]='\0'; if (size < StringSize) return false; // return false; board_copy(new_board,board); pos = 0; // loop while ((move = *line++) != MoveNone) { if (pos != 0) { if (pos >= size) return false; string[pos++] = ' '; } if (!move_is_legal(move,new_board) || !move_to_san(move,new_board,&string[pos],size-pos)) { if (Strict || UseDebug) { move_to_can(move,new_board,move_string,sizeof(move_string)); my_log("POLYGLOT ILLEGAL MOVE IN LINE %s\n",move_string); board_disp(new_board); if (Strict) my_fatal("line_to_san(): illegal move\n"); } break; } pos += (int)strlen(&string[pos]); move_do(new_board,move); } if (pos >= size) return false; string[pos] = '\0'; return true; }
void list_disp(const list_t * list, const board_t * board) { int i, move, value; char string[256]; ASSERT(list_is_ok(list)); ASSERT(board_is_ok(board)); for (i = 0; i < list->size; i++) { move = list->move[i]; value = list->value[i]; if (!move_to_can(move,board,string,256)) ASSERT(false); my_log("POLYGLOT %-5s %04X %+4d\n",string,move,value); } my_log("POLYGLOT\n"); }
bool is_attacked(const board_t * board, int to, int colour) { const uint8 * ptr; int from, piece; ASSERT(board_is_ok(board)); ASSERT(square_is_ok(to)); ASSERT(colour_is_ok(colour)); for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) { piece = board->square[from]; ASSERT(colour_equal(piece,colour)); if (piece_attack(board,piece,from,to)) return true; } return false; }
void move_undo_null( const undo_t * undo) { ASSERT(undo!=NULL); // update board info Turn = undo->turn; Key = undo->key; Lock= undo->lock; // update key stack ASSERT(Sp>0); Sp--; // debug ASSERT(board_is_ok(board)); }
static void perft(const board_t * board, int depth) { int me; list_t list[1]; int i, move; board_t new_board[1]; ASSERT(board_is_ok(board)); ASSERT(depth_is_ok(depth)); ASSERT(!is_in_check(board,colour_opp(board->turn))); // init NodeNb++; // leaf if (depth == 0) { LeafNb++; return; } // more init me = board->turn; // move loop gen_moves(list,board); for (i = 0; i < list_size(list); i++) { move = list_move(list,i); board_copy(new_board,board); move_do(new_board,move); if (!is_in_check(new_board,me)) perft(new_board,depth-1); } }
bool game_is_ok(const game_t * game) { board_t board[1]; int pos, move; if (game == NULL) return false; if (game->size < 0 || game->size > GameSize) return false; if (game->pos < 0 || game->pos > game->size) return false; // optional heavy DEBUG mode if (!UseSlowDebug) return true; if (!board_is_ok(game->start_board)) return false; board_copy(board,game->start_board); for (pos = 0; pos <= game->size; pos++) { if (pos == game->pos) { if (!board_equal(game->board,board)) return false; } if (pos >= game->size) break; if (game->key[pos] != board->key) return false; move = game->move[pos]; if (!move_is_legal(move,board)) ; move_do(board,move); } if (game->status != game_comp_status(game)) return false; return true; }
int search_full_root(list_t * list, board_t * board, int a, int b, int depth, int search_type, int ThreadId) { int value; ASSERT(list_is_ok(list)); ASSERT(board_is_ok(board)); ASSERT(depth_is_ok(depth)); ASSERT(search_type==SearchNormal||search_type==SearchShort); ASSERT(list==SearchRoot[ThreadId]->list); ASSERT(!LIST_IS_EMPTY(list)); ASSERT(board==SearchCurrent[ThreadId]->board); ASSERT(board_is_legal(board)); ASSERT(depth>=1); value = full_root(list,board,a,b,depth,0,search_type, ThreadId); ASSERT(value_is_ok(value)); ASSERT(LIST_VALUE(list,0)==value); return value; }
bool line_to_can(const move_t line[], const board_t * board, char string[], int size) { board_t new_board[1]; int pos; int move; ASSERT(line_is_ok(line)); ASSERT(board_is_ok(board)); ASSERT(string!=NULL); ASSERT(size>=StringSize); // init if (size < StringSize) return false; board_copy(new_board,board); pos = 0; // loop while ((move = *line++) != MoveNone) { if (pos != 0) { if (pos >= size) return false; string[pos++] = ' '; } if (!move_to_can(move,new_board,&string[pos],size-pos)) return false; pos += (int)strlen(&string[pos]); move_do(new_board,move); } if (pos >= size) return false; string[pos] = '\0'; return true; }
bool line_from_can (move_t line[], const board_t * board, const char string[], int size) { int pos; char new_string[StringSize], *p; int move; board_t new_board[1]; ASSERT(line!=NULL); ASSERT(board_is_ok(board)); ASSERT(string!=NULL); ASSERT(size>=LineSize); // init pos = 0; board_copy(new_board,board); // loop strcpy(new_string,string); // HACK for (p = strtok(new_string," "); p != NULL; p = strtok(NULL," ")) { move = move_from_can(p,new_board); ASSERT(move!=MoveNone); ASSERT(move_is_legal(move,new_board)); if (move == MoveNone || !move_is_legal(move,new_board)) break; // HACK: ignore illegal moves if (pos >= size) return false; line[pos++] = move; move_do(new_board,move); } if (pos >= size) return false; line[pos] = MoveNone; return true; }
void search_perft(const board_t * board, int depth_max) { int depth; my_timer_t timer[1]; double time, speed; ASSERT(board_is_ok(board)); ASSERT(depth_max>=1&&depth_max<DepthMax); // init board_disp(board); // iterative deepening for (depth = 1; depth <= depth_max; depth++) { // init NodeNb = 0; LeafNb = 0; my_timer_reset(timer); my_timer_start(timer); perft(board,depth); my_timer_stop(timer); time = my_timer_elapsed_cpu(timer); speed = (time < 0.01) ? 0.0 : double(NodeNb) / time; printf("%2d %10lld %10lld %7.2f %7.0f\n",depth,NodeNb,LeafNb,time,speed); } printf("\n"); }
int search_full_root(list_t * list, board_t * board, int depth, int search_type) { int value, a, b; ASSERT(list_is_ok(list)); ASSERT(board_is_ok(board)); ASSERT(depth_is_ok(depth)); ASSERT(search_type==SearchNormal||search_type==SearchShort); ASSERT(list==SearchRoot->list); ASSERT(!LIST_IS_EMPTY(list)); ASSERT(board==SearchCurrent->board); ASSERT(board_is_legal(board)); ASSERT(depth>=1); if (SearchBest[SearchCurrent->multipv].value == 0){ a = -ValueInf; b = +ValueInf; } else{ a = SearchBest[SearchCurrent->multipv].value - 40; b = SearchBest[SearchCurrent->multipv].value + 40; } if (SearchInput->multipv > 0){ a = -ValueInf; b = +ValueInf; } value = full_root(list,board,a,b,depth,0,search_type); ASSERT(value_is_ok(value)); ASSERT(LIST_VALUE(list,0)==value); return value; }
void search() { int move; int depth; int i; bool search_ready; for (i = 0; i < MultiPVMax; i++){ save_multipv[SearchCurrent->multipv].mate = 0; save_multipv[SearchCurrent->multipv].depth = 0; save_multipv[SearchCurrent->multipv].max_depth = 0; save_multipv[SearchCurrent->multipv].value = 0; save_multipv[SearchCurrent->multipv].time = 0; save_multipv[SearchCurrent->multipv].node_nb = 0; strcpy(save_multipv[SearchCurrent->multipv].pv_string,""); } SearchInput->multipv = option_get_int("MultiPV")-1; SearchCurrent->multipv = 0; ASSERT(board_is_ok(SearchInput->board)); // opening book if (option_get_bool("OwnBook") && !SearchInput->infinite) { move = book_move(SearchInput->board); if (move != MoveNone) { // play book move SearchBest[SearchCurrent->multipv].move = move; SearchBest[SearchCurrent->multipv].value = 1; SearchBest[SearchCurrent->multipv].flags = SearchExact; SearchBest[SearchCurrent->multipv].depth = 1; SearchBest[SearchCurrent->multipv].pv[0] = move; SearchBest[SearchCurrent->multipv].pv[1] = MoveNone; search_update_best(); return; } } // SearchInput gen_legal_moves(SearchInput->list,SearchInput->board); if (LIST_SIZE(SearchInput->list) < SearchInput->multipv+1){ SearchInput->multipv = LIST_SIZE(SearchInput->list)-1; } if (LIST_SIZE(SearchInput->list) <= 1) { SearchInput->depth_is_limited = true; SearchInput->depth_limit = 4; // was 1 } // SearchInfo if (setjmp(SearchInfo->buf) != 0) { ASSERT(SearchInfo->can_stop); ASSERT(SearchBest->move!=MoveNone); search_update_current(); return; } // SearchRoot list_copy(SearchRoot->list,SearchInput->list); // SearchCurrent board_copy(SearchCurrent->board,SearchInput->board); my_timer_reset(SearchCurrent->timer); my_timer_start(SearchCurrent->timer); // init trans_inc_date(Trans); sort_init(); search_full_init(SearchRoot->list,SearchCurrent->board); // analyze game for evaluation if (SearchCurrent->board->piece_size[White] < 3 && SearchCurrent->board->piece_size[Black] < 3){ trans_endgame = true; } else{ trans_endgame = false; } // iterative deepening search_ready = false; for (depth = 1; depth < DepthMax; depth++) { for (SearchCurrent->multipv = 0; SearchCurrent->multipv <= SearchInput->multipv; SearchCurrent->multipv++){ if (DispDepthStart && SearchCurrent->multipv == 0) send("info depth %d",depth); SearchCurrent->max_extensions = depth * 10; SearchRoot->bad_1 = false; SearchRoot->change = false; board_copy(SearchCurrent->board,SearchInput->board); if (UseShortSearch && depth <= ShortSearchDepth) { search_full_root(SearchRoot->list,SearchCurrent->board,depth,SearchShort); } else { search_full_root(SearchRoot->list,SearchCurrent->board,depth,SearchNormal); } search_update_current(); if (DispDepthEnd && SearchCurrent->multipv == SearchInput->multipv) { send("info depth %d seldepth %d time %.0f nodes " S64_FORMAT " nps %.0f",depth,SearchCurrent->max_depth,SearchCurrent->time*1000.0,SearchCurrent->node_nb,SearchCurrent->speed); } // update search info if (depth >= 1) SearchInfo->can_stop = true; if (depth == 1 && LIST_SIZE(SearchRoot->list) >= 2 && LIST_VALUE(SearchRoot->list,0) >= LIST_VALUE(SearchRoot->list,1) + EasyThreshold) { SearchRoot->easy = true; } if (depth > 1) { SearchRoot->bad_2 = SearchRoot->bad_1; SearchRoot->bad_1 = false; ASSERT(SearchRoot->bad_2==(SearchBest->value<=SearchRoot->last_value-BadThreshold)); } SearchRoot->last_value = SearchBest[SearchCurrent->multipv].value; // stop search? if (SearchInput->depth_is_limited && SearchCurrent->multipv >= SearchInput->multipv && depth >= SearchInput->depth_limit) { SearchRoot->flag = true; } if (SearchInput->time_is_limited && SearchCurrent->time * 2 >= SearchInput->time_limit_1 && !SearchRoot->bad_2) { SearchRoot->flag = true; } if (SearchInput->time_is_limited && SearchCurrent->time >= SearchInput->time_limit_1 * EasyRatio && SearchRoot->easy) { ASSERT(!SearchRoot->bad_2); ASSERT(!SearchRoot->change); SearchRoot->flag = true; } if (SearchInput->time_is_limited && SearchCurrent->time >= SearchInput->time_limit_1 * EarlyRatio && !SearchRoot->bad_2 && !SearchRoot->change) { SearchRoot->flag = true; } if (SearchInfo->can_stop && (SearchInfo->stop || (SearchRoot->flag && !SearchInput->infinite))) { search_ready = true; break; } } if (search_ready) break; } }
void move_do(board_t * board, int move) { int me, opp; int from, to; int piece, pos, capture; int old_flags, new_flags; int sq, ep_square; int pawn; ASSERT(board_is_ok(board)); ASSERT(move_is_ok(move)); ASSERT(move_is_pseudo(move,board)); // init me = board->turn; opp = colour_opp(me); from = move_from(move); to = move_to(move); piece = board->square[from]; ASSERT(colour_equal(piece,me)); pos = board->pos[from]; ASSERT(pos>=0); // update turn board->turn = opp; board->key ^= random_64(RandomTurn); // update castling rights old_flags = board_flags(board); if (piece_is_king(piece)) { board->castle[me][SideH] = SquareNone; board->castle[me][SideA] = SquareNone; } if (board->castle[me][SideH] == from) board->castle[me][SideH] = SquareNone; if (board->castle[me][SideA] == from) board->castle[me][SideA] = SquareNone; if (board->castle[opp][SideH] == to) board->castle[opp][SideH] = SquareNone; if (board->castle[opp][SideA] == to) board->castle[opp][SideA] = SquareNone; new_flags = board_flags(board); board->key ^= hash_castle_key(new_flags^old_flags); // HACK // update en-passant square ep_square = sq = board->ep_square; if (sq != SquareNone) { board->key ^= random_64(RandomEnPassant+square_file(sq)); board->ep_square = SquareNone; } if (piece_is_pawn(piece) && abs(to-from) == 32) { pawn = piece_make_pawn(opp); if (board->square[to-1] == pawn || board->square[to+1] == pawn) { board->ep_square = sq = (from + to) / 2; board->key ^= random_64(RandomEnPassant+square_file(sq)); } } // update ply number (captures are handled later) board->ply_nb++; if (piece_is_pawn(piece)) board->ply_nb = 0; // conversion // update move number if (me == Black) board->move_nb++; // castle if (colour_equal(board->square[to],me)) { int rank; int king_from, king_to; int rook_from, rook_to; int rook; rank = colour_is_white(me) ? Rank1 : Rank8; king_from = from; rook_from = to; if (to > from) { // h side king_to = square_make(FileG,rank); rook_to = square_make(FileF,rank); } else { // a side king_to = square_make(FileC,rank); rook_to = square_make(FileD,rank); } // remove the rook pos = board->pos[rook_from]; ASSERT(pos>=0); rook = Rook64 | me; // HACK square_clear(board,rook_from,rook); // move the king square_move(board,king_from,king_to,piece); // put the rook back square_set(board,rook_to,rook,pos); ASSERT(board->key==hash_key(board)); return; } // remove the captured piece if (piece_is_pawn(piece) && to == ep_square) { // en-passant capture sq = square_ep_dual(to); capture = board->square[sq]; ASSERT(capture==piece_make_pawn(opp)); square_clear(board,sq,capture); board->ply_nb = 0; // conversion } else { capture = board->square[to]; if (capture != Empty) { // normal capture ASSERT(colour_equal(capture,opp)); ASSERT(!piece_is_king(capture)); square_clear(board,to,capture); board->ply_nb = 0; // conversion } } // move the piece if (move_is_promote(move)) { // promote square_clear(board,from,piece); piece = move_promote_hack(move) | me; // HACK square_set(board,to,piece,pos); } else { // normal move square_move(board,from,to,piece); } ASSERT(board->key==hash_key(board)); }