Beispiel #1
0
        /// <summary>
        /// Iterative deepening sub-method.
        /// Evaluate moves at search depth 2. Reorder. Evaluate moves at search depth 3. Reorder ...
        /// </summary>
        private static SingleMove IterativeDeepeningBasic(IList <SingleMove> allMoves, int searchDepth, Board board, bool isMaximizing, int timeLimitInMs = 5000)
        {
            //
            var minimumSearchPercentForHigherDepthUse = 1 / (double)3;
            var timeUp    = false;
            int depthUsed = 0;

            var midResult             = new List <(double weight, SingleMove move)>();
            var currentIterationMoves = new List <SingleMove>(allMoves);

            (double eval, SingleMove move)previousIterationBest = new (0.0, new SingleMove((-1, -1), (-1, -1)));
            var watch = new Stopwatch();

            watch.Start();

            // Why this works for black start, but not white?
            //var alpha = -1000000.0;
            //var beta = 1000000.0;

            // Initial depth 2
            for (int i = 2; i <= searchDepth; i++)
            {
                var alpha = DefaultAlpha;
                var beta  = DefaultBeta;
                depthUsed = i;
                midResult.Clear();

                foreach (var move in currentIterationMoves)
                {
                    var newBoard   = new Board(board, move);
                    var evaluation = MiniMax.ToDepth(newBoard, i, alpha, beta, !isMaximizing);
                    midResult.Add((evaluation, move));

                    if (isMaximizing)
                    {
                        alpha = Math.Max(alpha, evaluation);
                    }
                    else
                    {
                        beta = Math.Min(beta, evaluation);
                    }

                    if (watch.ElapsedMilliseconds > timeLimitInMs)
                    {
                        timeUp = true;
                        break;
                    }
                }


                // Full search finished for depth
                midResult = MoveOrdering.SortWeightedMovesWithSort(midResult, isMaximizing).ToList();

                // Found checkmate
                //if (isMaximizing && midResult.First().weight > PieceBaseStrength.CheckMateThreshold
                //    || !isMaximizing && midResult.First().weight < -PieceBaseStrength.CheckMateThreshold)
                //{
                //    // TODO This might result in stupid movements, if opponent doesn't do the exact move AI thinks is best for it

                //    Diagnostics.AddMessage($" Iterative deepening search depth was {depthUsed}. Check mate found.");
                //    Diagnostics.AddMessage($" Move evaluation: {midResult.First().weight}.");
                //    return midResult.First().move;
                //}

                if (timeUp)
                {
                    break;
                }

                currentIterationMoves = midResult.Select(item => item.Item2).ToList();
                previousIterationBest = midResult.First();
            }

            // midResult is either partial or full. Just sort and return first.

            // If too small percent was searched for new depth, use prevous results
            // E.g. out of 8 possible moves, only 2 were searched
            if (midResult.Count / (double)allMoves.Count < minimumSearchPercentForHigherDepthUse)
            {
                var result = previousIterationBest;
                AddIterativeDeepeningResultDiagnostics(depthUsed, allMoves.Count, midResult.Count, result.eval, result.move, board);
                return(result.move);
            }

            var finalResult = MoveOrdering.SortWeightedMovesWithSort(midResult, isMaximizing).ToList();

            AddIterativeDeepeningResultDiagnostics(depthUsed, allMoves.Count, midResult.Count, finalResult.First().weight, finalResult.First().move, board);
            return(finalResult.First().move);
        }
Beispiel #2
0
        // TODO Delete. somehow unnecessary and complicated.
        public static EvaluationResult GetMoveScoreList(IList <SingleMove> moves,
                                                        int searchDepth, Board board, bool isMaximizing, bool useTranspositions)
        {
            var result = new EvaluationResult();
            var alpha  = DefaultAlpha;
            var beta   = DefaultBeta;

            if (useTranspositions)
            {
                foreach (var move in moves)
                {
                    var transposition = board.Shared.Transpositions.GetTranspositionForMove(board, move);
                    if (transposition != null && transposition.Depth >= searchDepth)
                    {
                        // Saved some time
                        // TODO extra parameters to evaluationresult if this was lower or upper bound
                        result.Add(transposition.Evaluation, move);
                    }
                    else
                    {
                        // Board evaluation at current depth
                        var newBoard = new Board(board, move);
                        var value    = MiniMax.ToDepthWithTranspositions(newBoard, searchDepth, alpha, beta,
                                                                         !isMaximizing);
                        result.Add(value, move);

                        // Add new transposition table
                        newBoard.Shared.Transpositions.Add(newBoard.BoardHash, searchDepth, value, NodeType.Exact, newBoard.Shared.GameTurnCount);

                        if (isMaximizing)
                        {
                            alpha = Math.Max(alpha, value);
                        }
                        else
                        {
                            beta = Math.Min(beta, value);
                        }
                    }
                }
            }
            else
            {
                foreach (var move in moves)
                {
                    // Board evaluation at current depth
                    var newBoard = new Board(board, move);
                    var value    = MiniMax.ToDepth(newBoard, searchDepth, alpha, beta, !isMaximizing);
                    result.Add(value, move);

                    if (isMaximizing)
                    {
                        alpha = Math.Max(alpha, value);
                    }
                    else
                    {
                        beta = Math.Min(beta, value);
                    }
                }
            }


            return(result);
        }