private void FloodFillMinDistancesQueen(Point point, PieceGrid pieceGrid, PointSquareArray <double?> result)
        {
            ISet <Point>            visited = new HashSet <Point>();
            Queue <(Point, double)> toVisit = new Queue <(Point, double)>();

            foreach (Point p in pieceGrid.GetOpenPointsOutFrom(point))
            {
                toVisit.Enqueue((p, 1));
            }

            while (toVisit.Any())
            {
                (Point, double)p = toVisit.Dequeue();
                if (visited.Contains(p.Item1))
                {
                    continue;
                }
                if (result[p.Item1].HasValue)
                {
                    result[p.Item1] = Math.Min(p.Item2, result[p.Item1].Value);
                }
                else
                {
                    result.Add(p.Item1, p.Item2);
                }
                visited.Add(p.Item1);
                foreach (Point pNext in pieceGrid.GetOpenPointsOutFrom(p.Item1)
                         .Where(adj => !visited.Contains(adj)))
                {
                    toVisit.Enqueue((pNext, p.Item2 + 1));
                }
            }
        }
Example #2
0
        /// <summary>
        /// Create a dictionary of points mapped to the minimum distance to that point for the given player and move type.
        /// As a side effect, this fills the Specific*Distances dictionary for the given <paramref name="owner"/>
        /// </summary>
        /// <param name="pieceGrid">PieceGrid to analyze</param>
        /// <param name="owner">Player whos amazons we are calculating distance for</param>
        /// <param name="queen">True for Queen distances, false for King distances</param>
        /// <returns>Dictionary of Points with their minimum distance values for the given player and move type</returns>
        private PointSquareArray <double?> BuildDistancesDictionary(PieceGrid pieceGrid, Owner owner, bool queen)
        {
            var          distancesDictionary = new PointSquareArray <double?>(pieceGrid.Size);
            ISet <Point> amazonPoints;

            if (owner == Owner.Player1)
            {
                amazonPoints = pieceGrid.Amazon1Points;
            }
            else
            {
                amazonPoints = pieceGrid.Amazon2Points;
            }
            foreach (Point amazonPoint in amazonPoints)
            {
                if (queen)
                {
                    FloodFillMinDistancesQueen(amazonPoint, pieceGrid, distancesDictionary);
                }
                else
                {
                    FloodFillMinDistancesKing(amazonPoint, pieceGrid, distancesDictionary);
                }
            }
            return(distancesDictionary);
        }
        /// <summary>
        /// Build all the internal analysis data for the given PieceGrid
        /// </summary>
        /// <param name="pieceGrid">PieceGrid to analyze</param>
        /// <param name="playerToMove">Player whos turn it is</param>
        public void BuildAnalysis(PieceGrid pieceGrid, Owner playerToMove)
        {
            if (pieceGrid.Id == LastAnalyzedPieceGridId)
            {
                return;
            }
            LastAnalyzedPieceGridId = pieceGrid.Id;

            LocalAdvantages = new PointSquareArray <LocalAdvantage>(pieceGrid.Size);

            Player1QueenMinDistances = BuildDistancesDictionary(pieceGrid, Owner.Player1);
            Player2QueenMinDistances = BuildDistancesDictionary(pieceGrid, Owner.Player2);

            CalculateLocalAdvantages(pieceGrid, playerToMove);

            T1 = LocalAdvantages.Where(a => a.Value != null).Sum(a => a.Value.DeltaQueen);
        }
Example #4
0
        private void FloodFillMinDistancesKing(Point point, PieceGrid pieceGrid, PointSquareArray <double?> result)
        {
            ISet <Point>            visited = new HashSet <Point>();
            Queue <(Point, double)> toVisit = new Queue <(Point, double)>();

            foreach (Point p in point.GetAdjacentPoints().Where(adj => !pieceGrid.IsOutOfBounds(adj) &&
                                                                !pieceGrid.PointPieces[adj].Impassible))
            {
                toVisit.Enqueue((p, 1));
            }

            while (toVisit.Any())
            {
                (Point, double)p = toVisit.Dequeue();
                if (visited.Contains(p.Item1))
                {
                    continue;
                }
                if (result[p.Item1].HasValue)
                {
                    result[p.Item1] = Math.Min(p.Item2, result[p.Item1].Value);
                }
                else
                {
                    result.Add(p.Item1, p.Item2);
                }
                if (SpecificKingDistances[point] == null)
                {
                    SpecificKingDistances.Add(point, new PointSquareArray <double>(pieceGrid.Size));
                }
                SpecificKingDistances[point].Add(p.Item1, p.Item2);
                visited.Add(p.Item1);
                foreach (Point pNext in p.Item1.GetAdjacentPoints()
                         .Where(adj => !pieceGrid.IsOutOfBounds(adj) &&
                                !pieceGrid.PointPieces[adj].Impassible &&
                                !visited.Contains(adj)))
                {
                    toVisit.Enqueue((pNext, p.Item2 + 1));
                }
            }
        }
Example #5
0
        /// <summary>
        /// Build all the internal analysis data for the given PieceGrid
        /// </summary>
        /// <param name="pieceGrid">PieceGrid to analyze</param>
        /// <param name="playerToMove">Player whos turn it is</param>
        public void BuildAnalysis(PieceGrid pieceGrid, Owner playerToMove)
        {
            if (pieceGrid.Id == LastAnalyzedPieceGridId)
            {
                return;
            }
            LastAnalyzedPieceGridId = pieceGrid.Id;

            LocalAdvantages        = new PointSquareArray <LocalAdvantage>(pieceGrid.Size);
            AmazonMobilityScores   = new PointSquareArray <double>(pieceGrid.Size);
            SpecificQueenDistances = new PointSquareArray <PointSquareArray <double> >(pieceGrid.Size);
            SpecificKingDistances  = new PointSquareArray <PointSquareArray <double> >(pieceGrid.Size);

            SpecificQueenDistances.Clear();
            SpecificKingDistances.Clear();

            Player1QueenMinDistances = BuildDistancesDictionary(pieceGrid, Owner.Player1, true);
            Player1KingMinDistances  = BuildDistancesDictionary(pieceGrid, Owner.Player1, false);
            Player2QueenMinDistances = BuildDistancesDictionary(pieceGrid, Owner.Player2, true);
            Player2KingMinDistances  = BuildDistancesDictionary(pieceGrid, Owner.Player2, false);

            CalculateLocalAdvantages(pieceGrid, playerToMove);
            CalculateAllAmazonMobility(pieceGrid);

            W = LocalAdvantages.Where(a => a.Value != null && a.Value.Player1Reachable && a.Value.Player2Reachable)
                .Sum(a => Math.Pow(2, -(Math.Abs(a.Value.Player1QueenDistance - a.Value.Player2QueenDistance))));
            C1 = 2 * LocalAdvantages.Where(a => a.Value != null).Sum(a => Math.Pow(2, -(a.Value.Player1QueenDistance)) - Math.Pow(2, -(a.Value.Player2QueenDistance)));
            C2 = LocalAdvantages.Where(a => a.Value != null).Sum(a => Math.Min(1, Math.Max(-1, (a.Value.Player2KingDistance - a.Value.Player1KingDistance) / 6d)));
            T1 = LocalAdvantages.Where(a => a.Value != null).Sum(a => a.Value.DeltaQueen);
            T2 = LocalAdvantages.Where(a => a.Value != null).Sum(a => a.Value.DeltaKing);

            T = (F1(W) * T1) + (F2(W) * C1) + (F3(W) * C2) + (F4(W) * T2);

            double player1MobilitySum = AmazonMobilityScores.Where(s => pieceGrid.Amazon1Points.Contains(s.Key))
                                        .Sum(s => IndividualWeightForM(W, s.Value));
            double player2MobilitySum = AmazonMobilityScores.Where(s => pieceGrid.Amazon2Points.Contains(s.Key))
                                        .Sum(s => IndividualWeightForM(W, s.Value));

            M = player2MobilitySum - player1MobilitySum;
        }