X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=67369ad5655d37656b869b23e1f0cbfa12781479;hp=21aa4f92069dbcbbf7997b73364b641444fc9ed2;hb=00a338088564356b46a8b45aa73a1640fadb2fc9;hpb=4634be8ba6176e71579fa01f5fd2c74e41eedad6 diff --git a/src/search.cpp b/src/search.cpp index 21aa4f92..67369ad5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -23,6 +23,7 @@ //// #include +#include #include #include #include @@ -128,18 +129,17 @@ namespace { }; - /// Constants and variables + /// Constants and variables initialized from UCI options // Minimum number of full depth (i.e. non-reduced) moves at PV and non-PV - // nodes: - int LMRPVMoves = 15; - int LMRNonPVMoves = 4; + // nodes + int LMRPVMoves, LMRNonPVMoves; - // Depth limit for use of dynamic threat detection: - Depth ThreatDepth = 5*OnePly; + // Depth limit for use of dynamic threat detection + Depth ThreatDepth; - // Depth limit for selective search: - Depth SelectiveDepth = 7*OnePly; + // Depth limit for selective search + const Depth SelectiveDepth = 7*OnePly; // Use internal iterative deepening? const bool UseIIDAtPVNodes = true; @@ -176,33 +176,34 @@ namespace { const bool PruneBlockingMoves = false; // Use futility pruning? - bool UseQSearchFutilityPruning = true; - bool UseFutilityPruning = true; + bool UseQSearchFutilityPruning, UseFutilityPruning; // Margins for futility pruning in the quiescence search, and at frontier // and near frontier nodes - Value FutilityMarginQS = Value(0x80); - Value FutilityMargins[6] = { Value(0x100), Value(0x200), Value(0x250), - Value(0x2A0), Value(0x340), Value(0x3A0) }; + const Value FutilityMarginQS = Value(0x80); - // Razoring - const bool RazorAtDepthOne = false; - Depth RazorDepth = 4*OnePly; - Value RazorMargin = Value(0x300); + // Remaining depth: 1 ply 1.5 ply 2 ply 2.5 ply 3 ply 3.5 ply + const Value FutilityMargins[12] = { Value(0x100), Value(0x120), Value(0x200), Value(0x220), Value(0x250), Value(0x270), + // 4 ply 4.5 ply 5 ply 5.5 ply 6 ply 6.5 ply + Value(0x2A0), Value(0x2C0), Value(0x340), Value(0x360), Value(0x3A0), Value(0x3C0) }; + // Razoring + const Depth RazorDepth = 4*OnePly; + + // Remaining depth: 1 ply 1.5 ply 2 ply 2.5 ply 3 ply 3.5 ply + const Value RazorMargins[6] = { Value(0x180), Value(0x300), Value(0x300), Value(0x3C0), Value(0x3C0), Value(0x3C0) }; + + // Remaining depth: 1 ply 1.5 ply 2 ply 2.5 ply 3 ply 3.5 ply + const Value RazorApprMargins[6] = { Value(0x520), Value(0x300), Value(0x300), Value(0x300), Value(0x300), Value(0x300) }; // Last seconds noise filtering (LSN) - bool UseLSNFiltering = false; + bool UseLSNFiltering; bool looseOnTime = false; - int LSNTime = 4 * 1000; // In milliseconds - Value LSNValue = Value(0x200); + int LSNTime; // In milliseconds + Value LSNValue; - // Extensions. Array index 0 is used at non-PV nodes, index 1 at PV nodes. - Depth CheckExtension[2] = {OnePly, OnePly}; - Depth SingleReplyExtension[2] = {OnePly / 2, OnePly / 2}; - Depth PawnPushTo7thExtension[2] = {OnePly / 2, OnePly / 2}; - Depth PassedPawnExtension[2] = {Depth(0), Depth(0)}; - Depth PawnEndgameExtension[2] = {OnePly, OnePly}; - Depth MateThreatExtension[2] = {Depth(0), Depth(0)}; + // Extensions. Array index 0 is used at non-PV nodes, index 1 at PV nodes. + Depth CheckExtension[2], SingleReplyExtension[2], PawnPushTo7thExtension[2]; + Depth PassedPawnExtension[2], PawnEndgameExtension[2], MateThreatExtension[2]; // Search depth at iteration 1 const Depth InitialDepth = OnePly /*+ OnePly/2*/; @@ -220,7 +221,7 @@ namespace { int BestMoveChangesByIteration[PLY_MAX_PLUS_2]; // MultiPV mode - int MultiPV = 1; + int MultiPV; // Time managment variables int SearchStartTime; @@ -240,15 +241,15 @@ namespace { int ExactMaxTime; // Show current line? - bool ShowCurrentLine = false; + bool ShowCurrentLine; // Log file - bool UseLogFile = false; + bool UseLogFile; std::ofstream LogFile; // MP related variables - Depth MinimumSplitDepth = 4*OnePly; - int MaxThreadsPerSplitPoint = 4; + Depth MinimumSplitDepth; + int MaxThreadsPerSplitPoint; Thread Threads[THREAD_MAX]; Lock MPLock; bool AllThreadsShouldExit = false; @@ -320,7 +321,7 @@ namespace { //// // The main transposition table -TranspositionTable TT = TranspositionTable(TTDefaultSize); +TranspositionTable TT; // Number of active threads: @@ -431,7 +432,6 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move, LMRPVMoves = get_option_value_int("Full Depth Moves (PV nodes)") + 1; LMRNonPVMoves = get_option_value_int("Full Depth Moves (non-PV nodes)") + 1; ThreatDepth = get_option_value_int("Threat Depth") * OnePly; - SelectiveDepth = get_option_value_int("Selective Plies") * OnePly; Chess960 = get_option_value_bool("UCI_Chess960"); ShowCurrentLine = get_option_value_bool("UCI_ShowCurrLine"); @@ -442,14 +442,6 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move, UseQSearchFutilityPruning = get_option_value_bool("Futility Pruning (Quiescence Search)"); UseFutilityPruning = get_option_value_bool("Futility Pruning (Main Search)"); - FutilityMarginQS = value_from_centipawns(get_option_value_int("Futility Margin (Quiescence Search)")); - int fmScale = get_option_value_int("Futility Margin Scale Factor (Main Search)"); - for (int i = 0; i < 6; i++) - FutilityMargins[i] = (FutilityMargins[i] * fmScale) / 100; - - RazorDepth = (get_option_value_int("Maximum Razoring Depth") + 1) * OnePly; - RazorMargin = value_from_centipawns(get_option_value_int("Razoring Margin")); - UseLSNFiltering = get_option_value_bool("LSN filtering"); LSNTime = get_option_value_int("LSN Time Margin (sec)") * 1000; LSNValue = value_from_centipawns(get_option_value_int("LSN Value Margin")); @@ -1196,7 +1188,7 @@ namespace { return bestValue; if (bestValue <= oldAlpha) - TT.store(pos, value_to_tt(bestValue, ply), depth, MOVE_NONE, VALUE_TYPE_UPPER); + TT.store(pos, value_to_tt(bestValue, ply), VALUE_TYPE_UPPER, depth, MOVE_NONE); else if (bestValue >= beta) { @@ -1207,10 +1199,10 @@ namespace { update_history(pos, m, depth, movesSearched, moveCount); update_killers(m, ss[ply]); } - TT.store(pos, value_to_tt(bestValue, ply), depth, m, VALUE_TYPE_LOWER); + TT.store(pos, value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, depth, m); } else - TT.store(pos, value_to_tt(bestValue, ply), depth, ss[ply].pv[ply], VALUE_TYPE_EXACT); + TT.store(pos, value_to_tt(bestValue, ply), VALUE_TYPE_EXACT, depth, ss[ply].pv[ply]); return bestValue; } @@ -1315,17 +1307,14 @@ namespace { } // Null move search not allowed, try razoring else if ( !value_is_mate(beta) - && approximateEval < beta - RazorMargin && depth < RazorDepth - && (RazorAtDepthOne || depth > OnePly) + && approximateEval < beta - RazorApprMargins[int(depth) - 2] && ttMove == MOVE_NONE && !pos.has_pawn_on_7th(pos.side_to_move())) { Value v = qsearch(pos, ss, beta-1, beta, Depth(0), ply, threadID); - if ( (v < beta - RazorMargin - RazorMargin / 4) - || (depth <= 2*OnePly && v < beta - RazorMargin) - || (depth <= OnePly && v < beta - RazorMargin / 2)) - return v; + if (v < beta - RazorMargins[int(depth) - 2]) + return v; } // Go with internal iterative deepening if we don't have a TT move @@ -1380,12 +1369,11 @@ namespace { continue; // Value based pruning - if (depth < 7 * OnePly && approximateEval < beta) + if (approximateEval < beta) { if (futilityValue == VALUE_NONE) futilityValue = evaluate(pos, ei, threadID) - + FutilityMargins[int(depth)/2 - 1] - + 32 * (depth & 1); + + FutilityMargins[int(depth) - 2]; if (futilityValue < beta) { @@ -1460,7 +1448,7 @@ namespace { return bestValue; if (bestValue < beta) - TT.store(pos, value_to_tt(bestValue, ply), depth, MOVE_NONE, VALUE_TYPE_UPPER); + TT.store(pos, value_to_tt(bestValue, ply), VALUE_TYPE_UPPER, depth, MOVE_NONE); else { BetaCounter.add(pos.side_to_move(), depth, threadID); @@ -1470,7 +1458,7 @@ namespace { update_history(pos, m, depth, movesSearched, moveCount); update_killers(m, ss[ply]); } - TT.store(pos, value_to_tt(bestValue, ply), depth, m, VALUE_TYPE_LOWER); + TT.store(pos, value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, depth, m); } assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); @@ -1516,6 +1504,7 @@ namespace { return value_from_tt(tte->value(), ply); } } + Move ttMove = (tte ? tte->move() : MOVE_NONE); // Evaluate the position statically EvalInfo ei; @@ -1548,7 +1537,7 @@ namespace { { // 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); + TT.store(pos, value_to_tt(bestValue, ply), VALUE_TYPE_EVAL, Depth(-127*OnePly), MOVE_NONE); return bestValue; } @@ -1559,7 +1548,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. - MovePicker mp = MovePicker(pos, pvNode, MOVE_NONE, EmptySearchStack, depth); + MovePicker mp = MovePicker(pos, pvNode, ttMove, EmptySearchStack, depth); Move move; int moveCount = 0; Bitboard dcCandidates = mp.discovered_check_candidates(); @@ -1636,22 +1625,20 @@ namespace { assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); // Update transposition table + Move m = ss[ply].pv[ply]; 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); + TT.store(pos, value_to_tt(bestValue, ply), VALUE_TYPE_UPPER, d, MOVE_NONE); else - TT.store(pos, value_to_tt(bestValue, ply), d, MOVE_NONE, VALUE_TYPE_LOWER); + TT.store(pos, value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, d, m); } // Update killers only for good check moves - Move m = ss[ply].currentMove; if (alpha >= beta && ok_to_history(pos, m)) // Only non capture moves are considered - { - // Wrong to update history when depth is <= 0 update_killers(m, ss[ply]); - } + return bestValue; } @@ -1934,7 +1921,7 @@ namespace { // Constructor RootMove::RootMove() { - nodes = cumulativeNodes = 0ULL; + nodes = cumulativeNodes = ourBeta = theirBeta = 0ULL; } // RootMove::operator<() is the comparison function used when @@ -1970,22 +1957,20 @@ namespace { for (int k = 0; !includeMove && searchMoves[k] != MOVE_NONE; k++) includeMove = (searchMoves[k] == mlist[i].move); - if (includeMove) - { - // Find a quick score for the move - StateInfo st; - SearchStack ss[PLY_MAX_PLUS_2]; - - moves[count].move = mlist[i].move; - moves[count].nodes = 0ULL; - pos.do_move(moves[count].move, st); - moves[count].score = -qsearch(pos, ss, -VALUE_INFINITE, VALUE_INFINITE, - Depth(0), 1, 0); - pos.undo_move(moves[count].move); - moves[count].pv[0] = moves[i].move; - moves[count].pv[1] = MOVE_NONE; // FIXME - count++; - } + if (!includeMove) + continue; + + // Find a quick score for the move + StateInfo st; + SearchStack ss[PLY_MAX_PLUS_2]; + + moves[count].move = mlist[i].move; + pos.do_move(moves[count].move, st); + moves[count].score = -qsearch(pos, ss, -VALUE_INFINITE, VALUE_INFINITE, Depth(0), 1, 0); + pos.undo_move(moves[count].move); + moves[count].pv[0] = moves[count].move; + moves[count].pv[1] = MOVE_NONE; // FIXME + count++; } sort(); }