/// 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);
        }