X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=3529627fd4d946949c9794b487f6c7eea44b25c8;hp=c3f96e13de0e1b69e1034507524eaec542b8991f;hb=d99a95df29574634146ec04a20726829681b2e23;hpb=b58ad355ca6b3d81795563da3b5172efaf6cc941 diff --git a/src/search.cpp b/src/search.cpp index c3f96e13..3529627f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -133,9 +133,6 @@ namespace { // when the static evaluation is at most IIDMargin below beta. const Value IIDMargin = Value(0x100); - // Use easy moves? - const bool UseEasyMove = true; - // Easy move margin. An easy move candidate must be at least this much // better than the second best move. const Value EasyMoveMargin = Value(0x200); @@ -165,13 +162,14 @@ namespace { bool UseQSearchFutilityPruning = true; bool UseFutilityPruning = true; - // Margins for futility pruning in the quiescence search, at frontier - // nodes, and at pre-frontier nodes - Value FutilityMargin0 = Value(0x80); - Value FutilityMargin1 = Value(0x100); - Value FutilityMargin2 = Value(0x300); + // 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) }; // Razoring + const bool RazorAtDepthOne = false; Depth RazorDepth = 4*OnePly; Value RazorMargin = Value(0x300); @@ -418,9 +416,10 @@ 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)"); - FutilityMargin0 = value_from_centipawns(get_option_value_int("Futility Margin 0")); - FutilityMargin1 = value_from_centipawns(get_option_value_int("Futility Margin 1")); - FutilityMargin2 = value_from_centipawns(get_option_value_int("Futility Margin 2")); + 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")); @@ -450,7 +449,6 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move, // Set thinking time: int myTime = time[side_to_move]; int myIncrement = increment[side_to_move]; - int oppTime = time[1 - side_to_move]; if (!movesToGo) // Sudden death time control { @@ -940,16 +938,17 @@ namespace { assert(ply >= 0 && ply < PLY_MAX); assert(threadID >= 0 && threadID < ActiveThreads); - // Initialize, and make an early exit in case of an aborted search, - // an instant draw, maximum ply reached, etc. - if (AbortSearch || thread_should_stop(threadID)) - return Value(0); - if (depth < OnePly) return qsearch(pos, ss, alpha, beta, Depth(0), ply, threadID); + // Initialize, and make an early exit in case of an aborted search, + // an instant draw, maximum ply reached, etc. init_node(pos, ss, ply, threadID); + // After init_node() that calls poll() + if (AbortSearch || thread_should_stop(threadID)) + return Value(0); + if (pos.is_draw()) return VALUE_DRAW; @@ -1037,7 +1036,7 @@ namespace { else value = alpha + 1; // Just to trigger next condition - if (value > alpha) // Go with full depth pv search + if (value > alpha) // Go with full depth non-pv search { ss[ply].reduction = Depth(0); value = -search(pos, ss, -alpha, newDepth, ply+1, true, threadID); @@ -1075,7 +1074,9 @@ namespace { // If we are at ply 1, and we are searching the first root move at // ply 0, set the 'Problem' variable if the score has dropped a lot // (from the computer's point of view) since the previous iteration: - if (Iteration >= 2 && -value <= ValueByIteration[Iteration-1] - ProblemMargin) + if ( ply == 1 + && Iteration >= 2 + && -value <= ValueByIteration[Iteration-1] - ProblemMargin) Problem = true; } @@ -1132,21 +1133,22 @@ namespace { assert(ply >= 0 && ply < PLY_MAX); assert(threadID >= 0 && threadID < ActiveThreads); - EvalInfo ei; + if (depth < OnePly) + return qsearch(pos, ss, beta-1, beta, Depth(0), ply, threadID); // Initialize, and make an early exit in case of an aborted search, // an instant draw, maximum ply reached, etc. + init_node(pos, ss, ply, threadID); + + // After init_node() that calls poll() if (AbortSearch || thread_should_stop(threadID)) return Value(0); - if (depth < OnePly) - return qsearch(pos, ss, beta-1, beta, Depth(0), ply, threadID); - - init_node(pos, ss, ply, threadID); - if (pos.is_draw()) return VALUE_DRAW; + EvalInfo ei; + if (ply >= PLY_MAX - 1) return evaluate(pos, ei, threadID); @@ -1189,8 +1191,8 @@ namespace { Value nullValue = -search(pos, ss, -(beta-1), depth-R*OnePly, ply+1, false, threadID); // Check for a null capture artifact, if the value without the null capture - // is above beta then there is a good possibility that this is a cut-node. - // We will do an IID later to find a ttMove. + // is above beta then mark the node as a suspicious failed low. We will verify + // later if we are really under threat. if ( UseNullDrivenIID && nullValue < beta && depth > 6 * OnePly @@ -1237,11 +1239,16 @@ namespace { } // Null move search not allowed, try razoring else if ( !value_is_mate(beta) - && ( (approximateEval < beta - RazorMargin && depth < RazorDepth) - ||(approximateEval < beta - PawnValueMidgame && depth <= OnePly))) + && approximateEval < beta - RazorMargin + && depth < RazorDepth + && (RazorAtDepthOne || depth >= 2*OnePly) + && 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) + if ( (v < beta - RazorMargin - RazorMargin / 4) + || (depth < 3*OnePly && v < beta - RazorMargin) + || (depth < 2*OnePly && v < beta - RazorMargin / 2)) return v; } @@ -1256,7 +1263,9 @@ namespace { { // The null move failed low due to a suspicious capture. Perhaps we // are facing a null capture artifact due to the side to move change - // and this is a cut-node. So it's a good time to search for a ttMove. + // and this position should fail high. So do a normal search with a + // reduced depth to get a good ttMove to use in the following full + // depth search. Move tm = ss[ply].threatMove; assert(tm != MOVE_NONE); @@ -1305,17 +1314,18 @@ namespace { && !moveIsCapture && !move_promotion(move)) { - // History pruning. See ok_to_prune() definition. + // History pruning. See ok_to_prune() definition if ( moveCount >= 2 + int(depth) && ok_to_prune(pos, move, ss[ply].threatMove, depth)) continue; - // Value based pruning. - if (depth < 3 * OnePly && approximateEval < beta) + // Value based pruning + if (depth < 7 * OnePly && approximateEval < beta) { if (futilityValue == VALUE_NONE) futilityValue = evaluate(pos, ei, threadID) - + (depth < 2 * OnePly ? FutilityMargin1 : FutilityMargin2); + + FutilityMargins[int(depth)/2 - 1] + + 32 * (depth & 1); if (futilityValue < beta) { @@ -1419,15 +1429,14 @@ namespace { assert(ply >= 0 && ply < PLY_MAX); assert(threadID >= 0 && threadID < ActiveThreads); - EvalInfo ei; - // Initialize, and make an early exit in case of an aborted search, // an instant draw, maximum ply reached, etc. + init_node(pos, ss, ply, threadID); + + // After init_node() that calls poll() if (AbortSearch || thread_should_stop(threadID)) return Value(0); - init_node(pos, ss, ply, threadID); - if (pos.is_draw()) return VALUE_DRAW; @@ -1437,6 +1446,7 @@ namespace { return value_from_tt(tte->value(), ply); // Evaluate the position statically + EvalInfo ei; bool isCheck = pos.is_check(); Value staticValue = (isCheck ? -VALUE_INFINITE : evaluate(pos, ei, threadID)); @@ -1486,7 +1496,7 @@ namespace { + Max(pos.midgame_value_of_piece_on(move_to(move)), pos.endgame_value_of_piece_on(move_to(move))) + (move_is_ep(move) ? PawnValueEndgame : Value(0)) - + FutilityMargin0 + + FutilityMarginQS + ei.futilityMargin; if (futilityValue < alpha) @@ -1774,8 +1784,10 @@ namespace { } // If we are at ply 1, and we are searching the first root move at // ply 0, set the 'Problem' variable if the score has dropped a lot - // (from the computer's point of view) since the previous iteration: - if (Iteration >= 2 && -value <= ValueByIteration[Iteration-1] - ProblemMargin) + // (from the computer's point of view) since the previous iteration. + if ( sp->ply == 1 + && Iteration >= 2 + && -value <= ValueByIteration[Iteration-1] - ProblemMargin) Problem = true; } lock_release(&(sp->lock)); @@ -1784,7 +1796,7 @@ namespace { lock_grab(&(sp->lock)); // If this is the master thread and we have been asked to stop because of - // a beta cutoff higher up in the tree, stop all slave threads: + // a beta cutoff higher up in the tree, stop all slave threads. if (sp->master == threadID && thread_should_stop(threadID)) for (int i = 0; i < ActiveThreads; i++) if (sp->slaves[i]) @@ -2183,15 +2195,18 @@ namespace { if (mateThreat) result += MateThreatExtension[pvNode]; - if (pos.move_is_pawn_push_to_7th(m)) + if (pos.type_of_piece_on(move_from(m)) == PAWN) { - result += PawnPushTo7thExtension[pvNode]; - *dangerous = true; - } - if (pos.move_is_passed_pawn_push(m)) - { - result += PassedPawnExtension[pvNode]; - *dangerous = true; + if (pos.move_is_pawn_push_to_7th(m)) + { + result += PawnPushTo7thExtension[pvNode]; + *dangerous = true; + } + if (pos.move_is_passed_pawn_push(m)) + { + result += PassedPawnExtension[pvNode]; + *dangerous = true; + } } if ( pos.move_is_capture(m) @@ -2280,7 +2295,8 @@ namespace { if ( !PruneBlockingMoves && threat != MOVE_NONE && piece_is_slider(pos.piece_on(tfrom)) - && bit_is_set(squares_between(tfrom, tto), mto) && pos.see(m) >= 0) + && bit_is_set(squares_between(tfrom, tto), mto) + && pos.see(m) >= 0) return false; return true;