private static void CompareBestMove(string filePath, int timeBudgetMs) { var file = File.OpenText(filePath); double freq = Stopwatch.Frequency; long totalTime = 0; long totalNodes = 0; int count = 0; int foundBest = 0; List <Move> bestMoves = new List <Move>(); while (!file.EndOfStream) { ParseEpd(file.ReadLine(), out Board board, bestMoves); Transpositions.Clear(); IterativeSearch search = new IterativeSearch(board); Move pvMove = default; long t0 = Stopwatch.GetTimestamp(); long tStop = t0 + (timeBudgetMs * Stopwatch.Frequency) / 1000; //search until running out of time while (true) { search.SearchDeeper(() => Stopwatch.GetTimestamp() > tStop); if (search.Aborted) { break; } pvMove = search.PrincipalVariation[0]; } long t1 = Stopwatch.GetTimestamp(); long dt = t1 - t0; totalTime += dt; totalNodes += search.NodesVisited; count++; string pvString = string.Join(' ', search.PrincipalVariation); bool foundBestMove = bestMoves.Contains(pvMove); if (foundBestMove) { foundBest++; } Console.WriteLine($"{count,4}. {(foundBestMove ? "[X]" : "[ ]")} {pvString} = {search.Score:+0.00;-0.00}, {search.NodesVisited / 1000}K nodes, { 1000 * dt / freq}ms"); Console.WriteLine($"{totalNodes,14} nodes, { (int)(totalTime / freq)} seconds, {foundBest} solved."); } Console.WriteLine(); Console.WriteLine($"Searched {count} positions for {timeBudgetMs}ms each. {totalNodes/1000}K nodes visited. Took {totalTime/freq:0.###} seconds!"); Console.WriteLine($"Best move found in {foundBest} / {count} positions!"); }
private void Search() { while (CanSearchDeeper()) { _time.StartInterval(); _search.SearchDeeper(_time.CheckTimeBudget); //aborted? if (_search.Aborted) { break; } //collect PV Collect(); } //Done searching! Uci.BestMove(_best); _search = null; }
private static void ListMoves(Board board, int depth) { IterativeSearch search = new IterativeSearch(depth, board); Move[] line = search.PrincipalVariation; int i = 1; foreach (var move in new LegalMoves(board)) { if (line != null && line.Length > 0 && line[0] == move) { string pvString = string.Join(' ', line); Console.WriteLine($"{i++,4}. {pvString} = {search.Score:+0.00;-0.00}"); } else { Console.WriteLine($"{i++,4}. {move}"); } } }
//***************** //*** INTERNALS *** //***************** private void StartSearch(int maxDepth, long maxNodes) { //do the first iteration. it's cheap, no time check, no thread Uci.Log($"Search scheduled to take {_time.TimePerMoveWithMargin}ms!"); //add all history positions with a score of 0 (Draw through 3-fold repetition) and freeze them by setting a depth that is never going to be overwritten foreach (var position in _history) { Transpositions.Store(position.ZobristHash, Transpositions.HISTORY, 0, SearchWindow.Infinite, 0, default); } _search = new IterativeSearch(_board, maxNodes); _time.StartInterval(); _search.SearchDeeper(); Collect(); //start the search thread _maxSearchDepth = maxDepth; _searching = new Thread(Search) { Priority = ThreadPriority.Highest }; _searching.Start(); }
static void Main() { CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; Board board = new Board(Board.STARTING_POS_FEN); Move move = default; while (true) { try { Console.WriteLine(); Print(board, move); move = default; if (board.IsChecked(Color.Black)) { Console.WriteLine(" <!> Black is in check"); } if (board.IsChecked(Color.White)) { Console.WriteLine(" <!> White is in check"); } } catch (Exception error) { Console.WriteLine("ERROR: " + error.Message); } Console.WriteLine(); Console.Write($"{board.SideToMove} >> "); string input = Console.ReadLine(); string[] tokens = input.Split(); string command = tokens[0]; long t0 = Stopwatch.GetTimestamp(); try { if (command == "reset") { board = new Board(Board.STARTING_POS_FEN); } if (command == "kiwi") { //Kiwipete position board = new Board("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -"); } else if (command.Count(c => c == '/') == 7) //Fen-string detection { board.SetupPosition(input); } else if (command == "perft") { int depth = int.Parse(tokens[1]); if (tokens.Length > 2) { ComparePerft(depth, tokens[2]); } else { RunPerft(board, depth); } } else if (command == "divide") { int depth = int.Parse(tokens[1]); RunDivide(board, depth); } else if (command == "!") { int depth = tokens.Length > 1 ? int.Parse(tokens[1]) : 4; IterativeSearch search = new IterativeSearch(depth, board); move = search.PrincipalVariation[0]; Console.WriteLine($"{board.SideToMove} >> {move}"); board.Play(move); } else if (command == "?" && tokens.Length == 3) { int timeBudgetMs = int.Parse(tokens[2]); CompareBestMove(tokens[1], timeBudgetMs); } else if (command == "?") { int depth = tokens.Length > 1 ? int.Parse(tokens[1]) : 0; ListMoves(board, depth); } else if (command == "m") { PrintMobility(board); } else { ApplyMoves(board, tokens); } long t1 = Stopwatch.GetTimestamp(); double dt = (t1 - t0) / (double)Stopwatch.Frequency; if (dt > 0.01) { Console.WriteLine($" Operation took {dt:0.####}s"); } } catch (Exception error) { Console.WriteLine("ERROR: " + error.Message); } } }