예제 #1
0
        private int AssessTimeForMiniMaxDepth(int depth, IList <SingleMove> availableMoves, Board board,
                                              int previousDepth, DiagnosticsData previousData)
        {
            var previousTime     = previousData.TimeElapsed.TotalMilliseconds;
            var prevousEvalCount = previousData.EvaluationCount + previousData.CheckCount;

            // Need a equation to model evalcount <-> time
            // movecount ^ depth = evalcount
            // evalcount correlates to time

            // Estimated evaluation speed. moves per millisecond
            // Speed = count / time
            var previousEvalSpeed = prevousEvalCount / previousTime;

            var evalCount = Math.Pow(Math.Max(availableMoves.Count, 6), depth);
            // lets say 20 ^ 5 = 3 200 000

            // Estimated total time with previous speed
            // Time = count /  speed
            var timeEstimate = evalCount / previousEvalSpeed;

            // Increase estimate proportionally depending of piece count
            // All pieces -> use as is
            // 1 piece -> 1/16 of the time
            var powerPieces = board.PieceList.Count(p => Math.Abs(p.RelativeStrength) > PieceBaseStrength.Pawn);
            var factor      = (double)powerPieces / 16;

            //var factor = 0.5 + (double)powerPieces / 32;

            return((int)(timeEstimate * factor));
        }
예제 #2
0
        public int DecideSearchDepth(DiagnosticsData previous, List <SingleMove> allMoves, Board board)
        {
            _previous = previous;
            var previousDepth = SearchDepth;

            // Previous was opening move from database
            if (previous.EvaluationCount == 0 && previous.CheckCount == 0)
            {
                Diagnostics.AddMessage($"Using search depth {SearchDepth}.");
                return(SearchDepth);
            }

            // Logic needs to be rewritten when using transposition tables, because of how much they affect speed.
            if (_useTranspositionTables)
            {
                SearchDepth = GetMaxDepthForCurrentBoardWithTranspositions(board);
                Diagnostics.AddMessage($"Using search depth {SearchDepth}.");
                return(SearchDepth);
            }

            var maxDepth = GetMaxDepthForCurrentBoard(board);

            SearchDepth = maxDepth;
            // TODO Skip until correlated to new speeds
            Diagnostics.AddMessage($"Using search depth {SearchDepth}.");
            return(maxDepth);

            var previousEstimate = 0;

            for (int i = 3; i <= maxDepth; i++)
            {
                var estimation = AssessTimeForMiniMaxDepth(i, allMoves, board, previousDepth, previous);

                // Use 50% tolerance for target time
                if (estimation > TargetTime * 1.50)
                {
                    SearchDepth = i - 1;
                    Diagnostics.AddMessage($"Using search depth {SearchDepth}. Time estimation was {previousEstimate} ms.");
                    return(SearchDepth);
                }
                else
                {
                    previousEstimate = estimation;
                }
            }

            SearchDepth = maxDepth;
            Diagnostics.AddMessage($"Failed to assess - using search depth {SearchDepth}. ");
            return(maxDepth);
            //AnalyzeGamePhase(allMoves.Count, board);
            //return SearchDepth;
        }
예제 #3
0
        public (int searchDepth, GamePhase gamePhase) DecideSearchDepth(DiagnosticsData previous, List <SingleMove> allMoves, Board board)
        {
            // Testing
            if (previous.OverrideSearchDepth != null)
            {
                return(previous.OverrideSearchDepth.Value, previous.OverrideGamePhase);
            }

            _previous = previous;

            AnalyzeGamePhase(allMoves.Count, board);
            return(SearchDepth, Phase);
        }
예제 #4
0
 /// <summary>
 /// Call in start of each player turn
 /// </summary>
 public static void StartMoveCalculations()
 {
     _currentData = new DiagnosticsData();
     _timeElapsed.Start();
 }
예제 #5
0
 /// <summary>
 /// Refresh data in beginning of each turn
 /// </summary>
 /// <param name="data"></param>
 /// <param name="turnCount"></param>
 public void Update(DiagnosticsData data, int turnCount)
 {
     _previous = data;
     TurnCount = turnCount;
 }
예제 #6
0
        public override IPlayerMove CreateMove()
        {
            if (_connectionTestOverride)
            {
                var diagnostics = Diagnostics.CollectAndClear();
                // Dummy moves for connection testing
                var move = new PlayerMoveImplementation()
                {
                    Move = new MoveImplementation()
                    {
                        StartPosition   = $"a{_connectionTestIndex--}",
                        EndPosition     = $"a{_connectionTestIndex}",
                        PromotionResult = PromotionPieceType.NoPromotion
                    },
                    Diagnostics = diagnostics.ToString()
                };

                return(move);
            }
            else
            {
                var isMaximizing = IsPlayerWhite;
                Diagnostics.StartMoveCalculations();

                // Get all available moves and do necessary filtering
                List <SingleMove> allMoves = Board.Moves(isMaximizing, true, true).ToList();
                if (allMoves.Count == 0)
                {
                    throw new ArgumentException($"No possible moves for player [isWhite={IsPlayerWhite}]. Game should have ended to draw (stalemate).");
                }

                // Reorder moves to improve alpha-beta cutoffs
                // allMoves = MoveResearch.OrderMoves(allMoves, Board, isMaximizing);

                if (MoveHistory.IsLeaningToDraw(GameHistory))
                {
                    var repetionMove = GameHistory[GameHistory.Count - 4];
                    allMoves.RemoveAll(m =>
                                       m.PrevPos.ToAlgebraic() == repetionMove.StartPosition &&
                                       m.NewPos.ToAlgebraic() == repetionMove.EndPosition);
                }
                Diagnostics.AddMessage($"Available moves found: {allMoves.Count}. ");

                Strategy.Update(PreviousData, TurnCount);
                var strategyResult = Strategy.DecideSearchDepth(PreviousData, allMoves, Board);
                SearchDepth = strategyResult.searchDepth;
                Phase       = strategyResult.gamePhase;
                var bestMove = AnalyzeBestMove(allMoves);

                if (bestMove == null)
                {
                    throw new ArgumentException($"Board didn't contain any possible move for player [isWhite={IsPlayerWhite}].");
                }

                // Update local
                Board.ExecuteMove(bestMove);
                TurnCount++;

                // Endgame checks
                // TODO should be now read from singlemove
                var castling = false;
                var check    = Board.IsCheck(IsPlayerWhite);
                //var checkMate = false;
                //if(check) checkMate = Board.IsCheckMate(IsPlayerWhite, true);
                if (bestMove.Promotion)
                {
                    Diagnostics.AddMessage($"Promotion occured at {bestMove.NewPos.ToAlgebraic()}. ");
                }

                PreviousData = Diagnostics.CollectAndClear();

                var move = new PlayerMoveImplementation()
                {
                    Move        = bestMove.ToInterfaceMove(castling, check),
                    Diagnostics = PreviousData.ToString()
                };
                GameHistory.Add(move.Move);
                return(move);
            }
        }