Example #1
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();
        }
Example #2
0
        // start_thinking() wakes up the main thread sleeping in MainThread::idle_loop()
        // so to start a new search, then returns immediately.
        public void start_thinking(Position pos, LimitsType limits, StateStackPtr states)
        {
            wait_for_think_finished();

            Search.SearchTime = Time.now(); // As early as possible

            Search.Signals.stopOnPonderhit = Search.Signals.firstRootMove = false;
            Search.Signals.stop = Search.Signals.failedLowAtRoot = false;

            Search.RootMoves.Clear();
            Search.RootPos = pos;
            Search.Limits = limits;

            if (states.Count > 0) // If we don't set a new position, preserve current state
            {
                Search.SetupStates = states; // Ownership transfer here                
                //Debug.Assert(states==null);
            }

            for (MoveList it = new MoveList(pos, GenTypeS.LEGAL); it.move()!= 0; ++it)
                if (limits.searchmoves.Count == 0
                    || Misc.existSearchMove(limits.searchmoves, it.move()))
                    Search.RootMoves.Add(new RootMove(it.move()));

            main().thinking = true;
            main().notify_one(); // Starts main thread
        }
Example #3
0
        internal static void init(LimitsType limits, int currentPly, Color 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
            int emergencyMoveHorizon = int.Parse(OptionMap.Instance["Emergency Move Horizon"].v);
            int emergencyBaseTime    = int.Parse(OptionMap.Instance["Emergency Base Time"].v);
            int emergencyMoveTime    = int.Parse(OptionMap.Instance["Emergency Move Time"].v);
            int minThinkingTime      = int.Parse(OptionMap.Instance["Minimum Thinking Time"].v);
            int 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);
        }
Example #4
0
            public static void Save(IValueSink sink, LimitsType value)
            {
                sink.EnterSequence();
                Value <uint> .Save(sink, value.DeviceInstanceRangeLowLimit);

                Value <uint> .Save(sink, value.DeviceInstanceRangeHighLimit);

                sink.LeaveSequence();
            }
Example #5
0
    /// init() is called at the beginning of the search and calculates the allowed
    /// thinking time out of the time control and current game ply. We support four
    /// different kinds of time controls, passed in 'limits':
    /// 
    /// inc == 0 && movestogo == 0 means: x basetime  [sudden death!]
    /// inc == 0 && movestogo != 0 means: x moves in y minutes
    /// inc >  0 && movestogo == 0 means: x basetime + z increment
    /// inc >  0 && movestogo != 0 means: x moves in y minutes + z increment
    internal static void init(LimitsType limits, ColorT us, int ply, DateTime now)
    {
        var minThinkingTime = int.Parse(OptionMap.Instance["Minimum Thinking Time"].v);
        var moveOverhead = int.Parse(OptionMap.Instance["Move Overhead"].v);
        var slowMover = int.Parse(OptionMap.Instance["Slow Mover"].v);
        var npmsec = int.Parse(OptionMap.Instance["nodestime"].v);

        // If we have to play in 'nodes as time' mode, then convert from time
        // to nodes, and use resulting values in time management formulas.
        // WARNING: Given npms (nodes per millisecond) must be much lower then
        // real engine speed to avoid time losses.
        if (npmsec != 0)
        {
            if (availableNodes == 0) // Only once at game start
            {
                availableNodes = npmsec*limits.time[us]; // Time is in msec
            }

            // Convert from millisecs to nodes
            limits.time[us] = (int) availableNodes;
            limits.inc[us] *= npmsec;
            limits.npmsec = npmsec;
        }

        start = now;
        unstablePvFactor = 1;
        optimumTime = maximumTime = Math.Max(limits.time[us], minThinkingTime);

        var MaxMTG = limits.movestogo != 0 ? Math.Min(limits.movestogo, MoveHorizon) : MoveHorizon;

        // We calculate optimum time usage for different hypothetical "moves to go"-values
        // and choose the minimum of calculated search time values. Usually the greatest
        // hypMTG gives the minimum values.
        for (var hypMTG = 1; hypMTG <= MaxMTG; ++hypMTG)
        {
            // Calculate thinking time for hypothetical "moves to go"-value
            var hypMyTime = limits.time[us] + limits.inc[us] *(hypMTG - 1) - moveOverhead*(2 + Math.Min(hypMTG, 40));

            hypMyTime = Math.Max(hypMyTime, 0);

            var t1 = minThinkingTime + remaining(TimeType.OptimumTime, hypMyTime, hypMTG, ply, slowMover);
            var t2 = minThinkingTime + remaining(TimeType.MaxTime, hypMyTime, hypMTG, ply, slowMover);

            optimumTime = Math.Min(t1, optimumTime);
            maximumTime = Math.Min(t2, maximumTime);
        }

        if (bool.Parse(OptionMap.Instance["Ponder"].v))
        {
            optimumTime += optimumTime/4;
        }

        optimumTime = Math.Min(optimumTime, maximumTime);
    }
Example #6
0
        // 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);
        }
Example #7
0
    // ThreadPool::start_thinking() wakes up the main thread sleeping in
    // MainThread::idle_loop() and starts a new search, then returns immediately.

    internal static void start_thinking(Position pos, LimitsType limits, StateInfoWrapper states)
    {
        main().join();
        Search.Signals.stopOnPonderhit = Search.Signals.firstRootMove = false;
        Search.Signals.stop = Search.Signals.failedLowAtRoot = false;

        Search.RootMoves.Clear();
        Search.RootPos = new Position(pos);
        Search.Limits = limits;

        var current = states[states.current];
        if (current != null) // If we don't set a new position, preserve current state
        {
            Search.SetupStates = states; // Ownership transfer here
            Debug.Assert(current != null);
        }

        var ml = new MoveList(GenType.LEGAL, pos);
        for (var index = ml.begin(); index < ml.end(); index++)
        {
            var m = ml.moveList.table[index];
            if (limits.searchmoves.Count == 0 || limits.searchmoves.FindAll(move => move == m.Move).Count > 0)
            {
                Search.RootMoves.Add(new RootMove(m));
            }
        }

        main().thinking = true;
        main().notify_one(); // Wake up main thread: 'thinking' must be already set
    }
Example #8
0
    // go() is called when engine receives the "go" UCI command. The function sets
    // the thinking time and other parameters from the input string, then starts
    // the search.
    internal static void go(Position pos, Stack<string> stack)
    {
        var token = string.Empty;
        var limits = new LimitsType();

        while (stack.Count > 0)
        {
            token = stack.Pop();

            if (token == "wtime")
            {
                limits.time[Color.WHITE] = int.Parse(stack.Pop());
            }
            else if (token == "btime")
            {
                limits.time[Color.BLACK] = int.Parse(stack.Pop());
            }
            else if (token == "winc")
            {
                limits.inc[Color.WHITE] = int.Parse(stack.Pop());
            }
            else if (token == "binc")
            {
                limits.inc[Color.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 = ulong.Parse(stack.Pop());
            }
            else if (token == "movetime")
            {
                limits.movetime = int.Parse(stack.Pop());
            }
            else if (token == "mate")
            {
                limits.mate = 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)
                {
                    limits.searchmoves.Add(to_move(pos, token));
                }
            }
        }

        ThreadPool.start_thinking(pos, limits, SetupStates);
    }
Example #9
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);
            //}
        }
Example #10
0
 public static void Save(IValueSink sink, LimitsType value)
 {
     sink.EnterSequence();
     Value<uint>.Save(sink, value.DeviceInstanceRangeLowLimit);
     Value<uint>.Save(sink, value.DeviceInstanceRangeHighLimit);
     sink.LeaveSequence();
 }
        /// 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 13), 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.
        public static void benchmark(Position current, Stack <string> stack)
        {
            LimitsType    limits = new LimitsType();
            List <string> fens   = new List <string>();

            // Assign default values to missing arguments
            string ttSize    = (stack.Count > 0) ? (stack.Pop()) : "32";
            string threads   = (stack.Count > 0) ? (stack.Pop()) : "1";
            string limit     = (stack.Count > 0) ? (stack.Pop()) : "14";
            string fenFile   = (stack.Count > 0) ? (stack.Pop()) : "default";
            string limitType = (stack.Count > 0) ? (stack.Pop()) : "depth";
            string cantidad  = (stack.Count > 0) ? (stack.Pop()) : "20";
            string desde     = (stack.Count > 0) ? (stack.Pop()) : "1";

            //string desde = (stack.Count > 0) ? (stack.Pop()) : "1";
            //string cantidad = (stack.Count > 0) ? (stack.Pop()) : "100000";
            //string limit = (stack.Count > 0) ? (stack.Pop()) : "21";
            //string fenFile = (stack.Count > 0) ? (stack.Pop()) : "default";
            //string ttSize = (stack.Count > 0) ? (stack.Pop()) : "32";
            //string threads = (stack.Count > 0) ? (stack.Pop()) : "1";
            //string limitType = (stack.Count > 0) ? (stack.Pop()) : "depth";


            Options["Hash"].setCurrentValue(ttSize);
            Options["Threads"].setCurrentValue(threads);
            TT.clear();

            if (limitType == "time")
            {
                limits.movetime = 1000 * int.Parse(limit); // movetime is in ms
            }
            else if (limitType == "nodes")
            {
                limits.nodes = int.Parse(limit);
            }

            else if (limitType == "mate")
            {
                limits.mate = int.Parse(limit);
            }

            else
            {
                limits.depth = int.Parse(limit);
            }

            if (fenFile == "default")
            {
                fens.AddRange(Defaults);
            }

            else if (fenFile == "current")
            {
                fens.Add(current.fen());
            }

            else
            {
                String fen;
                System.IO.StreamReader sr = new System.IO.StreamReader(fenFile, true);
                int leidos     = 0;
                int ingresados = 0;
                int init       = Int32.Parse(desde);
                int n          = Int32.Parse(cantidad);
                while (!sr.EndOfStream)
                {
                    fen = sr.ReadLine().Trim();
                    leidos++;

                    if (leidos >= init && ingresados <= n)
                    {
                        fens.Add(fen);
                        ingresados++;
                        if (ingresados >= n)
                        {
                            break;
                        }
                    }
                }

                sr.Close();
                sr.Dispose();
            }

            Int64         nodes   = 0;
            StateStackPtr st      = new StateStackPtr();
            long          elapsed = Time.now();

            for (int i = 0; i < fens.Count; ++i)
            {
                //time.Reset(); time.Start();
                Position pos = new Position(fens[i], Options["UCI_Chess960"].getInt() != 0 ? 1 : 0, Threads.main());

                inOut.Write(Types.newline + "Position: " + (i + 1).ToString() + "/" + fens.Count.ToString() + Types.newline);

                inOut.Write(": ");
                inOut.Write(fens[i]);
                inOut.Write(Types.newline);
                if (limitType == "divide")
                {
                    /**
                     * for (MoveList<LEGAL> it(pos); *it; ++it)
                     * {
                     *    StateInfo si;
                     *    pos.do_move(*it, si);
                     *    uint64_t cnt = limits.depth > 1 ? Search::perft(pos, (limits.depth - 1) * ONE_PLY) : 1;
                     *    pos.undo_move(*it);
                     *    cerr << move_to_uci(*it, pos.is_chess960()) << ": " << cnt << endl;
                     *    nodes += cnt;
                     * }
                     */
                }
                if (limitType == "perft")
                {
                    /**
                     * uint64_t cnt = Search::perft(pos, limits.depth * ONE_PLY);
                     * cerr << "\nPerft " << limits.depth  << " leaf nodes: " << cnt << endl;
                     *  nodes += cnt;
                     */
                }
                else
                {
                    Engine.Threads.start_thinking(pos, limits, st);
                    Threads.wait_for_think_finished();
                    nodes += (Int64)Search.RootPos.nodes_searched();
                }
            }

            elapsed = Time.now() - elapsed + 1; // Assure positive to avoid a 'divide by zero'

            inOut.Write(Types.newline + "===========================");
            inOut.Write(Types.newline + "Total time (ms) : " + elapsed.ToString());
            inOut.Write(Types.newline + "Nodes searched  : " + nodes.ToString());
            inOut.Write(Types.newline + "Nodes/second    : " + (1000 * nodes / elapsed).ToString() + Types.newline);
        }
        public static void benchfile(Position current, Stack <string> stack)
        {
            LimitsType limits = new LimitsType();

            // Assign default values to missing arguments
            //string ttSize = (stack.Count > 0) ? (stack.Pop()) : "32";
            //string threads = (stack.Count > 0) ? (stack.Pop()) : "1";
            //string limit = (stack.Count > 0) ? (stack.Pop()) : "14";
            //string fenFile = (stack.Count > 0) ? (stack.Pop()) : "default";
            //string limitType = (stack.Count > 0) ? (stack.Pop()) : "depth";
            //string cantidad = (stack.Count > 0) ? (stack.Pop()) : "20";

            string desde     = (stack.Count > 0) ? (stack.Pop()) : "17771192";
            string limit     = (stack.Count > 0) ? (stack.Pop()) : "1";
            string fenFile   = (stack.Count > 0) ? (stack.Pop()) : "c:\\fen\\unique00.fen";
            string desFile   = (stack.Count > 0) ? (stack.Pop()) : fenFile + ".dat2";
            string ttSize    = (stack.Count > 0) ? (stack.Pop()) : "32";
            string threads   = (stack.Count > 0) ? (stack.Pop()) : "1";
            string limitType = (stack.Count > 0) ? (stack.Pop()) : "depth";


            Options["Hash"].setCurrentValue(ttSize);
            Options["Threads"].setCurrentValue(threads);
            TT.clear();

            if (limitType == "time")
            {
                limits.movetime = 1000 * int.Parse(limit); // movetime is in ms
            }
            else if (limitType == "nodes")
            {
                limits.nodes = int.Parse(limit);
            }

            else if (limitType == "mate")
            {
                limits.mate = int.Parse(limit);
            }

            else
            {
                limits.depth = int.Parse(limit);
            }


            String fen;

            System.IO.StreamReader sr      = new System.IO.StreamReader(fenFile, true);
            System.IO.StreamWriter outfile = new System.IO.StreamWriter(desFile, false);

            Int64         i     = 0;
            Int64         nodes = 0;
            StateStackPtr st    = new StateStackPtr();
            //Stopwatch time = new Stopwatch();
            long elapsed = Time.now();
            int  inicio  = Int32.Parse(desde);

            while (!sr.EndOfStream)
            {
                fen = sr.ReadLine().Trim();
                i++;
                if (i < inicio)
                {
                    continue;
                }
                Position pos = new Position(fen, Options["UCI_Chess960"].getInt() != 0 ? 1 : 0, Threads.main());

                inOut.Write(Types.newline);
                inOut.Write("Position: ");
                inOut.Write((i + 1).ToString());
                inOut.Write(": ");
                inOut.Write(fen);
                inOut.Write(Types.newline);

                if (limitType == "perft")
                {
                    //int cnt = Search.perft(pos, limits.depth * DepthS.ONE_PLY);
                    //inOut.Write(Types.newline);
                    //inOut.Write("Perft ");
                    //inOut.Write(limits.depth.ToString());
                    //inOut.Write(" leaf nodes: ");
                    //inOut.Write(cnt.ToString());
                    //inOut.Write(Types.newline);
                    //nodes += cnt;
                }
                else
                {
                    Engine.Threads.start_thinking(pos, limits, st);
                    Threads.wait_for_think_finished();
                    nodes += (Int64)Search.RootPos.nodes_searched();
                    outfile.WriteLine(i + "\t" + Search.RootPos.nodes_searched() + "\t" + Search.RootMoves[0].pv[0] + "\t" + Search.RootMoves[0].pv[1] + "\t" + nodes + "\t" + fen);
                }

                if (i % 10000 == 0)
                {
                    outfile.Flush();
                    inOut.Write(Types.newline);
                    inOut.Write(i.ToString());
                }
            }

            sr.Close();
            sr.Dispose();
            outfile.Close();
            outfile.Dispose();


            elapsed = Time.now() - elapsed + 1; // Assure positive to avoid a 'divide by zero'

            inOut.Write(Types.newline);
            inOut.Write("===========================");

            inOut.Write(Types.newline);
            inOut.Write("Total time (ms) : ");
            inOut.Write(elapsed.ToString());

            inOut.Write(Types.newline);
            inOut.Write("Nodes searched  : ");
            inOut.Write(nodes.ToString());

            inOut.Write(Types.newline);
            inOut.Write("Nodes/second    : ");
            inOut.Write((1000 * nodes / elapsed).ToString());
            inOut.Write(Types.newline);
        }
Example #13
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 13), 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 millisecs or number of nodes.
    internal static void benchmark(Position current, Stack<string> stack)
    {
        var fens = new List<string>();

        var limits = new LimitsType();
        long nodes = 0;

        // Assign default values to missing arguments
        var ttSize = (stack.Count > 0) ? (stack.Pop()) : "16";
        var threads = (stack.Count > 0) ? (stack.Pop()) : "1";
#if DEBUG
        var limit = (stack.Count > 0) ? (stack.Pop()) : "7";
#else
        var limit = (stack.Count > 0) ? (stack.Pop()) : "13";
#endif
        var fenFile = (stack.Count > 0) ? (stack.Pop()) : "default";
        var limitType = (stack.Count > 0) ? (stack.Pop()) : "depth";

        OptionMap.Instance["Hash"].v = ttSize;
        OptionMap.Instance["Threads"].v = threads;
        Search.reset();

        if (limitType == "time")
        {
            limits.movetime = int.Parse(limit); // movetime is in ms
        }

        else if (limitType == "nodes")
        {
            limits.nodes = ulong.Parse(limit);
        }

        else if (limitType == "mate")
        {
            limits.mate = int.Parse(limit);
        }

        else
        {
            limits.depth = int.Parse(limit);
        }

        if (fenFile == "default")
        {
            fens.AddRange(Defaults);
        }

        else if (fenFile == "current")
        {
            fens.Add(current.fen());
        }

        else
        {
            var sr = new StreamReader(fenFile, true);
            var fensFromFile = sr.ReadToEnd();
            sr.Close();
            sr.Dispose();

            var split = fensFromFile.Replace("\r", "").Split('\n');
            fens.AddRange(from fen in split where fen.Trim().Length > 0 select fen.Trim());
        }

        var time = Stopwatch.StartNew();

        for (var i = 0; i < fens.Count; ++i)
        {
            var pos = new Position(fens[i], bool.Parse(OptionMap.Instance["UCI_Chess960"].v), ThreadPool.main());

            Output.WriteLine($"\nPosition: {i + 1} / {fens.Count}");

            if (limitType == "perft")
            {
                nodes += Search.perft(true, pos, limits.depth*Depth.ONE_PLY);
            }

            else
            {
                var st = new StateInfoWrapper();
                ThreadPool.start_thinking(pos, limits, st);
                ThreadPool.main().join();
                nodes += Search.RootPos.nodes_searched();
            }
        }

        var elapsed = time.ElapsedMilliseconds; // Ensure positivity to avoid a 'divide by zero'

        Output.Write("\n===========================");
        Output.Write($"\nTotal time (ms) : {elapsed}");
        Output.Write($"\nNodes searched  : {nodes}");
        Output.WriteLine($"\nNodes/second    : {1000*nodes/elapsed}");
    }