X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=3ac52f8c0f9cbd0910b00ab1a05532c198c291b1;hp=4590bd4a1905c6f3e0baa5931f3284487565fe68;hb=a2410227cc8df5373d6970bfe63bbd3df5287c8c;hpb=df722521ba7027df394ed6370571cb5dc2ed6da1 diff --git a/src/search.cpp b/src/search.cpp index 4590bd4a..3ac52f8c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -66,14 +66,14 @@ namespace { enum NodeType { Root, PV, NonPV }; // Razoring and futility margin based on depth - inline Value razor_margin(Depth d) { return Value(512 + 32 * d); } - inline Value futility_margin(Depth d) { return Value(200 * d); } + Value razor_margin(Depth d) { return Value(512 + 32 * d); } + Value futility_margin(Depth d) { return Value(200 * d); } // Futility and reductions lookup tables, initialized at startup int FutilityMoveCounts[2][16]; // [improving][depth] Depth Reductions[2][2][64][64]; // [pv][improving][depth][moveNumber] - template inline Depth reduction(bool i, Depth d, int mn) { + template Depth reduction(bool i, Depth d, int mn) { return Reductions[PvNode][i][std::min(d, 63 * ONE_PLY)][std::min(mn, 63)]; } @@ -129,13 +129,11 @@ namespace { }; size_t PVIdx; - TimeManagement Time; EasyMoveManager EasyMove; double BestMoveChanges; Value DrawValue[COLOR_NB]; HistoryStats History; CounterMovesHistoryStats CounterMovesHistory; - GainsStats Gains; MovesStats Countermoves; template @@ -182,6 +180,17 @@ void Search::init() { } +/// Search::reset() clears all search memory, to obtain reproducible search results + +void Search::reset () { + + TT.clear(); + History.clear(); + CounterMovesHistory.clear(); + Countermoves.clear(); +} + + /// Search::perft() is our utility to verify move generation. All the leaf nodes /// up to the given depth are generated and counted and the sum returned. template @@ -218,11 +227,12 @@ template uint64_t Search::perft(Position& pos, Depth depth); void Search::think() { - Time.init(Limits, RootPos.side_to_move(), RootPos.game_ply(), now()); + Color us = RootPos.side_to_move(); + Time.init(Limits, us, RootPos.game_ply(), now()); int contempt = Options["Contempt"] * PawnValueEg / 100; // From centipawns - DrawValue[ RootPos.side_to_move()] = VALUE_DRAW - Value(contempt); - DrawValue[~RootPos.side_to_move()] = VALUE_DRAW + Value(contempt); + DrawValue[ us] = VALUE_DRAW - Value(contempt); + DrawValue[~us] = VALUE_DRAW + Value(contempt); TB::Hits = 0; TB::RootInTB = false; @@ -291,6 +301,11 @@ void Search::think() { Threads.timer->run = false; } + // When playing in 'nodes as time' mode, subtract the searched nodes from + // the available ones before to exit. + if (Limits.npmsec) + Time.availableNodes += Limits.inc[us] - RootPos.nodes_searched(); + // When we reach the maximum depth, we can arrive here without a raise of // Signals.stop. However, if we are pondering or in an infinite search, // the UCI protocol states that we shouldn't print the best move before the @@ -334,10 +349,6 @@ namespace { beta = VALUE_INFINITE; TT.new_search(); - History.clear(); - CounterMovesHistory.clear(); - Gains.clear(); - Countermoves.clear(); size_t multiPV = Options["MultiPV"]; Skill skill(Options["Skill Level"]); @@ -542,7 +553,7 @@ namespace { goto moves_loop; } - moveCount = quietCount = 0; + moveCount = quietCount = ss->moveCount = 0; bestValue = -VALUE_INFINITE; ss->ply = (ss-1)->ply + 1; @@ -594,7 +605,7 @@ namespace { ss->currentMove = ttMove; // Can be MOVE_NONE // If ttMove is quiet, update killers, history, counter move on TT hit - if (ttValue >= beta && ttMove && !pos.capture_or_promotion(ttMove) && !inCheck) + if (ttValue >= beta && ttMove && !pos.capture_or_promotion(ttMove)) update_stats(pos, ss, ttMove, depth, nullptr, 0); return ttValue; @@ -630,7 +641,7 @@ namespace { } } - // Step 5. Evaluate the position statically and update parent's gain statistics + // Step 5. Evaluate the position statically if (inCheck) { ss->staticEval = eval = VALUE_NONE; @@ -659,23 +670,11 @@ namespace { if (ss->skipEarlyPruning) goto moves_loop; - if ( !pos.captured_piece_type() - && ss->staticEval != VALUE_NONE - && (ss-1)->staticEval != VALUE_NONE - && (move = (ss-1)->currentMove) != MOVE_NULL - && move != MOVE_NONE - && type_of(move) == NORMAL) - { - Square to = to_sq(move); - Gains.update(pos.piece_on(to), to, -(ss-1)->staticEval - ss->staticEval); - } - // Step 6. Razoring (skipped when in check) if ( !PvNode && depth < 4 * ONE_PLY && eval + razor_margin(depth) <= alpha - && ttMove == MOVE_NONE - && !pos.pawn_on_7th(pos.side_to_move())) + && ttMove == MOVE_NONE) { if ( depth <= ONE_PLY && eval + razor_margin(3 * ONE_PLY) <= alpha) @@ -750,7 +749,7 @@ namespace { assert((ss-1)->currentMove != MOVE_NONE); assert((ss-1)->currentMove != MOVE_NULL); - MovePicker mp(pos, ttMove, History, CounterMovesHistory, pos.captured_piece_type()); + MovePicker mp(pos, ttMove, History, CounterMovesHistory, PieceValue[MG][pos.captured_piece_type()]); CheckInfo ci(pos); while ((move = mp.next_move()) != MOVE_NONE) @@ -827,6 +826,8 @@ moves_loop: // When in check and at SpNode search starts from here } else ++moveCount; + + ss->moveCount = moveCount; if (RootNode) { @@ -845,7 +846,7 @@ moves_loop: // When in check and at SpNode search starts from here captureOrPromotion = pos.capture_or_promotion(move); givesCheck = type_of(move) == NORMAL && !ci.dcCandidates - ? ci.checkSq[type_of(pos.piece_on(from_sq(move)))] & to_sq(move) + ? ci.checkSquares[type_of(pos.piece_on(from_sq(move)))] & to_sq(move) : pos.gives_check(move, ci); dangerous = givesCheck @@ -902,8 +903,7 @@ moves_loop: // When in check and at SpNode search starts from here // Futility pruning: parent node if (predictedDepth < 7 * ONE_PLY) { - futilityValue = ss->staticEval + futility_margin(predictedDepth) - + 128 + Gains[pos.moved_piece(move)][to_sq(move)]; + futilityValue = ss->staticEval + futility_margin(predictedDepth) + 256; if (futilityValue <= alpha) { @@ -936,12 +936,11 @@ moves_loop: // When in check and at SpNode search starts from here if (!RootNode && !SpNode && !pos.legal(move, ci.pinned)) { moveCount--; + ss->moveCount = moveCount; continue; } ss->currentMove = move; - if (!SpNode && !captureOrPromotion && quietCount < 64) - quietsSearched[quietCount++] = move; // Step 14. Make the move pos.do_move(move, st, givesCheck); @@ -957,13 +956,14 @@ moves_loop: // When in check and at SpNode search starts from here ss->reduction = reduction(improving, depth, moveCount); if ( (!PvNode && cutNode) - || History[pos.piece_on(to_sq(move))][to_sq(move)] < VALUE_ZERO - || ( History[pos.piece_on(to_sq(move))][to_sq(move)] - + CounterMovesHistory[pos.piece_on(prevMoveSq)][prevMoveSq] - [pos.piece_on(to_sq(move))][to_sq(move)] < VALUE_ZERO)) + || ( History[pos.piece_on(to_sq(move))][to_sq(move)] < VALUE_ZERO + && CounterMovesHistory[pos.piece_on(prevMoveSq)][prevMoveSq] + [pos.piece_on(to_sq(move))][to_sq(move)] <= VALUE_ZERO)) ss->reduction += ONE_PLY; - if (move == countermove) + if ( History[pos.piece_on(to_sq(move))][to_sq(move)] > VALUE_ZERO + && CounterMovesHistory[pos.piece_on(prevMoveSq)][prevMoveSq] + [pos.piece_on(to_sq(move))][to_sq(move)] > VALUE_ZERO) ss->reduction = std::max(DEPTH_ZERO, ss->reduction - ONE_PLY); // Decrease reduction for moves that escape a capture @@ -979,13 +979,6 @@ moves_loop: // When in check and at SpNode search starts from here value = -search(pos, ss+1, -(alpha+1), -alpha, d, true); - // Re-search at intermediate depth if reduction is very high - if (value > alpha && ss->reduction >= 4 * ONE_PLY) - { - Depth d2 = std::max(newDepth - 2 * ONE_PLY, ONE_PLY); - value = -search(pos, ss+1, -(alpha+1), -alpha, d2, true); - } - doFullDepthSearch = (value > alpha && ss->reduction != DEPTH_ZERO); ss->reduction = DEPTH_ZERO; } @@ -1096,6 +1089,9 @@ moves_loop: // When in check and at SpNode search starts from here } } + if (!SpNode && !captureOrPromotion && move != bestMove && quietCount < 64) + quietsSearched[quietCount++] = move; + // Step 19. Check for splitting the search if ( !SpNode && Threads.size() >= 2 @@ -1139,8 +1135,8 @@ moves_loop: // When in check and at SpNode search starts from here : inCheck ? mated_in(ss->ply) : DrawValue[pos.side_to_move()]; // Quiet best move: update killers, history and countermoves - else if (bestValue >= beta && !pos.capture_or_promotion(bestMove) && !inCheck) - update_stats(pos, ss, bestMove, depth, quietsSearched, quietCount - 1); + else if (bestMove && !pos.capture_or_promotion(bestMove)) + update_stats(pos, ss, bestMove, depth, quietsSearched, quietCount); tte->save(posKey, value_to_tt(bestValue, ss->ply), bestValue >= beta ? BOUND_LOWER : @@ -1268,7 +1264,7 @@ moves_loop: // When in check and at SpNode search starts from here assert(is_ok(move)); givesCheck = type_of(move) == NORMAL && !ci.dcCandidates - ? ci.checkSq[type_of(pos.piece_on(from_sq(move)))] & to_sq(move) + ? ci.checkSquares[type_of(pos.piece_on(from_sq(move)))] & to_sq(move) : pos.gives_check(move, ci); // Futility pruning @@ -1297,8 +1293,7 @@ moves_loop: // When in check and at SpNode search starts from here // Detect non-capture evasions that are candidates to be pruned evasionPrunable = InCheck && bestValue > VALUE_MATED_IN_MAX_PLY - && !pos.capture(move) - && !pos.can_castle(pos.side_to_move()); + && !pos.capture(move); // Don't search moves with negative SEE values if ( (!InCheck || evasionPrunable) @@ -1398,10 +1393,12 @@ moves_loop: // When in check and at SpNode search starts from here *pv = MOVE_NONE; } - // update_stats() updates killers, history and countermoves stats after a fail-high - // of a quiet move. - void update_stats(const Position& pos, Stack* ss, Move move, Depth depth, Move* quiets, int quietsCnt) { + // update_stats() updates killers, history, countermove history and + // countermoves stats for a quiet best move. + + void update_stats(const Position& pos, Stack* ss, Move move, + Depth depth, Move* quiets, int quietsCnt) { if (ss->killers[0] != move) { @@ -1431,8 +1428,8 @@ moves_loop: // When in check and at SpNode search starts from here cmh.update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus); } - // Extra penalty for TT move in previous ply when it gets refuted - if (is_ok((ss-2)->currentMove) && (ss-1)->currentMove == (ss-1)->ttMove) + // Extra penalty for PV move in previous ply when it gets refuted + if (is_ok((ss-2)->currentMove) && (ss-1)->moveCount==1 && !pos.captured_piece_type()) { Square prevPrevSq = to_sq((ss-2)->currentMove); HistoryStats& ttMoveCmh = CounterMovesHistory[pos.piece_on(prevPrevSq)][prevPrevSq];