X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=da306a1a6150a487b3f6a734375e12023fd55862;hp=86c572b42c28eb212dad34989034578cc1dac2cf;hb=44643c277007e3902586418541c0c22ff110fde1;hpb=9d1e2c0e763241e78cb7c957c532c484c848150c diff --git a/src/search.cpp b/src/search.cpp index 86c572b4..da306a1a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1,7 +1,7 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) - Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad + Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -276,7 +276,7 @@ void Search::think() { sync_cout << "bestmove " << UCI::move(RootMoves[0].pv[0], RootPos.is_chess960()); - if (RootMoves[0].pv.size() > 1) + if (RootMoves[0].pv.size() > 1 || RootMoves[0].extract_ponder_from_tt(RootPos)) std::cout << " ponder " << UCI::move(RootMoves[0].pv[1], RootPos.is_chess960()); std::cout << sync_endl; @@ -365,7 +365,8 @@ namespace { // When failing high/low give some update (without cluttering // the UI) before a re-search. - if ( (bestValue <= alpha || bestValue >= beta) + if ( multiPV == 1 + && (bestValue <= alpha || bestValue >= beta) && Time::now() - SearchTime > 3000) sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl; @@ -584,7 +585,7 @@ namespace { else if (ttHit) { // Never assume anything on values stored in TT - if ((ss->staticEval = eval = tte->eval_value()) == VALUE_NONE) + if ((ss->staticEval = eval = tte->eval()) == VALUE_NONE) eval = ss->staticEval = evaluate(pos); // Can ttValue be used as a better position evaluation? @@ -632,7 +633,7 @@ namespace { } // Step 7. Futility pruning: child node (skipped when in check) - if ( !PvNode + if ( !RootNode && depth < 7 * ONE_PLY && eval - futility_margin(depth) >= beta && eval < VALUE_KNOWN_WIN // Do not return unproven wins @@ -650,7 +651,7 @@ namespace { assert(eval - beta >= 0); // Null move dynamic reduction based on depth and value - Depth R = (3 + depth / 4 + std::min((eval - beta) / PawnValueMg, 3)) * ONE_PLY; + Depth R = ((823 + 67 * depth) / 256 + std::min((eval - beta) / PawnValueMg, 3)) * ONE_PLY; pos.do_null_move(st); (ss+1)->skipEarlyPruning = true; @@ -829,9 +830,8 @@ moves_loop: // When in check and at SpNode search starts from here // Update the current move (this must be done after singular extension search) newDepth = depth - ONE_PLY + extension; - // Step 13. Pruning at shallow depth (exclude PV nodes) - if ( !PvNode - && !captureOrPromotion + // Step 13. Pruning at shallow depth + if ( !captureOrPromotion && !inCheck && !dangerous && bestValue > VALUE_MATED_IN_MAX_PLY) @@ -906,7 +906,7 @@ 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)] < 0) + || History[pos.piece_on(to_sq(move))][to_sq(move)] < VALUE_ZERO) ss->reduction += ONE_PLY; if (move == countermoves[0] || move == countermoves[1]) @@ -916,7 +916,7 @@ moves_loop: // When in check and at SpNode search starts from here if ( ss->reduction && type_of(move) == NORMAL && type_of(pos.piece_on(to_sq(move))) != PAWN - && pos.see(make_move(to_sq(move), from_sq(move))) < 0) + && pos.see(make_move(to_sq(move), from_sq(move))) < VALUE_ZERO) ss->reduction = std::max(DEPTH_ZERO, ss->reduction - ONE_PLY); Depth d = std::max(newDepth - ss->reduction, ONE_PLY); @@ -1165,7 +1165,7 @@ moves_loop: // When in check and at SpNode search starts from here if (ttHit) { // Never assume anything on values stored in TT - if ((ss->staticEval = bestValue = tte->eval_value()) == VALUE_NONE) + if ((ss->staticEval = bestValue = tte->eval()) == VALUE_NONE) ss->staticEval = bestValue = evaluate(pos); // Can ttValue be used as a better position evaluation? @@ -1210,8 +1210,7 @@ moves_loop: // When in check and at SpNode search starts from here : pos.gives_check(move, ci); // Futility pruning - if ( !PvNode - && !InCheck + if ( !InCheck && !givesCheck && futilityBase > -VALUE_KNOWN_WIN && !pos.advanced_pawn_push(move)) @@ -1220,13 +1219,13 @@ moves_loop: // When in check and at SpNode search starts from here futilityValue = futilityBase + PieceValue[EG][pos.piece_on(to_sq(move))]; - if (futilityValue < beta) + if (futilityValue <= alpha) { bestValue = std::max(bestValue, futilityValue); continue; } - if (futilityBase < beta && pos.see(move) <= VALUE_ZERO) + if (futilityBase <= alpha && pos.see(move) <= VALUE_ZERO) { bestValue = std::max(bestValue, futilityBase); continue; @@ -1240,8 +1239,7 @@ moves_loop: // When in check and at SpNode search starts from here && !pos.can_castle(pos.side_to_move()); // Don't search moves with negative SEE values - if ( !PvNode - && (!InCheck || evasionPrunable) + if ( (!InCheck || evasionPrunable) && type_of(move) != PROMOTION && pos.see_sign(move) < VALUE_ZERO) continue; @@ -1493,6 +1491,30 @@ void RootMove::insert_pv_in_tt(Position& pos) { } +/// RootMove::extract_ponder_from_tt() is called in case we have no ponder move before +/// exiting the search, for instance in case we stop the search during a fail high at +/// root. We try hard to have a ponder move to return to the GUI, otherwise in case of +/// 'ponder on' we have nothing to think on. + +Move RootMove::extract_ponder_from_tt(Position& pos) +{ + StateInfo st; + bool found; + + assert(pv.size() == 1); + + pos.do_move(pv[0], st); + TTEntry* tte = TT.probe(pos.key(), found); + Move m = found ? tte->move() : MOVE_NONE; + if (!MoveList(pos).contains(m)) + m = MOVE_NONE; + + pos.undo_move(pv[0]); + pv.push_back(m); + return m; +} + + /// Thread::idle_loop() is where the thread is parked when it has no work to do void Thread::idle_loop() {