diff --git a/Logic/Search/Searches.cs b/Logic/Search/Searches.cs index c59f8b4..177f27e 100644 --- a/Logic/Search/Searches.cs +++ b/Logic/Search/Searches.cs @@ -216,10 +216,11 @@ public static int Negamax(Position pos, SearchStackEntry* ss, int alph if (UseNMP && !isPV + && !doSkip && depth >= NMPMinDepth + && ss->Ply >= thisThread.NMPPly && eval >= beta && eval >= ss->StaticEval - && !doSkip && (ss - 1)->CurrentMove != Move.Null && pos.HasNonPawnMaterial(pos.ToMove)) { @@ -230,15 +231,24 @@ public static int Negamax(Position pos, SearchStackEntry* ss, int alph // Skip our turn, and see if the our opponent is still behind even with a free move. pos.MakeNullMove(); prefetch(TT.GetCluster(pos.State->Hash)); - score = -Negamax(pos, ss + 1, -beta, -beta + 1, depth - reduction, !cutNode); - pos.UnmakeNullMove(); if (score >= beta) { - // Null moves are not allowed to return mate or TT win scores, so ensure the score is below that. - return score < ScoreTTWin ? score : beta; + if (thisThread.NMPPly > 0 || depth <= 15) + { + return score > ScoreWin ? beta : score; + } + + thisThread.NMPPly = (3 * (depth - reduction) / 4) + ss->Ply; + int verification = Negamax(pos, ss, beta - 1, beta, depth - reduction, false); + thisThread.NMPPly = 0; + + if (verification >= beta) + { + return score; + } } } diff --git a/Logic/Threads/SearchThread.cs b/Logic/Threads/SearchThread.cs index eec2b10..c2a8b37 100644 --- a/Logic/Threads/SearchThread.cs +++ b/Logic/Threads/SearchThread.cs @@ -61,6 +61,8 @@ public unsafe class SearchThread : IDisposable /// public int CompletedDepth; + public int NMPPly; + /// /// When this number reaches , the main thread will check to see if the search /// needs to stop because of max time or max node constraints. diff --git a/Logic/Threads/SearchThreadPool.cs b/Logic/Threads/SearchThreadPool.cs index 9938529..3167c27 100644 --- a/Logic/Threads/SearchThreadPool.cs +++ b/Logic/Threads/SearchThreadPool.cs @@ -122,6 +122,7 @@ public void StartSearch(Position rootPosition, ref SearchInformation rootInfo, T td.CompletedDepth = 0; td.RootDepth = 0; td.SelDepth = 0; + td.NMPPly = 0; // Each thread gets its own copy of each of the root position's "RootMoves" since the thread will be sorting these // and doing that simultaneously would cause data races diff --git a/Logic/Util/Utilities.cs b/Logic/Util/Utilities.cs index 1a89b09..65ed51d 100644 --- a/Logic/Util/Utilities.cs +++ b/Logic/Util/Utilities.cs @@ -10,7 +10,7 @@ namespace Lizard.Logic.Util public static class Utilities { - public const string EngineBuildVersion = "11.1.3"; + public const string EngineBuildVersion = "11.1.4"; public const int NormalListCapacity = 128; public const int MoveListSize = 256;