public void Run(object arguments) { string[] args = (string[])arguments; Plug.Write(Utils.engine_info()); Plug.Write(Constants.endl); CheckInfoBroker.init(); EvalInfoBroker.init(); SwapListBroker.init(); MovesSearchedBroker.init(); PositionBroker.init(); StateInfoArrayBroker.init(); MListBroker.init(); LoopStackBroker.init(); MovePickerBroker.init(); StateInfoBroker.init(); Utils.init(); #if WINDOWS_RT #else Book.init(); #endif Position.init(); KPKPosition.init(); Endgame.init(); Search.init(); Evaluate.init(); Threads.init(); // .Net warmup sequence Plug.IsWarmup = true; Position pos = new Position(Uci.StartFEN, false, Threads.main_thread()); Stack <string> stack = Utils.CreateStack("go depth 7"); Uci.go(pos, stack); Threads.wait_for_search_finished(); Plug.IsWarmup = false; StringBuilder sb = new StringBuilder(); for (int i = 1; i < args.Length; i++) { sb.Append(args[i]).Append(" "); } Uci.uci_loop(sb.ToString()); Threads.exit(); }
// set_position() is called when engine receives the "position" UCI // command. The function sets up the position described in the given // fen string ("fen") or the starting position ("startpos") and then // makes the moves given in the following move list ("moves"). internal static void set_position(Position pos, Stack <string> stack) { Move m; string token, fen = string.Empty; token = stack.Pop(); if (token == "startpos") { fen = StartFEN; if (stack.Count > 0) { token = stack.Pop(); } // Consume "moves" token if any } else if (token == "fen") { while ((stack.Count > 0) && (token = stack.Pop()) != "moves") { fen += token + " "; } } else { return; } pos.from_fen(fen, bool.Parse(OptionMap.Instance["UCI_Chess960"].v), Threads.main_thread()); // Parse move list (if any) while ((stack.Count > 0) && (m = Utils.move_from_uci(pos, token = stack.Pop())) != MoveC.MOVE_NONE) { pos.do_move(m, StateRingBuf[SetupStatePos]); // Increment pointer to StateRingBuf circular buffer SetupStatePos = (SetupStatePos + 1) % 102; } }
internal static int SetupStatePos = 0; // *SetupState = StateRingBuf; /// Wait for a command from the user, parse this text string as an UCI command, /// and call the appropriate functions. Also intercepts EOF from stdin to ensure /// that we exit gracefully if the GUI dies unexpectedly. In addition to the UCI /// commands, the function also supports a few debug commands. internal static void uci_loop(string args) { for (int i = 0; i < 102; i++) { StateRingBuf[i] = new StateInfo(); } Position pos = new Position(StartFEN, false, Threads.main_thread()); // The root position string cmd, token = string.Empty; while (token != "quit") { if (args.Length > 0) { cmd = args; } else if (String.IsNullOrEmpty(cmd = Plug.ReadLine())) // Block here waiting for input { cmd = "quit"; } Stack <string> stack = Utils.CreateStack(cmd); token = stack.Pop(); if (token == "quit" || token == "stop") { Search.SignalsStop = true; Threads.wait_for_search_finished(); // Cannot quit while threads are running } else if (token == "ponderhit") { // The opponent has played the expected move. GUI sends "ponderhit" if // we were told to ponder on the same move the opponent has played. We // should continue searching but switching from pondering to normal search. Search.Limits.ponder = false; if (Search.SignalsStopOnPonderhit) { Search.SignalsStop = true; Threads.main_thread().wake_up(); // Could be sleeping } } else if (token == "go") { go(pos, stack); } else if (token == "ucinewgame") { /* Avoid returning "Unknown command" */ } else if (token == "isready") { Plug.Write("readyok"); Plug.Write(Constants.endl); } else if (token == "position") { set_position(pos, stack); } else if (token == "setoption") { set_option(stack); } else if (token == "d") { pos.print(0); } else if (token == "flip") { pos.flip(); } else if (token == "eval") { Plug.Write(Evaluate.trace(pos)); Plug.Write(Constants.endl); } else if (token == "bench") { Benchmark.benchmark(pos, stack); } else if (token == "key") { Plug.Write("key: "); Plug.Write(String.Format("{0:X}", pos.key())); Plug.Write("\nmaterial key: "); Plug.Write(pos.material_key().ToString()); Plug.Write("\npawn key: "); Plug.Write(pos.pawn_key().ToString()); Plug.Write(Constants.endl); } else if (token == "uci") { Plug.Write("id name "); Plug.Write(Utils.engine_info(true)); Plug.Write("\n"); Plug.Write(OptionMap.Instance.ToString()); Plug.Write("\nuciok"); Plug.Write(Constants.endl); } else if (token == "perft") { token = stack.Pop(); // Read depth Stack <string> ss = Utils.CreateStack( string.Format("{0} {1} {2} current perft", OptionMap.Instance["Hash"].v, OptionMap.Instance["Threads"].v, token) ); Benchmark.benchmark(pos, ss); } else { Plug.Write("Unknown command: "); Plug.Write(cmd); Plug.Write(Constants.endl); } if (args.Length > 0) // Command line arguments have one-shot behaviour { Threads.wait_for_search_finished(); break; } } }
/// benchmark() runs a simple benchmark by letting Stockfish analyze a set /// of positions for a given limit each. There are five parameters; the /// transposition table size, the number of search threads that should /// be used, the limit value spent for each position (optional, default is /// depth 12), an optional file name where to look for positions in fen /// format (defaults are the positions defined above) and the type of the /// limit value: depth (default), time in secs or number of nodes. internal static void benchmark(Position current, Stack <string> stack) { List <string> fens = new List <string>(); LimitsType limits = new LimitsType(); Int64 nodes = 0; Int64 nodesAll = 0; long e = 0; long eAll = 0; // Assign default values to missing arguments string ttSize = (stack.Count > 0) ? (stack.Pop()) : "128"; string threads = (stack.Count > 0) ? (stack.Pop()) : "1"; string limit = (stack.Count > 0) ? (stack.Pop()) : "12"; string fenFile = (stack.Count > 0) ? (stack.Pop()) : "default"; string limitType = (stack.Count > 0) ? (stack.Pop()) : "depth"; OptionMap.Instance["Hash"].v = ttSize; OptionMap.Instance["Threads"].v = threads; TT.clear(); if (limitType == "time") { limits.movetime = 1000 * int.Parse(limit); // maxTime is in ms } else if (limitType == "nodes") { limits.nodes = int.Parse(limit); } else { limits.depth = int.Parse(limit); } if (fenFile == "default") { fens.AddRange(Defaults); } else if (fenFile == "current") { fens.Add(current.to_fen()); } else { #if PORTABLE throw new Exception("File cannot be read."); #else System.IO.StreamReader sr = new System.IO.StreamReader(fenFile, true); string fensFromFile = sr.ReadToEnd(); sr.Close(); sr.Dispose(); string[] split = fensFromFile.Replace("\r", "").Split('\n'); foreach (string fen in split) { if (fen.Trim().Length > 0) { fens.Add(fen.Trim()); } } #endif } Stopwatch time = new Stopwatch(); long[] res = new long[fens.Count]; for (int i = 0; i < fens.Count; i++) { time.Reset(); time.Start(); Position pos = new Position(fens[i], bool.Parse(OptionMap.Instance["UCI_Chess960"].v), Threads.main_thread()); Plug.Write("\nPosition: "); Plug.Write((i + 1).ToString()); Plug.Write("/"); Plug.Write(fens.Count.ToString()); Plug.Write(Constants.endl); if (limitType == "perft") { Int64 cnt = Search.perft(pos, limits.depth * DepthC.ONE_PLY); Plug.Write("\nPerft "); Plug.Write(limits.depth.ToString()); Plug.Write(" leaf nodes: "); Plug.Write(cnt.ToString()); Plug.Write(Constants.endl); nodes = cnt; } else { Threads.start_searching(pos, limits, new List <Move>()); Threads.wait_for_search_finished(); nodes = Search.RootPosition.nodes; res[i] = nodes; } e = time.ElapsedMilliseconds; nodesAll += nodes; eAll += e; Plug.Write("\n==========================="); Plug.Write("\nTotal time (ms) : "); Plug.Write(e.ToString()); Plug.Write("\nNodes searched : "); Plug.Write(nodes.ToString()); Plug.Write("\nNodes/second : "); Plug.Write(((int)(nodes / (e / 1000.0))).ToString()); Plug.Write(Constants.endl); } Plug.Write("\n==========================="); Plug.Write("\nTotal time (ms) : "); Plug.Write(eAll.ToString()); Plug.Write("\nNodes searched : "); Plug.Write(nodesAll.ToString()); Plug.Write("\nNodes/second : "); Plug.Write(((int)(nodesAll / (eAll / 1000.0))).ToString()); Plug.Write(Constants.endl); //for (int i = 0; i < res.Length; i++) //{ // Plug.Write(string.Format("{0}: {1}", i, res[i])); // Plug.Write(Constants.endl); //} }