X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Fsearch.cpp;h=6173a9a4b410d98efb1c9ca3f7fc5646fa8db3b5;hb=5b2fc1e1c06d8348efb4bf45bac9c8f4916fd01c;hp=e44dd85481e5a83dab4849a5741087abd92eb160;hpb=d0daa16769256c304aaa83c3c56fa8926cf5216d;p=stockfish diff --git a/src/search.cpp b/src/search.cpp index e44dd854..6173a9a4 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; @@ -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]); @@ -1375,7 +1403,7 @@ namespace { // Calculate depth dependant futility pruning parameters const int FutilityMoveCountMargin = 3 + (1 << (3 * int(depth) / 8)); - const int FutilityValueMargin = 112 * bitScanReverse32(int(depth) * int(depth) / 2); + const int PostFutilityValueMargin = 112 * bitScanReverse32(int(depth) * int(depth) / 2); // Evaluate the position statically if (!isCheck) @@ -1389,10 +1417,22 @@ namespace { } ss[ply].eval = staticValue; - futilityValue = staticValue + FutilityValueMargin; + futilityValue = staticValue + PostFutilityValueMargin; //FIXME: Remove me, only for split 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 - PostFutilityValueMargin >= beta) + return (staticValue - PostFutilityValueMargin); + // 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 @@ -1529,7 +1570,20 @@ namespace { continue; // Value based pruning - futilityValueScaled = futilityValue - moveCount * IncrementalFutilityMargin; + Depth predictedDepth = newDepth; + + //FIXME HACK: awful code duplication + double red = 0.5 + ln(moveCount) * ln(depth / 2) / 3.0; + if (red >= 1.0) + predictedDepth -= int(floor(red * int(OnePly))); + + int preFutilityValueMargin = 0; + if (predictedDepth >= OnePly) + preFutilityValueMargin = 112 * bitScanReverse32(int(predictedDepth) * int(predictedDepth) / 2); + + preFutilityValueMargin += MG.retrieve(pos.piece_on(move_from(move)), move_from(move), move_to(move)) + 45; + + futilityValueScaled = ss[ply].eval + preFutilityValueMargin - moveCount * IncrementalFutilityMargin; if (futilityValueScaled < beta) { @@ -1590,7 +1644,7 @@ namespace { && idle_thread_exists(threadID) && !AbortSearch && !thread_should_stop(threadID) - && split(pos, ss, ply, &beta, &beta, &bestValue, futilityValue, + && split(pos, ss, ply, &beta, &beta, &bestValue, futilityValue, //FIXME: SMP & futilityValue depth, &moveCount, &mp, threadID, false)) break; } @@ -1682,6 +1736,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; @@ -2461,9 +2528,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); @@ -2471,15 +2537,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) @@ -2487,7 +2549,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)