X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=e7c4e6ca2c04d4d1b9008125dfacc68633b1e103;hp=5606847a8370be6ed954b770ad3516474a88370f;hb=17ef886fc32013fd5159484b8f9e547a5d183d59;hpb=02cd96e4c2e8a3da79512df4ea803687f9193071 diff --git a/src/search.cpp b/src/search.cpp index 5606847a..e7c4e6ca 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -125,9 +125,6 @@ namespace { const bool UseIIDAtPVNodes = true; const bool UseIIDAtNonPVNodes = false; - // Use null move driven internal iterative deepening? - bool UseNullDrivenIID = false; - // Internal iterative deepening margin. At Non-PV moves, when // UseIIDAtNonPVNodes is true, we do an internal iterative deepening search // when the static evaluation is at most IIDMargin below beta. @@ -196,7 +193,6 @@ namespace { // Iteration counters int Iteration; - bool LastIterations; BetaCounterType BetaCounter; // Scores and number of times the best move changed for each iteration: @@ -210,7 +206,7 @@ namespace { int SearchStartTime; int MaxNodes, MaxDepth; int MaxSearchTime, AbsoluteMaxSearchTime, ExtraSearchTime; - Move BestRootMove, PonderMove, EasyMove; + Move EasyMove; int RootMoveNumber; bool InfiniteSearch; bool PonderSearch; @@ -259,7 +255,7 @@ namespace { Depth depth, int ply, int threadID); void sp_search(SplitPoint *sp, int threadID); void sp_search_pv(SplitPoint *sp, int threadID); - void init_node(const Position &pos, SearchStack ss[], int ply, int threadID); + void init_node(SearchStack ss[], int ply, int threadID); void update_pv(SearchStack ss[], int ply); void sp_update_pv(SearchStack *pss, SearchStack ss[], int ply); bool connected_moves(const Position &pos, Move m1, Move m2); @@ -372,8 +368,6 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move, // Initialize global search variables Idle = false; SearchStartTime = get_system_time(); - BestRootMove = MOVE_NONE; - PonderMove = MOVE_NONE; EasyMove = MOVE_NONE; for (int i = 0; i < THREAD_MAX; i++) { @@ -427,7 +421,6 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move, if (UseLogFile) LogFile.open(get_option_value_string("Search Log Filename").c_str(), std::ios::out | std::ios::app); - UseNullDrivenIID = get_option_value_bool("Null driven IID"); UseQSearchFutilityPruning = get_option_value_bool("Futility Pruning (Quiescence Search)"); UseFutilityPruning = get_option_value_bool("Futility Pruning (Main Search)"); @@ -665,7 +658,6 @@ namespace { ValueByIteration[0] = Value(0); ValueByIteration[1] = rml.get_move_score(0); Iteration = 1; - LastIterations = false; EasyMove = rml.scan_for_easy_move(); @@ -720,9 +712,6 @@ namespace { ExtraSearchTime = BestMoveChangesByIteration[Iteration] * (MaxSearchTime / 2) + BestMoveChangesByIteration[Iteration-1] * (MaxSearchTime / 3); - // Try to guess if the current iteration is the last one or the last two - LastIterations = (current_search_time() > ((MaxSearchTime + ExtraSearchTime)*58) / 128); - // Stop search if most of MaxSearchTime is consumed at the end of the // iteration. We probably don't have enough time to search the first // move at the next iteration anyway. @@ -759,6 +748,11 @@ namespace { << " hashfull " << TT.full() << std::endl; // Print the best move and the ponder move to the standard output + if (ss[0].pv[0] == MOVE_NONE) + { + ss[0].pv[0] = rml.get_move(0); + ss[0].pv[1] = MOVE_NONE; + } std::cout << "bestmove " << ss[0].pv[0]; if (ss[0].pv[1] != MOVE_NONE) std::cout << " ponder " << ss[0].pv[1]; @@ -962,7 +956,7 @@ namespace { // Initialize, and make an early exit in case of an aborted search, // an instant draw, maximum ply reached, etc. - init_node(pos, ss, ply, threadID); + init_node(ss, ply, threadID); // After init_node() that calls poll() if (AbortSearch || thread_should_stop(threadID)) @@ -1158,7 +1152,7 @@ namespace { // Initialize, and make an early exit in case of an aborted search, // an instant draw, maximum ply reached, etc. - init_node(pos, ss, ply, threadID); + init_node(ss, ply, threadID); // After init_node() that calls poll() if (AbortSearch || thread_should_stop(threadID)) @@ -1191,7 +1185,6 @@ namespace { Value approximateEval = quick_evaluate(pos); bool mateThreat = false; - bool nullDrivenIID = false; bool isCheck = pos.is_check(); // Null move search @@ -1206,23 +1199,10 @@ namespace { StateInfo st; pos.do_null_move(st); - int R = (depth >= 4 * OnePly ? 4 : 3); // Null move dynamic reduction + int R = (depth >= 5 * OnePly ? 4 : 3); // Null move dynamic reduction Value nullValue = -search(pos, ss, -(beta-1), depth-R*OnePly, ply+1, false, threadID); - // Check for a null capture artifact, if the value without the null capture - // is above beta then mark the node as a suspicious failed low. We will verify - // later if we are really under threat. - if ( UseNullDrivenIID - && nullValue < beta - && depth > 6 * OnePly - &&!value_is_mate(nullValue) - && ttMove == MOVE_NONE - && ss[ply + 1].currentMove != MOVE_NONE - && pos.move_is_capture(ss[ply + 1].currentMove) - && pos.see(ss[ply + 1].currentMove) + nullValue >= beta) - nullDrivenIID = true; - pos.undo_null_move(); if (value_is_mate(nullValue)) @@ -1246,10 +1226,8 @@ namespace { // low score (which will cause the reduced move to fail high in the // parent node, which will trigger a re-search with full depth). if (nullValue == value_mated_in(ply + 2)) - { mateThreat = true; - nullDrivenIID = false; - } + ss[ply].threatMove = ss[ply + 1].currentMove; if ( depth < ThreatDepth && ss[ply - 1].reduction @@ -1267,8 +1245,8 @@ namespace { { Value v = qsearch(pos, ss, beta-1, beta, Depth(0), ply, threadID); if ( (v < beta - RazorMargin - RazorMargin / 4) - || (depth < 3*OnePly && v < beta - RazorMargin) - || (depth < 2*OnePly && v < beta - RazorMargin / 2)) + || (depth <= 2*OnePly && v < beta - RazorMargin) + || (depth <= OnePly && v < beta - RazorMargin / 2)) return v; } @@ -1279,22 +1257,6 @@ namespace { search(pos, ss, beta, Min(depth/2, depth-2*OnePly), ply, false, threadID); ttMove = ss[ply].pv[ply]; } - else if (nullDrivenIID) - { - // The null move failed low due to a suspicious capture. Perhaps we - // are facing a null capture artifact due to the side to move change - // and this position should fail high. So do a normal search with a - // reduced depth to get a good ttMove to use in the following full - // depth search. - Move tm = ss[ply].threatMove; - - assert(tm != MOVE_NONE); - assert(ttMove == MOVE_NONE); - - search(pos, ss, beta, depth/2, ply, false, threadID); - ttMove = ss[ply].pv[ply]; - ss[ply].threatMove = tm; - } // Initialize a MovePicker object for the current position, and prepare // to search all moves: @@ -1432,6 +1394,9 @@ namespace { } TT.store(pos, value_to_tt(bestValue, ply), depth, m, VALUE_TYPE_LOWER); } + + assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); + return bestValue; } @@ -1451,7 +1416,7 @@ namespace { // Initialize, and make an early exit in case of an aborted search, // an instant draw, maximum ply reached, etc. - init_node(pos, ss, ply, threadID); + init_node(ss, ply, threadID); // After init_node() that calls poll() if (AbortSearch || thread_should_stop(threadID)) @@ -1460,15 +1425,39 @@ namespace { if (pos.is_draw()) return VALUE_DRAW; - // Transposition table lookup - const TTEntry* tte = TT.retrieve(pos); - if (tte && ok_to_use_TT(tte, depth, beta, ply)) - return value_from_tt(tte->value(), ply); + // Transposition table lookup, only when not in PV + TTEntry* tte = NULL; + bool pvNode = (beta - alpha != 1); + if (!pvNode) + { + tte = TT.retrieve(pos); + if (tte && ok_to_use_TT(tte, depth, beta, ply)) + { + assert(tte->type() != VALUE_TYPE_EVAL); + + return value_from_tt(tte->value(), ply); + } + } // Evaluate the position statically EvalInfo ei; + Value staticValue; bool isCheck = pos.is_check(); - Value staticValue = (isCheck ? -VALUE_INFINITE : evaluate(pos, ei, threadID)); + ei.futilityMargin = Value(0); // Manually initialize futilityMargin + + if (isCheck) + staticValue = -VALUE_INFINITE; + + else if (tte && tte->type() == VALUE_TYPE_EVAL) + { + // Use the cached evaluation score if possible + assert(tte->value() == evaluate(pos, ei, threadID)); + assert(ei.futilityMargin == Value(0)); + + staticValue = tte->value(); + } + else + staticValue = evaluate(pos, ei, threadID); if (ply == PLY_MAX - 1) return evaluate(pos, ei, threadID); @@ -1478,7 +1467,13 @@ namespace { Value bestValue = staticValue; if (bestValue >= beta) + { + // Store the score to avoid a future costly evaluation() call + if (!isCheck && !tte && ei.futilityMargin == 0) + TT.store(pos, value_to_tt(bestValue, ply), Depth(-127*OnePly), MOVE_NONE, VALUE_TYPE_EVAL); + return bestValue; + } if (bestValue > alpha) alpha = bestValue; @@ -1486,8 +1481,7 @@ namespace { // Initialize a MovePicker object for the current position, and prepare // to search the moves. Because the depth is <= 0 here, only captures, // queen promotions and checks (only if depth == 0) will be generated. - bool pvNode = (beta - alpha != 1); - MovePicker mp = MovePicker(pos, pvNode, MOVE_NONE, EmptySearchStack, depth, isCheck ? NULL : &ei); + MovePicker mp = MovePicker(pos, pvNode, MOVE_NONE, EmptySearchStack, depth); Move move; int moveCount = 0; Bitboard dcCandidates = mp.discovered_check_candidates(); @@ -1564,7 +1558,14 @@ namespace { assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); // Update transposition table - TT.store(pos, value_to_tt(bestValue, ply), depth, MOVE_NONE, VALUE_TYPE_EXACT); + if (!pvNode) + { + Depth d = (depth == Depth(0) ? Depth(0) : Depth(-1)); + if (bestValue < beta) + TT.store(pos, value_to_tt(bestValue, ply), d, MOVE_NONE, VALUE_TYPE_UPPER); + else + TT.store(pos, value_to_tt(bestValue, ply), d, MOVE_NONE, VALUE_TYPE_LOWER); + } // Update killers only for good check moves Move m = ss[ply].currentMove; @@ -2016,7 +2017,7 @@ namespace { // NodesBetweenPolls nodes, init_node() also calls poll(), which polls // for user input and checks whether it is time to stop the search. - void init_node(const Position &pos, SearchStack ss[], int ply, int threadID) { + void init_node(SearchStack ss[], int ply, int threadID) { assert(ply >= 0 && ply < PLY_MAX); assert(threadID >= 0 && threadID < ActiveThreads); @@ -2441,7 +2442,7 @@ namespace { || ( !FailHigh && !fail_high_ply_1() && !Problem && t > 6*(MaxSearchTime + ExtraSearchTime)); - if ( (Iteration >= 2 && (!InfiniteSearch && overTime)) + if ( (Iteration >= 3 && (!InfiniteSearch && overTime)) || (ExactMaxTime && t >= ExactMaxTime) || (Iteration >= 3 && MaxNodes && nodes_searched() >= MaxNodes)) AbortSearch = true; @@ -2455,7 +2456,7 @@ namespace { void ponderhit() { int t = current_search_time(); PonderSearch = false; - if(Iteration >= 2 && + if(Iteration >= 3 && (!InfiniteSearch && (StopOnPonderhit || t > AbsoluteMaxSearchTime || (RootMoveNumber == 1 &&