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)); } } }
/// <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); }