Example #1
0
        /// <summary>
        /// Overridden virtual method that executs the search
        /// by issuing UCI commands to the LC0 engine with appropriate search limit parameters.
        /// </summary>
        /// <param name="curPositionAndMoves"></param>
        /// <param name="searchLimit"></param>
        /// <param name="gameMoveHistory"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        protected override GameEngineSearchResult DoSearch(PositionWithHistory curPositionAndMoves, SearchLimit searchLimit,
                                                           List <GameMoveStat> gameMoveHistory,
                                                           ProgressCallback callback, bool verbose)
        {
            DoSearchPrepare();

            if (SetupAction != null)
            {
                SetupAction();
            }

            string fen     = curPositionAndMoves.InitialPosition.FEN;
            string endFEN  = curPositionAndMoves.FinalPosition.FEN;
            string moveStr = curPositionAndMoves.MovesStr;

            // Run the analysis
            LC0VerboseMoveStats lc0Analysis = LC0Engine.AnalyzePositionFromFENAndMoves(fen, moveStr, endFEN, searchLimit);

            if (verbose)
            {
                lc0Analysis.Dump();
            }

            float scoreLC0 = (int)MathF.Round(EncodedEvalLogistic.LogisticToCentipawn(lc0Analysis.SearchEvalLogistic), 0);

            // TODO: can we somehow correctly set the staring N arugment here?
            return(new GameEngineSearchResult(lc0Analysis.BestMove, lc0Analysis.SearchEvalLogistic, scoreLC0, float.NaN,
                                              searchLimit, default, 0, (int)lc0Analysis.NumNodes, (int)lc0Analysis.UCIInfo.Depth));
Example #2
0
        /// <summary>
        /// Analyzes a position until a specified search limit is exhausted.
        /// </summary>
        /// <param name="fen">a FEN</param>
        /// <param name="nodes"></param>
        /// <returns></returns>
        public LC0VerboseMoveStats AnalyzePositionFromFENAndMoves(string startFEN, string movesStr, string endFEN,
                                                                  SearchLimit searchLimit)
        {
            Position positionEnd            = Position.FromFEN(endFEN);
            List <LC0VerboseMoveStat> moves = new List <LC0VerboseMoveStat>();

            UCISearchInfo searchInfo;

            int searchValueMilliseconds = (int)((float)searchLimit.Value * 1000.0f);

            switch (searchLimit.Type)
            {
            case SearchLimitType.NodesPerMove:
                searchInfo = Runner.EvalPositionToNodes(startFEN, movesStr, (int)searchLimit.Value);
                break;

            case SearchLimitType.SecondsPerMove:
                searchInfo = Runner.EvalPositionToMovetime(startFEN, movesStr, searchValueMilliseconds);
                break;

            case SearchLimitType.NodesForAllMoves:
                throw new Exception("NodesForAllMoves not supported for Leela Chess Zero");

            case SearchLimitType.SecondsForAllMoves:
                bool weAreWhite = positionEnd.MiscInfo.SideToMove == SideType.White;

                searchInfo = Runner.EvalPositionRemainingTime(startFEN, movesStr,
                                                              weAreWhite,
                                                              searchLimit.MaxMovesToGo,
                                                              (int)(searchLimit.Value * 1000),
                                                              (int)(searchLimit.ValueIncrement * 1000));
                break;

            default:
                throw new Exception($"Unknown SeachLimit.Type {searchLimit.Type}");
            }

            double elapsed = 0;//engine.EngineProcess.TotalProcessorTime.TotalSeconds - startTime;

            // no more, we now assume  win_percentages is requested     LeelaVerboseMoveStats ret = new LeelaVerboseMoveStats(positionEnd, searchInfo.BestMove, elapsed, searchInfo.Nodes, LZPositionEvalLogistic.CentipawnToLogistic2018(searchInfo.Score));
            float scoreLogistic     = searchInfo.ScoreLogistic;
            LC0VerboseMoveStats ret = new LC0VerboseMoveStats(positionEnd, searchInfo.BestMove, elapsed, searchInfo.Nodes, scoreLogistic, searchInfo);

            searchInfo.Infos.Reverse();
            foreach (string info in searchInfo.Infos)
            {
                if (info.Contains("P:"))
                {
                    moves.Add(new LC0VerboseMoveStat(ret, info));
                }
            }

            ret.SetMoves(moves);

            return(LastAnalyzedPositionStats = ret);
        }
Example #3
0
        /// <summary>
        /// Analyzes a specified position until a specified limit is exhausted.
        ///
        /// TODO: This method is highly redundant (and inferior to?) the next method AnalyzePositionFromFENAndMoves, delete it.
        /// </summary>
        /// <param name="fenOrFENAndMoves">a FEN</param>
        /// <param name="nodes"></param>
        /// <returns></returns>
        public UCISearchInfo AnalyzePositionFromFEN(string fenAndMovesString, SearchLimit searchLimit)
        {
            List <LC0VerboseMoveStat> moves = new List <LC0VerboseMoveStat>();

            Runner.EvalPositionPrepare();

            UCISearchInfo searchInfo;

            if (searchLimit.Type == SearchLimitType.SecondsPerMove)
            {
                searchInfo = Runner.EvalPositionToMovetime(fenAndMovesString, (int)(searchLimit.Value * 1000.0f));
            }
            else if (searchLimit.Type == SearchLimitType.NodesPerMove)
            {
                searchInfo = Runner.EvalPositionToNodes(fenAndMovesString, (int)searchLimit.Value);
            }
            else
            {
                throw new Exception("Unknown search limit " + searchLimit.Type);
            }

            double elapsed = searchInfo.EngineReportedSearchTime / 1000.0f;

            // no more, we now assume  win_percentages is requested     LeelaVerboseMoveStats ret = new LeelaVerboseMoveStats(positionEnd, searchInfo.BestMove, elapsed, searchInfo.Nodes, LZPositionEvalLogistic.CentipawnToLogistic2018(searchInfo.Score));
            float scoreConverted    = 2.0f * (((float)searchInfo.ScoreCentipawns / 10_000f) - 0.5f);
            PositionWithHistory pwh = PositionWithHistory.FromFENAndMovesUCI(fenAndMovesString);
            LC0VerboseMoveStats ret = new LC0VerboseMoveStats(pwh.FinalPosition, searchInfo.BestMove, elapsed, searchInfo.Nodes, scoreConverted, searchInfo);

            foreach (string info in searchInfo.Infos)
            {
                if (info.Contains("P:"))
                {
                    moves.Add(new LC0VerboseMoveStat(ret, info));
                }
            }

            ret.SetMoves(moves);

            // TODO: Someday perhaps make LeelaVerboseMoveStats a subclass of UCISearchInfo so this is more elegant
            UCISearchInfo uciInfo = new UCISearchInfo(null, ret.BestMove, null);

            uciInfo.Nodes = ret.NumNodes;
            uciInfo.EngineReportedSearchTime = (int)(1000.0f * ret.ElapsedTime);
            uciInfo.ExtraInfo = ret;
            uciInfo.BestMove  = ret.BestMove;

            return(uciInfo);
        }