X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=d59fc521eedcba2815ae3cdeaf92f4bdb6e80730;hp=505e9ec2a481f49efa53e3276c14e2c6b15b1572;hb=df201175c6a0704800b1578e338c6e2a202234fe;hpb=a5869d8d2532c6bb8dbcba7d74331c0ac0230482 diff --git a/src/search.cpp b/src/search.cpp index 505e9ec2..d59fc521 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -83,7 +83,7 @@ namespace { Value DrawValue[COLOR_NB]; HistoryStats History; GainsStats Gains; - CountermovesStats Countermoves; + MovesStats Countermoves, Followupmoves; template Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode); @@ -304,6 +304,7 @@ namespace { History.clear(); Gains.clear(); Countermoves.clear(); + Followupmoves.clear(); PVSize = Options["MultiPV"]; Skill skill(Options["Skill Level"]); @@ -428,32 +429,13 @@ namespace { if (depth > 4 && depth < 50 && PVSize == 1) TimeMgr.pv_instability(BestMoveChanges); - // Stop the search if most of the available time has been used. We - // probably don't have enough time to search the first move at the - // next iteration anyway. - if (IterationTime > (TimeMgr.available_time() * 62) / 100) + // Stop the search if only one legal move is available or most + // of the available time has been used. We probably don't have + // enough time to search the first move at the next iteration anyway. + if ( RootMoves.size() == 1 + || IterationTime > (TimeMgr.available_time() * 62) / 100) stop = true; - // Stop the search early if one move seems to be much better than others - if ( depth >= 12 - && BestMoveChanges <= DBL_EPSILON - && !stop - && PVSize == 1 - && bestValue > VALUE_MATED_IN_MAX_PLY - && ( RootMoves.size() == 1 - || Time::now() - SearchTime > (TimeMgr.available_time() * 20) / 100)) - { - Value rBeta = bestValue - 2 * PawnValueMg; - ss->excludedMove = RootMoves[0].pv[0]; - ss->skipNullMove = true; - Value v = search(pos, ss, rBeta - 1, rBeta, (depth - 3) * ONE_PLY, true); - ss->skipNullMove = false; - ss->excludedMove = MOVE_NONE; - - if (v < rBeta) - stop = true; - } - if (stop) { // If we are allowed to ponder do not stop the search now but @@ -518,7 +500,7 @@ namespace { moveCount = quietCount = 0; bestValue = -VALUE_INFINITE; - ss->currentMove = (ss+1)->excludedMove = bestMove = MOVE_NONE; + ss->currentMove = ss->ttMove = (ss+1)->excludedMove = bestMove = MOVE_NONE; ss->ply = (ss-1)->ply + 1; (ss+1)->skipNullMove = false; (ss+1)->reduction = DEPTH_ZERO; (ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE; @@ -551,7 +533,7 @@ namespace { excludedMove = ss->excludedMove; posKey = excludedMove ? pos.exclusion_key() : pos.key(); tte = TT.probe(posKey); - ttMove = RootNode ? RootMoves[PVIdx].pv[0] : tte ? tte->move() : MOVE_NONE; + ss->ttMove = ttMove = RootNode ? RootMoves[PVIdx].pv[0] : tte ? tte->move() : MOVE_NONE; ttValue = tte ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; // At PV nodes we check for exact scores, whilst at non-PV nodes we check for @@ -569,7 +551,7 @@ namespace { TT.refresh(tte); ss->currentMove = ttMove; // Can be MOVE_NONE - // If ttMove is quiet, update killers, history, and counter move on TT hit + // If ttMove is quiet, update killers, history, counter move and followup move on TT hit if (ttValue >= beta && ttMove && !pos.capture_or_promotion(ttMove) && !inCheck) update_stats(pos, ss, ttMove, depth, NULL, 0); @@ -731,7 +713,11 @@ moves_loop: // When in check and at SpNode search starts from here Move countermoves[] = { Countermoves[pos.piece_on(prevMoveSq)][prevMoveSq].first, Countermoves[pos.piece_on(prevMoveSq)][prevMoveSq].second }; - MovePicker mp(pos, ttMove, depth, History, countermoves, ss); + Square prevOwnMoveSq = to_sq((ss-2)->currentMove); + Move followupmoves[] = { Followupmoves[pos.piece_on(prevOwnMoveSq)][prevOwnMoveSq].first, + Followupmoves[pos.piece_on(prevOwnMoveSq)][prevOwnMoveSq].second }; + + MovePicker mp(pos, ttMove, depth, History, countermoves, followupmoves, ss); CheckInfo ci(pos); value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc improving = ss->staticEval >= (ss-2)->staticEval @@ -1048,7 +1034,7 @@ moves_loop: // When in check and at SpNode search starts from here PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER, depth, bestMove, ss->staticEval); - // Quiet best move: update killers, history and countermoves + // Quiet best move: update killers, history, countermoves and followupmoves if (bestValue >= beta && !pos.capture_or_promotion(bestMove) && !inCheck) update_stats(pos, ss, bestMove, depth, quietsSearched, quietCount - 1); @@ -1283,7 +1269,7 @@ moves_loop: // When in check and at SpNode search starts from here } - // update_stats() updates killers, history and countermoves stats after a fail-high + // update_stats() updates killers, history, countermoves and followupmoves stats after a fail-high // of a quiet move. void update_stats(Position& pos, Stack* ss, Move move, Depth depth, Move* quiets, int quietsCnt) { @@ -1309,6 +1295,12 @@ moves_loop: // When in check and at SpNode search starts from here Square prevMoveSq = to_sq((ss-1)->currentMove); Countermoves.update(pos.piece_on(prevMoveSq), prevMoveSq, move); } + + if (is_ok((ss-2)->currentMove) && (ss-1)->currentMove == (ss-1)->ttMove) + { + Square prevOwnMoveSq = to_sq((ss-2)->currentMove); + Followupmoves.update(pos.piece_on(prevOwnMoveSq), prevOwnMoveSq, move); + } } @@ -1631,8 +1623,9 @@ void check_time() { Time::point elapsed = Time::now() - SearchTime; bool stillAtFirstMove = Signals.firstRootMove && !Signals.failedLowAtRoot - && elapsed > (TimeMgr.available_time() * 62) / 100 - && elapsed > IterationTime * 1.4; + && ( elapsed > TimeMgr.available_time() + || ( elapsed > (TimeMgr.available_time() * 62) / 100 + && elapsed > IterationTime * 1.4)); bool noMoreTime = elapsed > TimeMgr.maximum_time() - 2 * TimerThread::Resolution || stillAtFirstMove;