diff --git a/Chase.Engine/Search.cs b/Chase.Engine/Search.cs index 1065d5e..2a1d254 100644 --- a/Chase.Engine/Search.cs +++ b/Chase.Engine/Search.cs @@ -1,5 +1,6 @@ using Chase.Engine.Interfaces; using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -10,7 +11,9 @@ namespace Chase.Engine { public class Search : ISearchAlgorithm { - private int evaluations; + private long evaluations; + + private long hashLookups; private Stopwatch timer; @@ -22,16 +25,21 @@ public class Search : ISearchAlgorithm private string levelOneNode; + private Dictionary hashtable; + public event EventHandler OnNewResult; public SearchResult GetBestMove(Position position, SearchArgs settings) { SearchResult result = new SearchResult(); + hashtable = new Dictionary(); + timer = Stopwatch.StartNew(); cutoff = false; evaluations = 0; - timeLimitMilliseconds = settings.MaxSeconds * 1000; + hashLookups = 0; + timeLimitMilliseconds = settings.MaxSeconds < 0 ? 10000000 : settings.MaxSeconds * 1000; // Iterative deepening // Increment depth by 2 since we always want to consider pairs of move (our move and opponent's move) @@ -40,7 +48,6 @@ public SearchResult GetBestMove(Position position, SearchArgs settings) currentDepth = depth; SearchResult nextDepth = AlphaBetaSearch(position, int.MinValue, int.MaxValue, depth, 1, 1); - nextDepth.Evaluations = evaluations; if (!cutoff) { @@ -48,6 +55,9 @@ public SearchResult GetBestMove(Position position, SearchArgs settings) } } + result.Evaluations = evaluations; + result.HashLookups = hashLookups; + return result; } @@ -173,6 +183,14 @@ private int EvaluateDevelopment(Position position) private SearchResult AlphaBetaSearch(Position position, int alpha, int beta, int depth, int reportdepth, int depthUp) { + // If we've already processed this position, use the saved evaluation + ulong hash = position.GetHash(); + if (hashtable.ContainsKey(hash)) + { + hashLookups++; + return hashtable[hash]; + } + // Evaluate the position int eval = EvaluatePosition(position); @@ -278,11 +296,17 @@ private SearchResult AlphaBetaSearch(Position position, int alpha, int beta, int CurrentMove = movenum++, TotalMoves = moves.Count, Depth = currentDepth, + HashLookups = hashLookups, CurrentVariation = (depthUp != 1 ? levelOneNode + " " : "") + move.ToString() + " " + child.PrimaryVariation }); } } + if (!hashtable.ContainsKey(hash)) + { + hashtable.Add(hash, best); + } + return best; } } diff --git a/Chase.Engine/SearchResult.cs b/Chase.Engine/SearchResult.cs index ff4cbb0..99a5775 100644 --- a/Chase.Engine/SearchResult.cs +++ b/Chase.Engine/SearchResult.cs @@ -12,6 +12,8 @@ public class SearchResult public long Evaluations { get; set; } + public long HashLookups { get; set; } + public string PrimaryVariation { get; set; } public Move BestMove { get; set; } diff --git a/Chase.Engine/SearchStatus.cs b/Chase.Engine/SearchStatus.cs index b96b63f..8e59713 100644 --- a/Chase.Engine/SearchStatus.cs +++ b/Chase.Engine/SearchStatus.cs @@ -12,6 +12,8 @@ public class SearchStatus public long SearchedNodes { get; set; } + public long HashLookups { get; set; } + public long ElapsedMilliseconds { get; set; } public int TotalMoves { get; set; } diff --git a/Chase.GUI/GameForm.cs b/Chase.GUI/GameForm.cs index ef0f893..ae2a128 100644 --- a/Chase.GUI/GameForm.cs +++ b/Chase.GUI/GameForm.cs @@ -81,6 +81,7 @@ private void Game_OnSearchProgress(SearchStatus status) " score: " + status.BestMoveSoFar.Score + " depth: " + status.Depth + " nps: " + status.NodesPerSecond.ToString("0") + + " hl: " + status.HashLookups + " pv: " + status.CurrentVariation; } else