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
        public void ApplyReverseMove(Move move)
        {
            Owner owner = PreviousPlayer;

            if (PieceGrid.PointPieces[move.AmazonsPoint].Owner != owner)
            {
                throw new ArgumentException($"Reverse move given doesn't correspond to {owner} previous turn. Move: {move}");
            }
            if (PieceGrid.PointPieces[move.AmazonsPoint].Name != PieceName.Amazon)
            {
                throw new ArgumentException($"Reverse move given isn't on an Amazon. You cannot move a {PieceGrid.PointPieces[move.Origin].Name}. Move: {move}");
            }

            PieceGrid.ApplyReverseMove(move);

            if (owner == Owner.Player1)
            {
                Player1MoveCount--;
            }
            else
            {
                Player2MoveCount--;
            }

            _moves.Clear();
        }
Example #3
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);
        }
Example #4
0
        public Board Clone()
        {
            Board newBoard = new Board();

            newBoard.PieceGrid        = PieceGrid.Clone();
            newBoard.Player1MoveCount = Player1MoveCount;
            newBoard.Player2MoveCount = Player2MoveCount;
            return(newBoard);
        }
Example #5
0
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            PieceGrid pieceGrid = (PieceGrid)value;

            writer.WriteStartObject();
            writer.WritePropertyName("Size");
            writer.WriteValue(pieceGrid.Size);
            writer.WritePropertyName("PointPieces");
            serializer.Serialize(writer, pieceGrid.PointPieces);
            writer.WriteEndObject();
        }
Example #6
0
 /// <summary>
 /// Calculate the mobility score for all amazons on the PieceGrid
 /// </summary>
 /// <param name="pieceGrid">PieceGrid to analyze</param>
 private void CalculateAllAmazonMobility(PieceGrid pieceGrid)
 {
     AmazonMobilityScores.Clear();
     foreach (Point p in pieceGrid.Amazon1Points)
     {
         AmazonMobilityScores.Add(p, CalculateAmazonMobility(p, Owner.Player1, pieceGrid));
     }
     foreach (Point p in pieceGrid.Amazon2Points)
     {
         AmazonMobilityScores.Add(p, CalculateAmazonMobility(p, Owner.Player2, pieceGrid));
     }
 }
        /// <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 #8
0
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            Newtonsoft.Json.Linq.JObject o = Newtonsoft.Json.Linq.JObject.Load(reader);
            int       size          = o.Value <int>("Size");
            PieceGrid newPieceGrid  = new PieceGrid(size);
            var       pieceGridJson = o.Value <JObject>("PointPieces");
            Dictionary <Point, Piece> pointPiecesDictionary = new Dictionary <Point, Piece>();

            foreach (KeyValuePair <string, JToken> kvp in pieceGridJson)
            {
                Point point = Point.Get(kvp.Key);
                Piece piece = Piece.Get(kvp.Value.Value <string>());
                pointPiecesDictionary.Add(point, piece);
            }
            newPieceGrid.Initialize(pointPiecesDictionary);
            return(newPieceGrid);
        }
 /// <summary>
 /// Build <see cref="LocalAdvantage"/> objects for each open space on the PieceGrid
 /// </summary>
 /// <param name="pieceGrid">PieceGrid to analyze</param>
 /// <param name="playerToMove">Player whos turn it is</param>
 private void CalculateLocalAdvantages(PieceGrid pieceGrid, Owner playerToMove)
 {
     LocalAdvantages.Clear();
     foreach (var kvp in pieceGrid.PointPieces)
     {
         if (!(kvp.Value is Open))
         {
             continue;
         }
         double         player1QueenDistance = Player1QueenMinDistances[kvp.Key] ?? 1000d;
         double         player2QueenDistance = Player2QueenMinDistances[kvp.Key] ?? 1000d;
         LocalAdvantage advantageValue       = new LocalAdvantage
         {
             Player1QueenDistance = player1QueenDistance,
             Player2QueenDistance = player2QueenDistance,
             PlayerToMove         = playerToMove,
         };
         LocalAdvantages[kvp.Key] = advantageValue;
     }
 }
Example #10
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 #11
0
        /// <summary>
        /// Calculate the mobility score for a specific amazon point on the PieceGrid.
        /// </summary>
        /// <remarks>
        /// Mobility is based on the breathing space of each space that can be moved to by an
        /// amazon at the given point. Closer (king distance) spaces are more valuable than
        /// distant ones.
        /// </remarks>
        /// <param name="p">Point containing an amazon</param>
        /// <param name="pieceGrid">PieceGrid to analyze</param>
        /// <returns>Numeric mobility score, higher numbers = more mobile</returns>
        private double CalculateAmazonMobility(Point p, Owner owner, PieceGrid pieceGrid)
        {
            IDictionary <Point, double?> minDistancesOppositePlayer;

            if (owner == Owner.Player1)
            {
                minDistancesOppositePlayer = Player2QueenMinDistances;
            }
            else if (owner == Owner.Player2)
            {
                minDistancesOppositePlayer = Player1QueenMinDistances;
            }
            else
            {
                throw new ArgumentException($"Point {p} doesn't have an amazon for either player!");
            }

            double mobility = 0d;

            foreach (Point target in pieceGrid.GetOpenPointsOutFrom(p))
            {
                int degree = target.GetAdjacentPoints()
                             .Where(adj => pieceGrid.PointPieces.ContainsKey(adj) && !pieceGrid.PointPieces[adj].Impassible)
                             .Count();
                if (!minDistancesOppositePlayer.ContainsKey(target))
                {
                    continue;
                }
                if (owner == Owner.Player1 && !LocalAdvantages[target].Player2Reachable)
                {
                    continue;
                }
                if (owner == Owner.Player2 && !LocalAdvantages[target].Player1Reachable)
                {
                    continue;
                }
                double localMobility = Math.Pow(2, -(SpecificKingDistances[p][target])) * degree;
                mobility += localMobility;
            }
            return(mobility);
        }
Example #12
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;
        }
Example #13
0
        public IEnumerable <Move> GetAvailableMoves(Owner owner = Owner.None, bool reverse = false)
        {
            bool cached = false;

            if (owner == Owner.None)
            {
                cached = _moves.ContainsKey(Owner.Player1) && _moves.ContainsKey(Owner.Player2);
            }
            else
            {
                cached = _moves.ContainsKey(owner);
            }

            if (!cached)
            {
                IEnumerable <Point> sourceSet;
                if (owner == Owner.Player1)
                {
                    List <Move> results = new List <Move>();
                    foreach (Point p in PieceGrid.Amazon1Points)
                    {
                        if (reverse)
                        {
                            results.AddRange(PieceGrid.GetReverseMovesFromPoint(p, owner));
                        }
                        else
                        {
                            results.AddRange(PieceGrid.GetMovesFromPoint(p));
                        }
                    }
                    _moves[owner] = results;
                }
                else if (owner == Owner.Player2)
                {
                    List <Move> results = new List <Move>();
                    foreach (Point p in PieceGrid.Amazon2Points)
                    {
                        if (reverse)
                        {
                            results.AddRange(PieceGrid.GetReverseMovesFromPoint(p, owner));
                        }
                        else
                        {
                            results.AddRange(PieceGrid.GetMovesFromPoint(p));
                        }
                    }
                    _moves[owner] = results;
                }
                else
                {
                    List <Move> results1 = new List <Move>();
                    List <Move> results2 = new List <Move>();
                    sourceSet = PieceGrid.Amazon1Points.Union(PieceGrid.Amazon2Points);
                    foreach (Point p in PieceGrid.Amazon1Points)
                    {
                        if (reverse)
                        {
                            results1.AddRange(PieceGrid.GetReverseMovesFromPoint(p, Owner.Player1));
                        }
                        else
                        {
                            results1.AddRange(PieceGrid.GetMovesFromPoint(p));
                        }
                    }
                    _moves[Owner.Player1] = results1;
                    foreach (Point p in PieceGrid.Amazon2Points)
                    {
                        if (reverse)
                        {
                            results2.AddRange(PieceGrid.GetReverseMovesFromPoint(p, Owner.Player2));
                        }
                        else
                        {
                            results2.AddRange(PieceGrid.GetMovesFromPoint(p));
                        }
                    }
                    _moves[Owner.Player2] = results2;
                }
            }

            if (owner == Owner.None)
            {
                return(_moves[Owner.Player1].Union(_moves[Owner.Player2]));
            }
            else
            {
                return(_moves[owner]);
            }
        }
Example #14
0
 public Board(PieceGrid grid)
 {
     PieceGrid        = grid;
     Player1MoveCount = grid.PointPieces.Count(kvp => kvp.Value is ArrowPlayer1);
     Player2MoveCount = grid.PointPieces.Count(kvp => kvp.Value is ArrowPlayer2);
 }
Example #15
0
 public Board(int size)
 {
     PieceGrid = new PieceGrid(size, PieceHelpers.GetInitialAmazonPositions(size));
 }