internal static int SetupStatePos = 0; // *SetupState = StateRingBuf; #endregion Fields #region Methods // go() is called when engine receives the "go" UCI command. The function sets // the thinking time and other parameters from the input string, and then starts // the main searching thread. internal static void go(Position pos, Stack<string> stack) { string token = string.Empty; LimitsType limits = new LimitsType(); List<Move> searchMoves = new List<Phase>(); while (stack.Count > 0) { token = stack.Pop(); if (token == "wtime") limits.time[ColorC.WHITE] = int.Parse(stack.Pop()); else if (token == "btime") limits.time[ColorC.BLACK] = int.Parse(stack.Pop()); else if (token == "winc") limits.inc[ColorC.WHITE] = int.Parse(stack.Pop()); else if (token == "binc") limits.inc[ColorC.BLACK] = int.Parse(stack.Pop()); else if (token == "movestogo") limits.movesToGo = int.Parse(stack.Pop()); else if (token == "depth") limits.depth = int.Parse(stack.Pop()); else if (token == "nodes") limits.nodes = int.Parse(stack.Pop()); else if (token == "movetime") limits.movetime = int.Parse(stack.Pop()); else if (token == "infinite") limits.infinite = 1; else if (token == "ponder") limits.ponder = true; else if (token == "searchmoves") while ((token = stack.Pop()) != null) { searchMoves.Add(Utils.move_from_uci(pos, token)); } } Threads.start_searching(pos, limits, searchMoves); }
/// 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); //} }
internal static void init(LimitsType limits, int currentPly, int us) { /* We support four different kind of time controls: increment == 0 && movesToGo == 0 means: x basetime [sudden death!] increment == 0 && movesToGo != 0 means: x moves in y minutes increment > 0 && movesToGo == 0 means: x basetime + z increment increment > 0 && movesToGo != 0 means: x moves in y minutes + z increment Time management is adjusted by following UCI parameters: emergencyMoveHorizon: Be prepared to always play at least this many moves emergencyBaseTime : Always attempt to keep at least this much time (in ms) at clock emergencyMoveTime : Plus attempt to keep at least this much time for each remaining emergency move minThinkingTime : No matter what, use at least this much thinking before doing the move */ int hypMTG, hypMyTime, t1, t2; // Read uci parameters var emergencyMoveHorizon = int.Parse(OptionMap.Instance["Emergency Move Horizon"].v); var emergencyBaseTime = int.Parse(OptionMap.Instance["Emergency Base Time"].v); var emergencyMoveTime = int.Parse(OptionMap.Instance["Emergency Move Time"].v); var minThinkingTime = int.Parse(OptionMap.Instance["Minimum Thinking Time"].v); var slowMover = int.Parse(OptionMap.Instance["Slow Mover"].v); // Initialize to maximum values but unstablePVExtraTime that is reset unstablePVExtraTime = 0; optimumSearchTime = maximumSearchTime = limits.time[us]; // We calculate optimum time usage for different hypothetic "moves to go"-values and choose the // minimum of calculated search time values. Usually the greatest hypMTG gives the minimum values. for (hypMTG = 1; hypMTG <= ((limits.movesToGo != 0) ? Math.Min(limits.movesToGo, MoveHorizon) : MoveHorizon); hypMTG++) { // Calculate thinking time for hypothetic "moves to go"-value hypMyTime = limits.time[us] + limits.inc[us] * (hypMTG - 1) - emergencyBaseTime - emergencyMoveTime * Math.Min(hypMTG, emergencyMoveHorizon); hypMyTime = Math.Max(hypMyTime, 0); t1 = minThinkingTime + remaining(TimeTypeC.OptimumTime, hypMyTime, hypMTG, currentPly, slowMover); t2 = minThinkingTime + remaining(TimeTypeC.MaxTime, hypMyTime, hypMTG, currentPly, slowMover); optimumSearchTime = Math.Min(optimumSearchTime, t1); maximumSearchTime = Math.Min(maximumSearchTime, t2); } if (bool.Parse(OptionMap.Instance["Ponder"].v)) { optimumSearchTime += optimumSearchTime / 4; } // Make sure that maxSearchTime is not over absoluteMaxSearchTime optimumSearchTime = Math.Min(optimumSearchTime, maximumSearchTime); }
// ThreadsManager::start_searching() wakes up the main thread sleeping in // main_loop() so to start a new search, then returns immediately. internal static void start_searching(Position pos, LimitsType limits, List<Move> searchMoves) { wait_for_search_finished(); Search.SearchTime.Reset(); Search.SearchTime.Start(); // As early as possible Search.SignalsStopOnPonderhit = Search.SignalsFirstRootMove = false; Search.SignalsStop = Search.SignalsFailedLowAtRoot = false; Search.RootPosition.copy(pos); Search.Limits = limits; Search.RootMoves.Clear(); MList mlist = MListBroker.GetObject(); mlist.pos = 0; Movegen.generate_legal(pos, mlist.moves, ref mlist.pos); for (int i = 0; i < mlist.pos; i++) { Move move = mlist.moves[i].move; if ((searchMoves.Count == 0) || Utils.existSearchMove(searchMoves, move)) { Search.RootMoves.Add(new RootMove(move)); } } MListBroker.Free(); main_thread().do_sleep = false; main_thread().wake_up(); }