Пример #1
0
        /// <summary>
        /// Processes a specified position command,
        /// with the side effect of resetting the curPositionAndMoves.
        /// </summary>
        /// <param name="command"></param>
        private void ProcessPosition(string command)
        {
            command = StringUtils.WhitespaceRemoved(command);

            string commandLower = command.ToLower();

            string posString;

            if (commandLower.StartsWith("position fen "))
            {
                posString = command.Substring(13);
            }
            else if (commandLower.StartsWith("position startpos"))
            {
                posString = command.Substring(9);
            }
            else
            {
                throw new Exception($"Illegal position command, expected to start with position fen or position startpos");
            }

            PositionWithHistory newPositionAndMoves = PositionWithHistory.FromFENAndMovesUCI(posString);

            curPositionIsContinuationOfPrior = newPositionAndMoves.IsIdenticalToPriorToLastMove(curPositionAndMoves);
            if (!curPositionIsContinuationOfPrior && CeresEngine != null)
            {
                CeresEngine.ResetGame();
            }

            // Switch to the new position and moves
            curPositionAndMoves = newPositionAndMoves;
        }
Пример #2
0
        /// <summary>
        /// Processes a specified position command,
        /// with the side effect of resetting the curPositionAndMoves.
        /// </summary>
        /// <param name="command"></param>
        private void ProcessPosition(string command)
        {
            string[] parts = command.Split(" ");

            string fen;
            int    nextIndex;

            string startFEN;

            switch (parts[1])
            {
            case "fen":
                fen       = command.Substring(command.IndexOf("fen") + 4);
                nextIndex = 2;
                while (parts.Length > nextIndex && parts[nextIndex] != "moves")
                {
                    fen = fen + " " + parts[nextIndex++];
                }
                startFEN = fen;
                break;

            case "startpos":
                startFEN  = Position.StartPosition.FEN;
                nextIndex = 2;
                break;

            default:
                throw new Exception("invalid " + command);
            }

            string movesSubstring = "";

            if (parts.Length > nextIndex && parts[nextIndex] == "moves")
            {
                for (int i = nextIndex + 1; i < parts.Length; i++)
                {
                    movesSubstring += parts[i] + " ";
                }
            }

            PositionWithHistory newPositionAndMoves = PositionWithHistory.FromFENAndMovesUCI(startFEN, movesSubstring);

            curPositionIsContinuationOfPrior = newPositionAndMoves.IsIdenticalToPriorToLastMove(curPositionAndMoves);
            if (!curPositionIsContinuationOfPrior && CeresEngine != null)
            {
                CeresEngine.ResetGame();
            }

            // Switch to the new position and moves
            curPositionAndMoves = newPositionAndMoves;
        }
Пример #3
0
        /// <summary>
        /// Runs the UCI loop.
        /// </summary>
        public void PlayUCI()
        {
            // Default to the startpos.
            curPositionAndMoves = PositionWithHistory.FromFENAndMovesUCI(Position.StartPosition.FEN, null);
            curManager          = null;
            gameMoveHistory     = new List <GameMoveStat>();

            while (true)
            {
                string command = InStream.ReadLine();

                switch (command)
                {
                case null:
                case "":
                    break;

                case "uci":
                    Send("id name Ceres"); // TODO: Add executable version
                    Send("id author David Elliott and the Ceres Authors");
                    // todo output options such as:
                    //   option name Logfile type check default false
                    Send("uciok");
                    break;

                case "setoption":
                    OutStream.WriteLine("Not processing option " + command);
                    return;

                case "stop":
                    if (taskSearchCurrentlyExecuting != null && !stopIsPending)
                    {
                        stopIsPending = true;

                        // TODO: cleanup
                        //       Possible race condition, curManager is only set in search callback which may not have hit yet
                        //       Fix eventually by rewriting SerchManager to have a constructor and then non-static Search method,
                        //       os we can get the context in this class directly after construction
                        while (curManager == null)
                        {
                            Thread.Sleep(1);              // **** TEMPORARY ***
                        }
                        curManager.ExternalStopRequested = true;
                        if (taskSearchCurrentlyExecuting != null)
                        {
                            taskSearchCurrentlyExecuting.Wait();
                            if (!debug && taskSearchCurrentlyExecuting != null)
                            {
                                taskSearchCurrentlyExecuting.Result?.Manager?.Dispose();
                            }
                            taskSearchCurrentlyExecuting = null;
                        }
                    }

                    curManager    = null;
                    stopIsPending = false;

                    break;

                case "ponderhit":
                    throw new NotImplementedException("Ceres does not yet support UCI ponder mode.");
                    return;

                case "xboard":
                    // ignore
                    break;

                case "debug on":
                    debug = true;
                    break;

                case "debug off":
                    debug = false;
                    break;

                case "isready":
                    InitializeEngineIfNeeded();
                    Send("readyok");
                    break;

                case "ucinewgame":
                    gameMoveHistory = new List <GameMoveStat>();
                    CeresEngine?.ResetGame();
                    break;

                case "quit":
                    if (curManager != null)
                    {
                        curManager.ExternalStopRequested = true;
                        taskSearchCurrentlyExecuting?.Wait();
                    }

                    if (CeresEngine != null)
                    {
                        CeresEngine.Dispose();
                    }

                    System.Environment.Exit(0);
                    break;

                case string c when c.StartsWith("go"):
                    if (taskSearchCurrentlyExecuting != null)
                    {
                        throw new Exception("Received go command when another search was running and not stopped first");
                    }

                    InitializeEngineIfNeeded();

                    taskSearchCurrentlyExecuting = ProcessGo(command);
                    break;

                case string c when c.StartsWith("position"):
                    try
                    {
                        ProcessPosition(c);
                    }
                    catch (Exception e)
                    {
                        Send($"Illegal position command: \"{c}\"" + System.Environment.NewLine + e.ToString());
                    }
                    break;

                // Proprietary commands
                case "lc0-config":
                    if (curManager != null)
                    {
                        string             netID  = EvaluatorDef.Nets[0].Net.NetworkID;
                        INNWeightsFileInfo netDef = NNWeightsFiles.LookupNetworkFile(netID);
                        (string exe, string options) = LC0EngineConfigured.GetLC0EngineOptions(null, null, curContext.EvaluatorDef, netDef, false, false);
                        Console.WriteLine("info string " + exe + " " + options);
                    }
                    else
                    {
                        Console.WriteLine("info string No search manager created");
                    }

                    break;

                case "dump-params":
                    if (curManager != null)
                    {
                        curManager.DumpParams();
                    }
                    else
                    {
                        Console.WriteLine("info string No search manager created");
                    }
                    break;

                case "dump-processor":
                    HardwareManager.DumpProcessorInfo();
                    break;

                case "dump-time":
                    if (curManager != null)
                    {
                        curManager.DumpTimeInfo();
                    }
                    else
                    {
                        Console.WriteLine("info string No search manager created");
                    }
                    break;

                case "dump-store":
                    if (curManager != null)
                    {
                        using (new SearchContextExecutionBlock(curContext))
                            curManager.Context.Tree.Store.Dump(true);
                    }
                    else
                    {
                        Console.WriteLine("info string No search manager created");
                    }
                    break;

                case "dump-move-stats":
                    if (curManager != null)
                    {
                        using (new SearchContextExecutionBlock(curContext))
                            curManager.Context.Root.Dump(1, 1, prefixString: "info string ");
                    }
                    else
                    {
                        Console.WriteLine("info string No search manager created");
                    }
                    break;

                case "dump-pv":
                    DumpPV(false);
                    break;

                case "dump-pv-detail":
                    DumpPV(true);
                    break;

                case "dump-nvidia":
                    NVML.DumpInfo();
                    break;


                case "waitdone": // proprietary verb
                    taskSearchCurrentlyExecuting?.Wait();
                    break;

                default:
                    Console.WriteLine($"error Unknown command: {command}");
                    break;
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Runs the UCI loop.
        /// </summary>
        public void PlayUCI()
        {
            // Default to the startpos.
            curPositionAndMoves = PositionWithHistory.FromFENAndMovesUCI(Position.StartPosition.FEN);
            gameMoveHistory     = new List <GameMoveStat>();

            while (true)
            {
                string command = InStream.ReadLine();
                if (uciLogWriter != null)
                {
                    LogWriteLine("IN:", command);
                }

                switch (command)
                {
                case null:
                case "":
                    break;

                case "uci":
                    UCIWriteLine($"id name Ceres {CeresVersion.VersionString}");
                    UCIWriteLine("id author David Elliott and the Ceres Authors");
                    UCIWriteLine(SetOptionUCIDescriptions);
                    UCIWriteLine("uciok");
                    break;

                case string c when c.StartsWith("setoption"):
                    ProcessSetOption(command);

                    break;

                case "stop":
                    if (taskSearchCurrentlyExecuting != null && !stopIsPending)
                    {
                        stopIsPending = true;

                        // Avoid race condition by mkaing sure the search is already created.
                        while (CeresEngine.Search?.Manager == null)
                        {
                            Thread.Sleep(20);
                        }

                        CeresEngine.Search.Manager.ExternalStopRequested = true;
                        if (taskSearchCurrentlyExecuting != null)
                        {
                            taskSearchCurrentlyExecuting.Wait();
                            //                if (!debug && taskSearchCurrentlyExecuting != null) taskSearchCurrentlyExecuting.Result?.Search?.Manager?.Dispose();
                            taskSearchCurrentlyExecuting = null;
                        }
                    }

                    stopIsPending = false;

                    break;

                case "ponderhit":
                    throw new NotImplementedException("Ceres does not yet support UCI ponder mode.");
                    return;

                case "xboard":
                    // ignore
                    break;

                case "debug on":
                    debug = true;
                    break;

                case "debug off":
                    debug = false;
                    break;

                case "isready":
                    InitializeEngineIfNeeded();
                    UCIWriteLine("readyok");
                    break;

                case "ucinewgame":
                    gameMoveHistory = new List <GameMoveStat>();
                    CeresEngine?.ResetGame();
                    break;

                case "quit":
                    if (taskSearchCurrentlyExecuting != null)
                    {
                        CeresEngine.Search.Manager.ExternalStopRequested = true;
                        taskSearchCurrentlyExecuting?.Wait();
                    }

                    if (CeresEngine != null)
                    {
                        CeresEngine.Dispose();
                    }

                    System.Environment.Exit(0);
                    break;

                case string c when c.StartsWith("go"):

                    // Possibly another search is already executing.
                    // The UCI specification is unclear about what to do in this situation.
                    // Some engines seem to enqueue these for later execution (e.g. Stockfish)
                    // whereas others (e.g. Python chess) report this as an error condition.
                    // Currently Ceres waits only a short while for any possible pending search
                    // to finish (e.g. to avoid a race condition if it is in the process of being shutdown)
                    // and aborts with an error if search is still in progress.
                    // It is not viable to wait indefinitely, since (among other reasons)
                    // the engine needs to monitor for stop commands.
                    const int MAX_MILLISECONDS_WAIT = 500;

                    taskSearchCurrentlyExecuting?.Wait(MAX_MILLISECONDS_WAIT);

                    if (taskSearchCurrentlyExecuting != null && !taskSearchCurrentlyExecuting.IsCompleted)
                    {
                        throw new Exception("Received go command when another search was running and not stopped first.");
                    }

                    InitializeEngineIfNeeded();

                    taskSearchCurrentlyExecuting = ProcessGo(command);
                    break;

                case string c when c.StartsWith("position"):
                    try
                    {
                        ProcessPosition(c);
                    }
                    catch (Exception e)
                    {
                        UCIWriteLine($"Illegal position command: \"{c}\"" + System.Environment.NewLine + e.ToString());
                    }
                    break;

                // Proprietary commands
                case "lc0-config":
                    if (CeresEngine?.Search != null)
                    {
                        string             netID  = EvaluatorDef.Nets[0].Net.NetworkID;
                        INNWeightsFileInfo netDef = NNWeightsFiles.LookupNetworkFile(netID);
                        (string exe, string options) = LC0EngineConfigured.GetLC0EngineOptions(null, null, CeresEngine.Search.Manager.Context.EvaluatorDef, netDef, false, false);
                        UCIWriteLine("info string " + exe + " " + options);
                    }
                    else
                    {
                        UCIWriteLine("info string No search manager created");
                    }

                    break;

                case "dump-params":
                    if (CeresEngine?.Search != null)
                    {
                        CeresEngine?.Search.Manager.DumpParams();
                    }
                    else
                    {
                        UCIWriteLine("info string No search manager created");
                    }
                    break;

                case "dump-processor":
                    HardwareManager.DumpProcessorInfo();
                    break;

                case "dump-time":
                    if (CeresEngine?.Search != null)
                    {
                        CeresEngine?.Search.Manager.DumpTimeInfo(OutStream);
                    }
                    else
                    {
                        UCIWriteLine("info string No search manager created");
                    }
                    break;

                case "dump-store":
                    if (CeresEngine?.Search != null)
                    {
                        using (new SearchContextExecutionBlock(CeresEngine.Search.Manager.Context))
                            CeresEngine.Search.Manager.Context.Tree.Store.Dump(true);
                    }
                    else
                    {
                        UCIWriteLine("info string No search manager created");
                    }
                    break;

                case "dump-move-stats":
                    if (CeresEngine?.Search != null)
                    {
                        OutputVerboseMoveStats(CeresEngine.Search.SearchRootNode);
                    }
                    else
                    {
                        UCIWriteLine("info string No search manager created");
                    }
                    break;

                case "dump-pv":
                    DumpPV(false);
                    break;

                case "dump-pv-detail":
                    DumpPV(true);
                    break;

                case "dump-nvidia":
                    NVML.DumpInfo();
                    break;

                case "show-tree-plot":
                    if (CeresEngine?.Search != null)
                    {
                        using (new SearchContextExecutionBlock(CeresEngine.Search.Manager.Context))
                        {
                            TreePlot.Show(CeresEngine.Search.Manager.Context.Root.Ref);
                        }
                    }
                    else
                    {
                        UCIWriteLine("info string No search manager created");
                    }
                    break;

                case string c when c.StartsWith("save-tree-plot"):
                    if (CeresEngine?.Search != null)
                    {
                        string[] parts = command.Split(" ");
                        if (parts.Length == 2)
                        {
                            string fileName = parts[1];
                            using (new SearchContextExecutionBlock(CeresEngine.Search.Manager.Context))
                            {
                                TreePlot.Save(CeresEngine.Search.Manager.Context.Root.Ref, fileName);
                            }
                        }
                        else if (parts.Length == 1)
                        {
                            UCIWriteLine("Filename was not provided");
                        }
                        else
                        {
                            UCIWriteLine("Filename cannot contain spaces");
                        }
                    }

                    else
                    {
                        UCIWriteLine("info string No search manager created");
                    }
                    break;

                case "waitdone": // proprietary verb used for test driver
                    taskSearchCurrentlyExecuting?.Wait();
                    break;

                default:
                    UCIWriteLine($"error Unknown command: {command}");
                    break;
                }
            }
        }