static int full_quiescence(board_t * board, int alpha, int beta, int depth, int height, mv_t pv[]) { bool in_check; int old_alpha; int value, best_value; int best_move; int move; int opt_value; attack_t attack[1]; sort_t sort[1]; undo_t undo[1]; mv_t new_pv[HeightMax]; int cd; ASSERT(board!=NULL); ASSERT(range_is_ok(alpha,beta)); ASSERT(depth_is_ok(depth)); ASSERT(height_is_ok(height)); ASSERT(pv!=NULL); ASSERT(board_is_legal(board)); ASSERT(depth<=0); // 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(); } // draw? if (board_is_repetition(board) || recog_draw(board)) return ValueDraw; // mate-distance pruning if (UseDistancePruning) { // lower bound value = VALUE_MATE(height+2); // does not work if the current position is mate if (value > alpha && board_is_mate(board)) value = VALUE_MATE(height); if (value > alpha) { alpha = value; if (value >= beta) return value; } // upper bound value = -VALUE_MATE(height+1); if (value < beta) { beta = value; if (value <= alpha) return value; } } // more init attack_set(attack,board); in_check = ATTACK_IN_CHECK(attack); if (in_check) { ASSERT(depth<0); depth++; // in-check extension } // height limit if (height >= HeightMax-1) return eval(board, alpha, beta); // more init old_alpha = alpha; best_value = ValueNone; best_move = MoveNone; /* if (UseDelta) */ opt_value = +ValueInf; if (!in_check) { // lone-king stalemate? if (simple_stalemate(board)) return ValueDraw; // stand pat value = eval(board, alpha, beta); ASSERT(value>best_value); best_value = value; if (value > alpha) { alpha = value; if (value >= beta) goto cut; } if (UseDelta) { opt_value = value + DeltaMargin; ASSERT(opt_value<+ValueInf); } } // move loop /* cd = CheckDepth; if(cd < 0 && board->piece_size[board->turn] <= 5) cd++; */ sort_init_qs(sort,board,attack, depth>=CheckDepth /* depth>=cd */); while ((move=sort_next_qs(sort)) != MoveNone) { SearchStack[height].move = move; // delta pruning if (UseDelta && beta == old_alpha+1) { if (!in_check && !move_is_check(move,board) && !capture_is_dangerous(move,board)) { ASSERT(move_is_tactical(move,board)); // optimistic evaluation value = opt_value; int to = MOVE_TO(move); int capture = board->square[to]; if (capture != Empty) { value += VALUE_PIECE(capture); } else if (MOVE_IS_EN_PASSANT(move)) { value += ValuePawn; } if (MOVE_IS_PROMOTE(move)) value += ValueQueen - ValuePawn; // pruning if (value <= alpha) { if (value > best_value) { best_value = value; PV_CLEAR(pv); } continue; } } } move_do(board,move,undo); value = -full_quiescence(board,-beta,-alpha,depth-1,height+1,new_pv); 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 ASSERT(board_is_mate(board)); return VALUE_MATE(height); } cut: ASSERT(value_is_ok(best_value)); return best_value; }
static int full_quiescence(board_t * board, int alpha, int beta, int depth, int height, mv_t pv[], int ThreadId) { bool in_check; int old_alpha; int value, best_value; int best_move; int move; int opt_value; attack_t attack[1]; sort_t sort[1]; undo_t undo[1]; mv_t new_pv[HeightMax]; int probe_score, probe_depth; int trans_move, trans_depth, trans_flags, trans_value; entry_t * found_entry; ASSERT(board!=NULL); ASSERT(range_is_ok(alpha,beta)); ASSERT(depth_is_ok(depth)); ASSERT(height_is_ok(height)); ASSERT(pv!=NULL); ASSERT(board_is_legal(board)); ASSERT(depth<=0); // init SearchCurrent[ThreadId]->node_nb++; SearchInfo[ThreadId]->check_nb--; PV_CLEAR(pv); if (height > SearchCurrent[ThreadId]->max_depth) SearchCurrent[ThreadId]->max_depth = height; if (SearchInfo[ThreadId]->check_nb <= 0) { SearchInfo[ThreadId]->check_nb += SearchInfo[ThreadId]->check_inc; search_check(ThreadId); } // draw? if (board_is_repetition(board)) return ValueDraw; /* Interior node recognizer from scorpio by Daniel Shawul -> dont probe at the leaves as this will slow down search For 4/3 pieces probe there also. -> After captures and pawn moves assume exact score and cutoff tree, because we are making progress. Note this is not done only for speed. -> if we are far from root (depth / 2), assume exact score and cutoff tree */ /* if (egbb_is_loaded && board->piece_nb <= 4){ if (probe_bitbases(board, probe_score)){ probe_score = value_from_trans(probe_score,height); return probe_score; } }*/ if (recog_draw(board,ThreadId)) return ValueDraw; // mate-distance pruning if (UseDistancePruning) { // lower bound value = VALUE_MATE(height+2); // does not work if the current position is mate if (value > alpha && board_is_mate(board)) value = VALUE_MATE(height); if (value > alpha) { alpha = value; if (value >= beta) return value; } // upper bound value = -VALUE_MATE(height+1); if (value < beta) { beta = value; if (value <= alpha) return value; } } // transposition table: added by Jerry Donald, about +20 elo self-play // new in Toga II 4.0: accept hash hits in PV ~ +3 elo trans_move = MoveNone; if (UseTrans) { if (trans_retrieve(Trans,&found_entry,board->key,&trans_move,&trans_depth,&trans_flags,&trans_value)) { trans_value = value_from_trans(trans_value,height); if ((UseExact && trans_value != ValueNone && TRANS_IS_EXACT(trans_flags)) || (TRANS_IS_LOWER(trans_flags) && trans_value >= beta) || (TRANS_IS_UPPER(trans_flags) && trans_value <= alpha)) { return trans_value; } } } // more init attack_set(attack,board); in_check = ATTACK_IN_CHECK(attack); if (in_check) { ASSERT(depth<0); depth++; // in-check extension } // height limit if (height >= HeightMax-1) return eval(board, alpha, beta, ThreadId); // more init old_alpha = alpha; best_value = ValueNone; best_move = MoveNone; /* if (UseDelta) */ opt_value = +ValueInf; if (!in_check) { // lone-king stalemate? if (simple_stalemate(board)) return ValueDraw; // stand pat value = eval(board, alpha, beta, ThreadId); ASSERT(value>best_value); best_value = value; if (value > alpha) { alpha = value; if (value >= beta) goto cut; } if (UseDelta) { opt_value = value + DeltaMargin; ASSERT(opt_value<+ValueInf); } } // move loop /* cd = CheckDepth; if(cd < 0 && board->piece_size[board->turn] <= 5) cd++; */ sort_init_qs(sort,board,attack, depth>=SearchCurrent[ThreadId]->CheckDepth /* depth>=cd */); while ((move=sort_next_qs(sort)) != MoveNone) { // delta pruning if (UseDelta && beta == old_alpha+1) { // i.e. non-PV if (!in_check && !move_is_check(move,board) && !capture_is_dangerous(move,board)) { ASSERT(move_is_tactical(move,board)); // optimistic evaluation value = opt_value; int to = MOVE_TO(move); int capture = board->square[to]; if (capture != Empty) { value += VALUE_PIECE(capture); } else if (MOVE_IS_EN_PASSANT(move)) { value += ValuePawn; } if (MOVE_IS_PROMOTE(move)) value += ValueQueen - ValuePawn; // pruning if (value <= alpha) { if (value > best_value) { best_value = value; PV_CLEAR(pv); } continue; } } } move_do(board,move,undo); value = -full_quiescence(board,-beta,-alpha,depth-1,height+1,new_pv,ThreadId); 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; if (value >= beta) goto cut; } } } // ALL node if (best_value == ValueNone) { // no legal move ASSERT(board_is_mate(board)); return VALUE_MATE(height); } cut: // store result in hash table (JD) if (UseTrans) { trans_move = best_move; trans_depth = 0; trans_flags = TransUnknown; if (best_value > old_alpha) trans_flags |= TransLower; if (best_value < beta) trans_flags |= TransUpper; trans_value = value_to_trans(best_value,height); trans_store(Trans,board->key,trans_move,trans_depth,trans_flags,trans_value); } ASSERT(value_is_ok(best_value)); return best_value; }