diff --git a/src/search.cpp b/src/search.cpp index bc922119c..28367605e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1408,12 +1409,32 @@ moves_loop: // When in check, search starts here rm.effort += nodes - nodeCount; - rm.averageScore = - rm.averageScore != -VALUE_INFINITE ? (value + rm.averageScore) / 2 : value; + u64 N = nodes - nodeCount; + u64 E_prev = std::max(u64(1), rm.effort - N); - rm.meanSquaredScore = rm.meanSquaredScore != -VALUE_INFINITE * VALUE_INFINITE - ? (value * std::abs(value) + rm.meanSquaredScore) / 2 - : value * std::abs(value); + // Dynamic EMA parameters for root move + constexpr u64 Scale = 32; + constexpr u64 ChiNumerator = 3; + constexpr u64 ChiDenominator = 2; // Chi = 3/2 = 1.5 + constexpr u64 MinWeight = 12; // 37.5% minimum weight + constexpr u64 MaxWeight = 24; // 75% maximum weight + + u64 w = std::clamp((Scale * N * ChiDenominator) + / (N * ChiDenominator + ChiNumerator * E_prev), + MinWeight, MaxWeight); + u64 w_mss = std::min(w, u64(16)); + i64 v2 = i64(value) * std::abs(value); + + if (rm.averageScore == -VALUE_INFINITE) + rm.averageScore = value; + else + rm.averageScore = Value((value * w + rm.averageScore * (Scale - w)) / Scale); + + if (rm.meanSquaredScore == -VALUE_INFINITE * VALUE_INFINITE) + rm.meanSquaredScore = value * std::abs(value); + else + rm.meanSquaredScore = + Value((v2 * w_mss + int64_t(rm.meanSquaredScore) * (Scale - w_mss)) / Scale); // PV move or new best move? if (moveCount == 1 || value > alpha)