예제 #1
0
        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);
        }
예제 #2
0
        /// 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);
            //}
        }
예제 #3
0
        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);
        }
예제 #4
0
        // 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();
        }