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)); }
void move_eval(const board_t * board, int eval) { int index; int best_value, value; int move; ASSERT(board!=NULL); ASSERT(value_is_ok(eval)); move = board->move; ASSERT(move_is_ok(move)); // exceptions if ((move & (1 << 15)) != 0) return; if (MOVE_TO(move) == board->cap_sq) return; if (MOVE_IS_CASTLE(move)) return; ASSERT(!MOVE_IS_PROMOTE(move)); ASSERT(!MOVE_IS_EN_PASSANT(move)); ASSERT(board->cap_sq==Empty); ASSERT(!board_is_check(board)); index = PIECE_TO_12(board->square[MOVE_TO(move)]) * 64 + SQUARE_TO_64(MOVE_TO(move)); ASSERT(index>=0&&index<HistorySize); if (eval > ValueQueen) { value = ValueQueen; } else if (eval < -ValueQueen) { value = -ValueQueen; } else { value = eval; } best_value = HistEval[index]; ASSERT(best_value<=HistoryEvalMax); ASSERT(best_value>=-HistoryEvalMax); if (value >= best_value) { if (value == HistoryEvalValue) value++; HistEval[index] = value; } else { if (HistEval[index] > -ValueQueen) { if (best_value == HistoryEvalValue+1) { HistEval[index] -= 2; } else { HistEval[index]--; } } } ASSERT(HistEval[index]!=HistoryEvalValue); ASSERT(HistEval[index]<=HistoryEvalMax); ASSERT(HistEval[index]>=-HistoryEvalMax); }
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; }
static bool move_is_pseudo_debug(int move, board_t * board) { list_t list[1]; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(!board_is_check(board)); gen_moves(list,board); return list_contain(list,move); }
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)); }
static bool simple_stalemate(const board_t * board) { int me, opp; int king; int opp_flag; int from, to; int capture; const inc_t * inc_ptr; int inc; ASSERT(board!=NULL); ASSERT(board_is_legal(board)); ASSERT(!board_is_check(board)); // lone king? me = board->turn; if (board->piece_size[me] != 1 || board->pawn_size[me] != 0) return false; // no // king in a corner? king = KING_POS(board,me); if (king != A1 && king != H1 && king != A8 && king != H8) return false; // no // init opp = COLOUR_OPP(me); opp_flag = COLOUR_FLAG(opp); // king can move? from = king; for (inc_ptr = KingInc; (inc=*inc_ptr) != IncNone; inc_ptr++) { to = from + inc; capture = board->square[to]; if (capture == Empty || FLAG_IS(capture,opp_flag)) { if (!is_attacked(board,to,opp)) return false; // legal king move } } // no legal move ASSERT(board_is_stalemate((board_t*)board)); return true; }
void gen_quiet_moves(list_t * list, const board_t * board) { ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(!board_is_check(board)); LIST_CLEAR(list); add_quiet_moves(list,board); add_castle_moves(list,board); // debug ASSERT(list_is_ok(list)); }
bool quiet_is_pseudo( int move, board_t *board ) { int to; ASSERT(move_is_ok(move)); ASSERT(board != NULL); ASSERT(!board_is_check(board)); to = MOVE_TO(move); ASSERT(SQUARE_IS_OK(to)); if( board->square[to] != Empty ) return false; // capture return move_is_pseudo(move, board ); }
static void add_castle_moves(list_t * list, const board_t * board) { ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(!board_is_check(board)); if (COLOUR_IS_WHITE(board->turn)) { if ((board->flags & FlagsWhiteKingCastle) != 0 && board->square[F1] == Empty && board->square[G1] == Empty && !is_attacked(board,F1,Black)) { LIST_ADD(list,MOVE_MAKE_FLAGS(E1,G1,MoveCastle)); } if ((board->flags & FlagsWhiteQueenCastle) != 0 && board->square[D1] == Empty && board->square[C1] == Empty && board->square[B1] == Empty && !is_attacked(board,D1,Black)) { LIST_ADD(list,MOVE_MAKE_FLAGS(E1,C1,MoveCastle)); } } else { // black if ((board->flags & FlagsBlackKingCastle) != 0 && board->square[F8] == Empty && board->square[G8] == Empty && !is_attacked(board,F8,White)) { LIST_ADD(list,MOVE_MAKE_FLAGS(E8,G8,MoveCastle)); } if ((board->flags & FlagsBlackQueenCastle) != 0 && board->square[D8] == Empty && board->square[C8] == Empty && board->square[B8] == Empty && !is_attacked(board,D8,White)) { LIST_ADD(list,MOVE_MAKE_FLAGS(E8,C8,MoveCastle)); } } }
static bool gen_evasions(list_t * list, const board_t * board, const attack_t * attack, bool legal, bool stop) { int me, opp; int opp_flag; int king; const inc_t * inc_ptr; int inc; int to; int piece; ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(attack!=NULL); ASSERT(legal==true||legal==false); ASSERT(stop==true||stop==false); ASSERT(board_is_check(board)); ASSERT(ATTACK_IN_CHECK(attack)); // init LIST_CLEAR(list); me = board->turn; opp = COLOUR_OPP(me); opp_flag = COLOUR_FLAG(opp); king = KING_POS(board,me); for (inc_ptr = KingInc; (inc=*inc_ptr) != IncNone; inc_ptr++) { if (inc != -attack->di[0] && inc != -attack->di[1]) { // avoid escaping along a check line to = king + inc; piece = board->square[to]; if (piece == Empty || FLAG_IS(piece,opp_flag)) { if (!legal || !is_attacked(board,to,opp)) { if (stop) return true; LIST_ADD(list,MOVE_MAKE(king,to)); } } } } if (attack->dn >= 2) return false; // double check, we are done // single check ASSERT(attack->dn==1); // capture the checking piece if (add_pawn_captures(list,board,attack->ds[0],legal,stop) && stop) return true; if (add_piece_moves(list,board,attack->ds[0],legal,stop) && stop) return true; // interpose a piece inc = attack->di[0]; if (inc != IncNone) { // line for (to = king+inc; to != attack->ds[0]; to += inc) { ASSERT(SQUARE_IS_OK(to)); ASSERT(board->square[to]==Empty); if (add_pawn_moves(list,board,to,legal,stop) && stop) return true; if (add_piece_moves(list,board,to,legal,stop) && stop) return true; } } return false; }
bool move_is_pseudo(int move, board_t * board) { int me, opp; int from, to; int piece, capture; int inc, delta; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); ASSERT(!board_is_check(board)); // special cases if (MOVE_IS_SPECIAL(move)) { return move_is_pseudo_debug(move,board); } ASSERT((move&~07777)==0); // init me = board->turn; opp = COLOUR_OPP(board->turn); // from from = MOVE_FROM(move); ASSERT(SQUARE_IS_OK(from)); piece = board->square[from]; if (!COLOUR_IS(piece,me)) return false; ASSERT(piece_is_ok(piece)); // to to = MOVE_TO(move); ASSERT(SQUARE_IS_OK(to)); capture = board->square[to]; if (COLOUR_IS(capture,me)) return false; // move if (PIECE_IS_PAWN(piece)) { if (SQUARE_IS_PROMOTE(to)) return false; inc = PAWN_MOVE_INC(me); delta = to - from; ASSERT(delta_is_ok(delta)); if (capture == Empty) { // pawn push if (delta == inc) return true; if (delta == (2*inc) && PAWN_RANK(from,me) == Rank2 && board->square[from+inc] == Empty) { return true; } } else { // pawn capture if (delta == (inc-1) || delta == (inc+1)) return true; } } else { if (PIECE_ATTACK(board,piece,from,to)) return true; } return false; }
static int full_no_null(board_t * board, int alpha, int beta, int depth, int height, mv_t pv[], int node_type, int trans_move, int * best_move) { int value, best_value; int move; int new_depth; attack_t attack[1]; sort_t sort[1]; undo_t undo[1]; mv_t new_pv[HeightMax]; ASSERT(board!=NULL); ASSERT(range_is_ok(alpha,beta)); ASSERT(depth_is_ok(depth)); ASSERT(height_is_ok(height)); ASSERT(pv!=NULL); ASSERT(node_type==NodePV||node_type==NodeCut||node_type==NodeAll); ASSERT(trans_move==MoveNone||move_is_ok(trans_move)); ASSERT(best_move!=NULL); ASSERT(board_is_legal(board)); ASSERT(!board_is_check(board)); ASSERT(depth>=1); // init SearchStack[height].best_move = MoveNone; SearchStack[height].move = MoveNone; SearchStack[height].threat_move = MoveNone; SearchStack[height].reduced = false; SearchCurrent->node_nb++; SearchInfo->check_nb--; PV_CLEAR(pv); if (height > SearchCurrent->max_depth) SearchCurrent->max_depth = height; if (SearchInfo->check_nb <= 0) { SearchInfo->check_nb += SearchInfo->check_inc; search_check(); } attack_set(attack,board); ASSERT(!ATTACK_IN_CHECK(attack)); *best_move = MoveNone; best_value = ValueNone; // move loop sort_init(sort,board,attack,depth,height,trans_move); while ((move=sort_next(sort)) != MoveNone) { SearchStack[height].move = move; new_depth = full_new_depth(depth,move,board,false,false,false,height); move_do(board,move,undo); value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NODE_OPP(node_type)); move_undo(board,move,undo); if (value > best_value) { best_value = value; pv_cat(pv,new_pv,move); if (value > alpha) { alpha = value; *best_move = move; SearchStack[height].best_move = move; if (value >= beta) goto cut; } } } // ALL node if (best_value == ValueNone) { // no legal move => stalemate ASSERT(board_is_stalemate(board)); best_value = ValueDraw; } cut: ASSERT(value_is_ok(best_value)); return best_value; }
static int full_root(list_t * list, board_t * board, int alpha, int beta, int depth, int height, int search_type) { int old_alpha; int value, best_value[MultiPVMax]; int i, move, j; int new_depth; undo_t undo[1]; mv_t new_pv[HeightMax]; bool found; ASSERT(list_is_ok(list)); ASSERT(board_is_ok(board)); ASSERT(range_is_ok(alpha,beta)); ASSERT(depth_is_ok(depth)); ASSERT(height_is_ok(height)); 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); // init SearchStack[height].best_move = MoveNone; SearchStack[height].move = MoveNone; SearchStack[height].threat_move = MoveNone; SearchStack[height].reduced = false; SearchCurrent->node_nb++; SearchInfo->check_nb--; if (SearchCurrent->multipv == 0) for (i = 0; i < LIST_SIZE(list); i++) list->value[i] = ValueNone; old_alpha = alpha; best_value[SearchCurrent->multipv] = ValueNone; // move loop for (i = 0; i < LIST_SIZE(list); i++) { move = LIST_MOVE(list,i); if (SearchCurrent->multipv > 0){ found = false; for (j = 0; j < SearchCurrent->multipv; j++){ if (SearchBest[j].pv[0] == move){ found = true; break; } } if (found == true) continue; } SearchStack[height].move = move; SearchRoot->depth = depth; SearchRoot->move = move; SearchRoot->move_pos = i; SearchRoot->move_nb = LIST_SIZE(list); search_update_root(); new_depth = full_new_depth(depth,move,board,board_is_check(board)&&LIST_SIZE(list)==1,false,true, height); move_do(board,move,undo); if (search_type == SearchShort || best_value[SearchCurrent->multipv] == ValueNone) { // first move value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NodePV); if (value <= alpha){ // research old_alpha = -ValueInf; value = -full_search(board,-beta,ValueInf,new_depth,height+1,new_pv,NodePV); } else if (value >= beta){ // research value = -full_search(board,-ValueInf,-alpha,new_depth,height+1,new_pv,NodePV); } } else { // other moves value = -full_search(board,-alpha-1,-alpha,new_depth,height+1,new_pv,NodeCut); if (value > alpha) { // && value < beta SearchRoot->change = true; SearchRoot->easy = false; SearchRoot->flag = false; search_update_root(); value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NodePV); } } move_undo(board,move,undo); if (value <= alpha) { // upper bound list->value[i] = old_alpha; } else if (value >= beta) { // lower bound list->value[i] = beta; } else { // alpha < value < beta => exact value list->value[i] = value; } if (value > best_value[SearchCurrent->multipv] && (best_value[SearchCurrent->multipv] == ValueNone || value > alpha)) { SearchBest[SearchCurrent->multipv].move = move; SearchStack[height].best_move = move; SearchBest[SearchCurrent->multipv].value = value; if (value <= alpha) { // upper bound SearchBest[SearchCurrent->multipv].flags = SearchUpper; } else if (value >= beta) { // lower bound SearchBest[SearchCurrent->multipv].flags = SearchLower; } else { // alpha < value < beta => exact value SearchBest[SearchCurrent->multipv].flags = SearchExact; } SearchBest[SearchCurrent->multipv].depth = depth; pv_cat(SearchBest[SearchCurrent->multipv].pv,new_pv,move); search_update_best(); } if (value > best_value[SearchCurrent->multipv]) { best_value[SearchCurrent->multipv] = value; if (value > alpha) { if (search_type == SearchNormal) alpha = value; if (value >= beta) break; } } } ASSERT(value_is_ok(best_value)); list_sort(list); ASSERT(SearchBest->move==LIST_MOVE(list,0)); ASSERT(SearchBest->value==best_value); if (UseTrans && best_value[SearchCurrent->multipv] > old_alpha && best_value[SearchCurrent->multipv] < beta) { pv_fill(SearchBest[SearchCurrent->multipv].pv,board); } return best_value[SearchCurrent->multipv]; }
bool egbb_probe(const board_t * board, int * value) { int i; int sq; int piece; int colour, me; const sq_t * ptr; int counter; int white_king, black_king; int piece_list[4], square_list[4]; ASSERT(board!=NULL); ASSERT(value!=NULL); ASSERT(board_is_ok(board)); ASSERT(!board_is_check(board)); // init if (Egbb->init == 0) return false; if (Egbb->load == 0) return false; ASSERT(board->piece_nb<=Egbb->piece_nb); // init for (i = 0; i < 4; i++) { piece_list[i] = 0; square_list[i] = 0; } Egbb->read_nb++; // king white_king = SQUARE_TO_64(KING_POS(board,White)); black_king = SQUARE_TO_64(KING_POS(board,Black)); counter = 0; for (colour = 0; colour < ColourNb; colour++) { me = colour; // pieces for (ptr = &board->piece[me][1]; (sq=*ptr) != SquareNone; ptr++) { // HACK: no king piece = board->square[sq]; // index ASSERT(counter>=0&&counter<4); piece_list[counter] = TbPiece[PIECE_TO_12(piece)]; square_list[counter] = SQUARE_TO_64(sq); counter++; } // pawns for (ptr = &board->pawn[me][0]; (sq=*ptr) != SquareNone; ptr++) { piece = board->square[sq]; // index ASSERT(counter>=0&&counter<4); piece_list[counter] = TbPiece[PIECE_TO_12(piece)]; square_list[counter] = SQUARE_TO_64(sq); counter++; } } // probe *value = probe_egbb_ptr(board->turn,white_king,black_king,piece_list[0],square_list[0],piece_list[1],square_list[1],piece_list[2],square_list[2]); // score if (*value != ValueError) { Egbb->read_hit++; ASSERT(!value_is_mate(*value)); return true; } return false; }