Пример #1
0
        public void Run(object arguments)
        {
            string[] args = (string[])arguments;

            Plug.Write(Utils.engine_info());
            Plug.Write(Constants.endl);

            CheckInfoBroker.init();
            EvalInfoBroker.init();
            SwapListBroker.init();
            MovesSearchedBroker.init();
            PositionBroker.init();
            StateInfoArrayBroker.init();

            MListBroker.init();
            LoopStackBroker.init();
            MovePickerBroker.init();
            StateInfoBroker.init();

            Utils.init();
            Book.init();
            Position.init();
            KPKPosition.init();
            Endgame.init();
            Search.init();
            Evaluate.init();

            Threads.init();

            // .Net warmup sequence
            Plug.IsWarmup = true;
            Position       pos   = new Position(Uci.StartFEN, false, Threads.main_thread());
            Stack <string> stack = Utils.CreateStack("go depth 7");

            Uci.go(pos, stack);
            Threads.wait_for_search_finished();
            Plug.IsWarmup = false;

            StringBuilder sb = new StringBuilder();

            for (int i = 1; i < args.Length; i++)
            {
                sb.Append(args[i]).Append(" ");
            }

            Uci.uci_loop(sb.ToString());

            Threads.exit();
        }
Пример #2
0
        internal Thread(ThreadLoopType lt, ManualResetEvent initEvent)
        {
            is_searching  = do_exit = false;
            maxPly        = splitPointsCnt = 0;
            curSplitPoint = null;
            loopType      = lt;
            idx           = Threads.size();

            do_sleep = loopType != ThreadLoopType.Main; // Avoid a race with start_searching()

            for (int j = 0; j < Constants.MAX_SPLITPOINTS_PER_THREAD; j++)
            {
                splitPoints[j] = new SplitPoint();
            }

#if WINDOWS_RT
            Windows.Foundation.IAsyncAction action = Windows.System.Threading.ThreadPool.RunAsync(delegate { StartThread(initEvent); }, WorkItemPriority.Normal);
#else
            ThreadPool.QueueUserWorkItem(this.StartThread, initEvent);
#endif
        }
Пример #3
0
        // set_position() is called when engine receives the "position" UCI
        // command. The function sets up the position described in the given
        // fen string ("fen") or the starting position ("startpos") and then
        // makes the moves given in the following move list ("moves").
        internal static void set_position(Position pos, Stack <string> stack)
        {
            Move   m;
            string token, fen = string.Empty;

            token = stack.Pop();

            if (token == "startpos")
            {
                fen = StartFEN;
                if (stack.Count > 0)
                {
                    token = stack.Pop();
                }                                             // Consume "moves" token if any
            }
            else if (token == "fen")
            {
                while ((stack.Count > 0) && (token = stack.Pop()) != "moves")
                {
                    fen += token + " ";
                }
            }
            else
            {
                return;
            }

            pos.from_fen(fen, bool.Parse(OptionMap.Instance["UCI_Chess960"].v), Threads.main_thread());

            // Parse move list (if any)
            while ((stack.Count > 0) && (m = Utils.move_from_uci(pos, token = stack.Pop())) != MoveC.MOVE_NONE)
            {
                pos.do_move(m, StateRingBuf[SetupStatePos]);

                // Increment pointer to StateRingBuf circular buffer
                SetupStatePos = (SetupStatePos + 1) % 102;
            }
        }
Пример #4
0
        /// Thread::idle_loop() is where the thread is parked when it has no work to do.
        /// The parameter 'master_sp', if non-NULL, is a pointer to an active SplitPoint
        /// object for which the thread is the master.
        internal void idle_loop(SplitPoint sp_master, ManualResetEvent initEvent)
        {
            if (initEvent != null)
            {
                // Signal done
                initEvent.Set();
            }

            bool use_sleeping_threads = Threads.useSleepingThreads;

            // If this thread is the master of a split point and all slaves have
            // finished their work at this split point, return from the idle loop.
            while ((sp_master == null) || (sp_master.slavesMask != 0))
            {
                // If we are not searching, wait for a condition to be signaled
                // instead of wasting CPU time polling for work.
                while (do_sleep ||
                       do_exit ||
                       (!is_searching && use_sleeping_threads))
                {
                    if (do_exit)
                    {
                        Debug.Assert(sp_master == null);
                        return;
                    }

                    // Grab the lock to avoid races with Thread::wake_up()
                    ThreadHelper.lock_grab(sleepLock);

                    // If we are master and all slaves have finished don't go to sleep
                    if ((sp_master != null) && (sp_master.slavesMask == 0))
                    {
                        ThreadHelper.lock_release(sleepLock);
                        break;
                    }

                    // Do sleep after retesting sleep conditions under lock protection, in
                    // particular we need to avoid a deadlock in case a master thread has,
                    // in the meanwhile, allocated us and sent the wake_up() call before we
                    // had the chance to grab the lock.
                    if (do_sleep || !is_searching)
                    {
                        ThreadHelper.cond_wait(sleepCond, sleepLock);
                    }

                    ThreadHelper.lock_release(sleepLock);
                }

                // If this thread has been assigned work, launch a search
                if (is_searching)
                {
                    Debug.Assert(!do_sleep && !do_exit);

                    ThreadHelper.lock_grab(Threads.splitLock);

                    Debug.Assert(is_searching);
                    SplitPoint sp = curSplitPoint;

                    ThreadHelper.lock_release(Threads.splitLock);

                    LoopStack ls    = LoopStackBroker.GetObject();
                    Stack[]   ss    = ls.ss;
                    int       ssPos = 0;

                    Position pos = PositionBroker.GetObject();
                    pos.copy(sp.pos, this);

                    Array.Copy(sp.ss, sp.ssPos - 1, ss, ssPos, 4);
                    ss[ssPos + 1].sp = sp;

                    ThreadHelper.lock_grab(sp.Lock);

                    if (sp.nodeType == NodeTypeC.Root)
                    {
                        Search.search(NodeTypeC.SplitPointRoot, pos, ss, ssPos + 1, sp.alpha, sp.beta, sp.depth);
                    }
                    else if (sp.nodeType == NodeTypeC.PV)
                    {
                        Search.search(NodeTypeC.SplitPointPV, pos, ss, ssPos + 1, sp.alpha, sp.beta, sp.depth);
                    }
                    else if (sp.nodeType == NodeTypeC.NonPV)
                    {
                        Search.search(NodeTypeC.SplitPointNonPV, pos, ss, ssPos + 1, sp.alpha, sp.beta, sp.depth);
                    }
                    else
                    {
                        Debug.Assert(false);
                    }

                    Debug.Assert(is_searching);

                    is_searching = false;
#if ACTIVE_REPARENT
                    sp.allSlavesRunning = false;
#endif
                    sp.slavesMask &= ~(1UL << idx);
                    sp.nodes      += pos.nodes;

                    // Wake up master thread so to allow it to return from the idle loop in
                    // case we are the last slave of the split point.
                    if (use_sleeping_threads &&
                        this != sp.master &&
                        !sp.master.is_searching)
                    {
                        sp.master.wake_up();
                    }

                    // After releasing the lock we cannot access anymore any SplitPoint
                    // related data in a safe way becuase it could have been released under
                    // our feet by the sp master. Also accessing other Thread objects is
                    // unsafe because if we are exiting there is a chance are already freed.
                    ThreadHelper.lock_release(sp.Lock);

#if ACTIVE_REPARENT
                    // Try to reparent to the first split point, with still all slaves
                    // running, where we are available as a possible slave.
                    for (int i = 0; i < Threads.size(); i++)
                    {
                        Thread     th     = Threads.threads[i];
                        int        spCnt  = th.splitPointsCnt;
                        SplitPoint latest = th.splitPoints[spCnt != 0 ? spCnt - 1 : 0];

                        if (this.is_available_to(th) &&
                            spCnt > 0 &&
                            !th.cutoff_occurred() &&
                            latest.allSlavesRunning &&
                            Utils.more_than_one(latest.slavesMask))
                        {
                            ThreadHelper.lock_grab(latest.Lock);
                            ThreadHelper.lock_grab(Threads.splitLock);

                            // Retest all under lock protection, we are in the middle
                            // of a race storm here !
                            if (this.is_available_to(th) &&
                                spCnt == th.splitPointsCnt &&
                                !th.cutoff_occurred() &&
                                latest.allSlavesRunning &&
                                Utils.more_than_one(latest.slavesMask))
                            {
                                latest.slavesMask |= 1UL << idx;
                                curSplitPoint      = latest;
                                is_searching       = true;
                            }

                            ThreadHelper.lock_release(Threads.splitLock);
                            ThreadHelper.lock_release(latest.Lock);

                            break; // Exit anyhow, only one try (enough in 99% of cases)
                        }
                    }
#endif

                    pos.startState = null;
                    pos.st         = null;
                    PositionBroker.Free();
                    LoopStackBroker.Free(ls);
                }
            }
        }
Пример #5
0
        internal static int SetupStatePos = 0; // *SetupState = StateRingBuf;

        /// Wait for a command from the user, parse this text string as an UCI command,
        /// and call the appropriate functions. Also intercepts EOF from stdin to ensure
        /// that we exit gracefully if the GUI dies unexpectedly. In addition to the UCI
        /// commands, the function also supports a few debug commands.
        internal static void uci_loop(string args)
        {
            for (int i = 0; i < 102; i++)
            {
                StateRingBuf[i] = new StateInfo();
            }

            Position pos = new Position(StartFEN, false, Threads.main_thread()); // The root position
            string   cmd, token = string.Empty;

            while (token != "quit")
            {
                if (args.Length > 0)
                {
                    cmd = args;
                }
                else if (String.IsNullOrEmpty(cmd = Plug.ReadLine())) // Block here waiting for input
                {
                    cmd = "quit";
                }
                Stack <string> stack = Utils.CreateStack(cmd);

                token = stack.Pop();

                if (token == "quit" || token == "stop")
                {
                    Search.SignalsStop = true;
                    Threads.wait_for_search_finished(); // Cannot quit while threads are running
                }
                else if (token == "ponderhit")
                {
                    // The opponent has played the expected move. GUI sends "ponderhit" if
                    // we were told to ponder on the same move the opponent has played. We
                    // should continue searching but switching from pondering to normal search.
                    Search.Limits.ponder = false;

                    if (Search.SignalsStopOnPonderhit)
                    {
                        Search.SignalsStop = true;
                        Threads.main_thread().wake_up(); // Could be sleeping
                    }
                }
                else if (token == "go")
                {
                    go(pos, stack);
                }
                else if (token == "ucinewgame")
                { /* Avoid returning "Unknown command" */
                }
                else if (token == "isready")
                {
                    Plug.Write("readyok");
                    Plug.Write(Constants.endl);
                }
                else if (token == "position")
                {
                    set_position(pos, stack);
                }
                else if (token == "setoption")
                {
                    set_option(stack);
                }
                else if (token == "validmoves")
                {
                    Search.validmoves(pos, stack);
                }
                else if (token == "d")
                {
                    pos.print(0);
                }
                else if (token == "flip")
                {
                    pos.flip();
                }
                else if (token == "eval")
                {
                    Plug.Write(Evaluate.trace(pos));
                    Plug.Write(Constants.endl);
                }
                else if (token == "bench")
                {
                    Benchmark.benchmark(pos, stack);
                }
                else if (token == "key")
                {
                    Plug.Write("key: ");
                    Plug.Write(String.Format("{0:X}", pos.key()));
                    Plug.Write("\nmaterial key: ");
                    Plug.Write(pos.material_key().ToString());
                    Plug.Write("\npawn key: ");
                    Plug.Write(pos.pawn_key().ToString());
                    Plug.Write(Constants.endl);
                }
                else if (token == "uci")
                {
                    Plug.Write("id name "); Plug.Write(Utils.engine_info(true));
                    Plug.Write("\n"); Plug.Write(OptionMap.Instance.ToString());
                    Plug.Write("\nuciok"); Plug.Write(Constants.endl);
                }
                else if (token == "perft")
                {
                    token = stack.Pop();  // Read depth
                    Stack <string> ss = Utils.CreateStack(
                        string.Format("{0} {1} {2} current perft", OptionMap.Instance["Hash"].v, OptionMap.Instance["Threads"].v, token)
                        );
                    Benchmark.benchmark(pos, ss);
                }
                else
                {
                    Plug.Write("Unknown command: ");
                    Plug.Write(cmd);
                    Plug.Write(Constants.endl);
                }

                if (args.Length > 0) // Command line arguments have one-shot behaviour
                {
                    Threads.wait_for_search_finished();
                    break;
                }
            }
        }
Пример #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);
        }
Пример #7
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);
            //}
        }
Пример #8
0
 internal static void on_threads(UCIOption opt)
 {
     Threads.read_uci_options(null);
 }