public SearchResult GetBestMove(SearchArgs settings) { return(search.GetBestMove(Board, settings)); }
public void AnalyzePosition(Position position, int depth, string file) { Semaphore s = new Semaphore(1, 1); using (StreamWriter w = new StreamWriter(file, false)) { w.WriteLine("Last Move,Best Move,Move Score,Primary Variation,Depth,Evaluations,Seconds"); } // Create a list of positions so we can process in parallel List <Position> positions = new List <Position>(); positions.Add(position); foreach (Move move in position.GetValidMoves()) { Position copy = position.Clone(); copy.MakeMove(move); positions.Add(copy); } // Create a list of actions to run in parallel List <Action> actions = new List <Action>(); foreach (Position p in positions) { actions.Add(() => { Stopwatch timer = Stopwatch.StartNew(); Search search = new Search(); SearchArgs args = new SearchArgs(depth, -1, false); SearchResult best = search.GetBestMove(p, args); timer.Stop(); s.WaitOne(); using (StreamWriter w = new StreamWriter(file, true)) { string history = ""; if (!string.IsNullOrEmpty(p.MovesHistory)) { string move = p.MovesHistory; if (move.Contains(" ")) { move = move.Split(' ')[0]; } history = "After " + move; } else { history = "Starting Position"; } w.WriteLine(history + "," + best.BestMove.ToString() + "," + best.Score + "," + best.PrimaryVariation + "," + depth + "," + best.Evaluations + "," + (timer.ElapsedMilliseconds / 1000.0).ToString("0.000")); } s.Release(); }); } // Analyze all positions in parallel actions.ForEach(a => Task.Run(a)); }
public SearchResult GetBestMove(Position position, SearchArgs settings) { SearchResult result = new SearchResult(); initiatingPlayer = position.PlayerToMove; timer = Stopwatch.StartNew(); cutoff = false; evaluations = 0; hashLookups = 0; useCache = settings.EnableCaching; timeLimitMilliseconds = settings.MaxSeconds < 0 ? long.MaxValue : settings.MaxSeconds * 1000; List <Move> moves = null; List <int> depths = new List <int>(); // Instead of creating some complicated for loop, just store up the depths we intend to search ahead of time if (settings.MaxSeconds < 0) { if (settings.MaxDepth != 1) { // If we're searching deeper than 3 (6 half moves) then do a fast two level deep search to help with move ordering depths.Add(4); } else if (settings.MaxDepth > 1) { // If we're searching deeper than 1 (2 half moves) then do a super fast one level deep search to help with move ordering depths.Add(2); } depths.Add(settings.MaxDepth * 2); } else { // All the depths we intend to search, in order for (int depth = 2; depth <= settings.MaxDepth * 2; depth += 2) { depths.Add(depth); } } // Iterative deepening // Increment depth by 2 since we always want to consider pairs of move (our move and opponent's move) foreach (int depth in depths) { // Need to re-initialize hash table at each depth hashtable = new Dictionary <ulong, SearchResult>(); currentDepth = depth; SearchResult nextDepth = AlphaBetaSearch(position, int.MinValue, int.MaxValue, depth, 1, 1, ref moves); // Move ordering for next iteration if (initiatingPlayer == Player.Red) { moves.Sort((c, n) => c.Evaluation.CompareTo(n.Evaluation)); } else { moves.Sort((c, n) => n.Evaluation.CompareTo(c.Evaluation)); } if (!cutoff) { result = nextDepth; } } result.Evaluations = evaluations; result.HashLookups = hashLookups; return(result); }