示例#1
0
    /// RootMove::insert_pv_in_tt() is called at the end of a search iteration, and
    /// inserts the PV back into the TT. This makes sure the old PV moves are searched
    /// first, even if the old TT entries have been overwritten.
    internal void insert_pv_in_tt(Position pos)
    {
        var st = new StateInfoWrapper();

        foreach (var m in pv)
        {
            Debug.Assert(new MoveList(GenType.LEGAL, pos).contains(m));

            bool ttHit;
            var tte = TranspositionTable.probe(pos.key(), out ttHit);

            if (!ttHit || tte.move() != m) // Don't overwrite correct entries
            {
                tte.save(
                    pos.key(),
                    Value.VALUE_NONE,
                    Bound.BOUND_NONE,
                    Depth.DEPTH_NONE,
                    m,
                    Value.VALUE_NONE,
                    TranspositionTable.generation());
            }

            var current = st[st.current];
            st++;
            pos.do_move(m, current, pos.gives_check(m, new CheckInfo(pos)));
        }

        for (var i = pv.Count; i > 0;)
        {
            pos.undo_move(pv[--i]);
        }
    }
示例#2
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
    }
示例#3
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}");
    }