X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fsearch.cpp;h=b653ef9e70f1b33dcde02a8310ea35e24ab6d288;hb=05a8c318b8cfc284906f6077fd934d35d891028c;hp=7c341f878f7200d321343567c249ec8fcd8964f0;hpb=5ca428402793b07b432b006056a1368f359c4ea0;p=stockfish diff --git a/src/search.cpp b/src/search.cpp index 7c341f87..b653ef9e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -32,6 +32,7 @@ #include "book.h" #include "evaluate.h" #include "history.h" +#include "maxgain.h" #include "misc.h" #include "movegen.h" #include "movepick.h" @@ -263,6 +264,8 @@ namespace { // History table History H; + // MaxGain table + MaxGain MG; /// Functions @@ -700,6 +703,7 @@ namespace { // Initialize TT.new_search(); H.clear(); + MG.clear(); init_ss_array(ss); IterationInfo[1] = IterationInfoType(rml.get_move_score(0), rml.get_move_score(0)); Iteration = 1; @@ -841,7 +845,7 @@ namespace { // If we are pondering or in infinite search, we shouldn't print the // best move before we are told to do so. - if (!AbortSearch && !ExactMaxTime && (PonderSearch || InfiniteSearch)) + if (!AbortSearch && (PonderSearch || InfiniteSearch)) wait_for_stop_or_ponderhit(); else // Print final search statistics @@ -891,6 +895,14 @@ namespace { Value oldAlpha = alpha; Value value = -VALUE_INFINITE; CheckInfo ci(pos); + bool isCheck = pos.is_check(); + + // Evaluate the position statically + EvalInfo ei; + if (!isCheck) + ss[0].eval = evaluate(pos, ei, 0); + else + ss[0].eval = VALUE_NONE; // Loop through all the moves in the root move list for (int i = 0; i < rml.move_count() && !AbortSearch; i++) @@ -1153,9 +1165,25 @@ namespace { tte = TT.retrieve(pos.get_key()); } + // Evaluate the position statically + isCheck = pos.is_check(); + EvalInfo ei; + if (!isCheck) + { + ss[ply].eval = evaluate(pos, ei, threadID); + + // Store gain statistics + Move m = ss[ply - 1].currentMove; + if ( m != MOVE_NULL + && pos.captured_piece() == NO_PIECE_TYPE + && !move_is_castle(m) + && !move_is_promotion(m)) + MG.store(pos.piece_on(move_to(m)), move_from(m), move_to(m), ss[ply - 1].eval, -ss[ply].eval); + + } + // Initialize a MovePicker object for the current position, and prepare // to search all moves - isCheck = pos.is_check(); mateThreat = pos.has_mate_threat(opposite_color(pos.side_to_move())); CheckInfo ci(pos); MovePicker mp = MovePicker(pos, ttMove, depth, H, &ss[ply]); @@ -1391,8 +1419,20 @@ namespace { ss[ply].eval = staticValue; futilityValue = staticValue + FutilityValueMargin; staticValue = refine_eval(tte, staticValue, ply); // Enhance accuracy with TT value if possible + + // Store gain statistics + Move m = ss[ply - 1].currentMove; + if ( m != MOVE_NULL + && pos.captured_piece() == NO_PIECE_TYPE + && !move_is_castle(m) + && !move_is_promotion(m)) + MG.store(pos.piece_on(move_to(m)), move_from(m), move_to(m), ss[ply - 1].eval, -ss[ply].eval); } + // Post futility pruning + if (staticValue - FutilityValueMargin >= beta) + return (staticValue - FutilityValueMargin); + // Null move search if ( allowNullmove && depth > OnePly @@ -1520,6 +1560,7 @@ namespace { if ( useFutilityPruning && !dangerous && !captureOrPromotion + && !move_is_castle(move) && move != ttMove) { // Move count based pruning @@ -1682,6 +1723,19 @@ namespace { else staticValue = evaluate(pos, ei, threadID); + if (!isCheck) + { + ss[ply].eval = staticValue; + // Store gain statistics + Move m = ss[ply - 1].currentMove; + if ( m != MOVE_NULL + && pos.captured_piece() == NO_PIECE_TYPE + && !move_is_castle(m) + && !move_is_promotion(m)) + MG.store(pos.piece_on(move_to(m)), move_from(m), move_to(m), ss[ply - 1].eval, -ss[ply].eval); + } + + // Initialize "stand pat score", and return it immediately if it is // at least beta. bestValue = staticValue; @@ -2046,37 +2100,40 @@ namespace { break; // New best move? - lock_grab(&(sp->lock)); - if (value > sp->bestValue && !thread_should_stop(threadID)) + if (value > sp->bestValue) // Less then 2% of cases { - sp->bestValue = value; - if (value > sp->alpha) + lock_grab(&(sp->lock)); + if (value > sp->bestValue && !thread_should_stop(threadID)) { - // Ask threads to stop before to modify sp->alpha - if (value >= sp->beta) + sp->bestValue = value; + if (value > sp->alpha) { - for (int i = 0; i < ActiveThreads; i++) - if (i != threadID && (i == sp->master || sp->slaves[i])) - Threads[i].stop = true; + // Ask threads to stop before to modify sp->alpha + if (value >= sp->beta) + { + for (int i = 0; i < ActiveThreads; i++) + if (i != threadID && (i == sp->master || sp->slaves[i])) + Threads[i].stop = true; - sp->finished = true; - } + sp->finished = true; + } - sp->alpha = value; + sp->alpha = value; - sp_update_pv(sp->parentSstack, ss, sp->ply); - if (value == value_mate_in(sp->ply + 1)) - ss[sp->ply].mateKiller = move; - } - // 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 ( sp->ply == 1 - && Iteration >= 2 - && -value <= IterationInfo[Iteration-1].value - ProblemMargin) - Problem = true; + sp_update_pv(sp->parentSstack, ss, sp->ply); + if (value == value_mate_in(sp->ply + 1)) + ss[sp->ply].mateKiller = move; + } + // 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 ( sp->ply == 1 + && Iteration >= 2 + && -value <= IterationInfo[Iteration-1].value - ProblemMargin) + Problem = true; + } + lock_release(&(sp->lock)); } - lock_release(&(sp->lock)); } lock_grab(&(sp->lock)); @@ -2458,9 +2515,8 @@ namespace { Square mfrom, mto, tfrom, tto; - // Prune if there isn't any threat move and - // is not a castling move (common case). - if (threat == MOVE_NONE && !move_is_castle(m)) + // Prune if there isn't any threat move + if (threat == MOVE_NONE) return true; mfrom = move_from(m); @@ -2468,15 +2524,11 @@ namespace { tfrom = move_from(threat); tto = move_to(threat); - // Case 1: Castling moves are never pruned - if (move_is_castle(m)) - return false; - - // Case 2: Don't prune moves which move the threatened piece + // Case 1: Don't prune moves which move the threatened piece if (mfrom == tto) return false; - // Case 3: If the threatened piece has value less than or equal to the + // Case 2: If the threatened piece has value less than or equal to the // value of the threatening piece, don't prune move which defend it. if ( pos.move_is_capture(threat) && ( pos.midgame_value_of_piece_on(tfrom) >= pos.midgame_value_of_piece_on(tto) @@ -2484,7 +2536,7 @@ namespace { && pos.move_attacks_square(m, tto)) return false; - // Case 4: If the moving piece in the threatened move is a slider, don't + // Case 3: If the moving piece in the threatened move is a slider, don't // prune safe moves which block its ray. if ( piece_is_slider(pos.piece_on(tfrom)) && bit_is_set(squares_between(tfrom, tto), mto)