X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=cd815c2af266e679294ff81ba0f5806f7b548d4a;hp=ccf3b56d65b34199f74f7a8f22348035bacf4e52;hb=5413fda7397f8ffe32e41b9c7f13297c39929f5c;hpb=aab5863dd42da0a8e493a2ffaca96319b3d19ebb diff --git a/src/search.cpp b/src/search.cpp index ccf3b56d..cd815c2a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -60,13 +60,13 @@ namespace { enum NodeType { Root, PV, NonPV, SplitPointRoot, SplitPointPV, SplitPointNonPV }; // Dynamic razoring margin based on depth - inline Value razor_margin(Depth d) { return Value(512 + 16 * int(d)); } + inline Value razor_margin(Depth d) { return Value(512 + 16 * d); } // Futility lookup tables (initialized at startup) and their access functions int FutilityMoveCounts[2][32]; // [improving][depth] inline Value futility_margin(Depth d) { - return Value(100 * int(d)); + return Value(100 * d); } // Reduction lookup tables (initialized at startup) and their access function @@ -129,8 +129,8 @@ void Search::init() { { double pvRed = 0.00 + log(double(hd)) * log(double(mc)) / 3.00; double nonPVRed = 0.33 + log(double(hd)) * log(double(mc)) / 2.25; - Reductions[1][1][hd][mc] = (int8_t) ( pvRed >= 1.0 ? floor( pvRed * int(ONE_PLY)) : 0); - Reductions[0][1][hd][mc] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(ONE_PLY)) : 0); + Reductions[1][1][hd][mc] = int8_t( pvRed >= 1.0 ? pvRed * int(ONE_PLY) : 0); + Reductions[0][1][hd][mc] = int8_t(nonPVRed >= 1.0 ? nonPVRed * int(ONE_PLY) : 0); Reductions[1][0][hd][mc] = Reductions[1][1][hd][mc]; Reductions[0][0][hd][mc] = Reductions[0][1][hd][mc]; @@ -185,7 +185,7 @@ void Search::think() { RootColor = RootPos.side_to_move(); TimeMgr.init(Limits, RootPos.game_ply(), RootColor); - int cf = Options["Contempt Factor"] * PawnValueMg / 100; // From centipawns + int cf = Options["Contempt Factor"] * PawnValueEg / 100; // From centipawns DrawValue[ RootColor] = VALUE_DRAW - Value(cf); DrawValue[~RootColor] = VALUE_DRAW + Value(cf); @@ -219,7 +219,7 @@ void Search::think() { << " time: " << Limits.time[RootColor] << " increment: " << Limits.inc[RootColor] << " moves to go: " << Limits.movestogo - << std::endl; + << "\n" << std::endl; } // Reset the threads, still sleeping: will wake up at split time @@ -327,7 +327,7 @@ namespace { // Reset aspiration window starting size if (depth >= 5) { - delta = Value(depth > 23 ? 16 : 12); + delta = Value(16); alpha = std::max(RootMoves[PVIdx].prevScore - delta,-VALUE_INFINITE); beta = std::min(RootMoves[PVIdx].prevScore + delta, VALUE_INFINITE); } @@ -534,7 +534,6 @@ namespace { : ttValue >= beta ? (tte->bound() & BOUND_LOWER) : (tte->bound() & BOUND_UPPER))) { - TT.refresh(tte); ss->currentMove = ttMove; // Can be MOVE_NONE // If ttMove is quiet, update killers, history, counter move and followup move on TT hit @@ -680,7 +679,7 @@ namespace { // Step 10. Internal iterative deepening (skipped when in check) if ( depth >= (PvNode ? 5 * ONE_PLY : 8 * ONE_PLY) && !ttMove - && (PvNode || ss->staticEval + Value(256) >= beta)) + && (PvNode || ss->staticEval + 256 >= beta)) { Depth d = depth - 2 * ONE_PLY - (PvNode ? DEPTH_ZERO : depth / 4); @@ -820,7 +819,7 @@ moves_loop: // When in check and at SpNode search starts from here if (predictedDepth < 7 * ONE_PLY) { futilityValue = ss->staticEval + futility_margin(predictedDepth) - + Value(128) + Gains[pos.moved_piece(move)][to_sq(move)]; + + 128 + Gains[pos.moved_piece(move)][to_sq(move)]; if (futilityValue <= alpha) { @@ -933,12 +932,11 @@ moves_loop: // When in check and at SpNode search starts from here alpha = splitPoint->alpha; } - // Finished searching the move. If Signals.stop is true, the search - // was aborted because the user interrupted the search or because we - // ran out of time. In this case, the return value of the search cannot - // be trusted, and we don't update the best move and/or PV. + // Finished searching the move. If a stop or a cutoff occurred, the return + // value of the search cannot be trusted, and we return immediately without + // updating best move, PV and TT. if (Signals.stop || thisThread->cutoff_occurred()) - return value; // To avoid returning VALUE_INFINITE + return VALUE_ZERO; if (RootNode) { @@ -991,10 +989,14 @@ moves_loop: // When in check and at SpNode search starts from here && Threads.available_slave(thisThread) && thisThread->splitPointsSize < MAX_SPLITPOINTS_PER_THREAD) { - assert(bestValue < beta); + assert(bestValue > -VALUE_INFINITE && bestValue < beta); thisThread->split(pos, ss, alpha, beta, &bestValue, &bestMove, depth, moveCount, &mp, NT, cutNode); + + if (Signals.stop || thisThread->cutoff_occurred()) + return VALUE_ZERO; + if (bestValue >= beta) break; } @@ -1003,21 +1005,22 @@ moves_loop: // When in check and at SpNode search starts from here if (SpNode) return bestValue; + // Following condition would detect a stop or a cutoff set only after move + // loop has been completed. But in this case bestValue is valid because we + // have fully searched our subtree, and we can anyhow save the result in TT. + /* + if (Signals.stop || thisThread->cutoff_occurred()) + return VALUE_DRAW; + */ + // Step 20. Check for mate and stalemate // All legal moves have been searched and if there are no legal moves, it - // must be mate or stalemate. Note that we can have a false positive in - // case of Signals.stop or thread.cutoff_occurred() are set, but this is - // harmless because return value is discarded anyhow in the parent nodes. - // If we are in a singular extension search then return a fail low score. - // A split node has at least one move - the one tried before to be split. + // must be mate or stalemate. If we are in a singular extension search then + // return a fail low score. if (!moveCount) return excludedMove ? alpha : inCheck ? mated_in(ss->ply) : DrawValue[pos.side_to_move()]; - // If we have pruned all the moves without searching return a fail-low score - if (bestValue == -VALUE_INFINITE) - bestValue = alpha; - TT.store(posKey, value_to_tt(bestValue, ss->ply), bestValue >= beta ? BOUND_LOWER : PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER, @@ -1125,7 +1128,7 @@ moves_loop: // When in check and at SpNode search starts from here if (PvNode && bestValue > alpha) alpha = bestValue; - futilityBase = bestValue + Value(128); + futilityBase = bestValue + 128; } // Initialize a MovePicker object for the current position, and prepare @@ -1343,7 +1346,7 @@ moves_loop: // When in check and at SpNode search starts from here string uci_pv(const Position& pos, int depth, Value alpha, Value beta) { - std::stringstream s; + std::stringstream ss; Time::point elapsed = Time::now() - SearchTime + 1; size_t uciPVSize = std::min((size_t)Options["MultiPV"], RootMoves.size()); int selDepth = 0; @@ -1362,23 +1365,23 @@ moves_loop: // When in check and at SpNode search starts from here int d = updated ? depth : depth - 1; Value v = updated ? RootMoves[i].score : RootMoves[i].prevScore; - if (s.rdbuf()->in_avail()) // Not at first line - s << "\n"; + if (ss.rdbuf()->in_avail()) // Not at first line + ss << "\n"; - s << "info depth " << d - << " seldepth " << selDepth - << " score " << (i == PVIdx ? score_to_uci(v, alpha, beta) : score_to_uci(v)) - << " nodes " << pos.nodes_searched() - << " nps " << pos.nodes_searched() * 1000 / elapsed - << " time " << elapsed - << " multipv " << i + 1 - << " pv"; + ss << "info depth " << d + << " seldepth " << selDepth + << " score " << (i == PVIdx ? score_to_uci(v, alpha, beta) : score_to_uci(v)) + << " nodes " << pos.nodes_searched() + << " nps " << pos.nodes_searched() * 1000 / elapsed + << " time " << elapsed + << " multipv " << i + 1 + << " pv"; for (size_t j = 0; RootMoves[i].pv[j] != MOVE_NONE; ++j) - s << " " << move_to_uci(RootMoves[i].pv[j], pos.is_chess960()); + ss << " " << move_to_uci(RootMoves[i].pv[j], pos.is_chess960()); } - return s.str(); + return ss.str(); } } // namespace