private Turn CollectHealth(LevelView levelView) { if (levelView.Player.Health > HighHealthLimit || !levelView.HealthPacks.Any()) { automaton.PopAction(); return(automaton.CurrentAction.Invoke(levelView)); } var influenceMap = InfluenceMap.CreateForm(levelView); var pathToNearestHealth = PathFinder.FindShortestPathWithInfluenceMap(levelView, influenceMap, levelView.Player.Location, loc => levelView.GetHealthPackAt(loc).HasValue); return(PathFinder.GetFirstTurn(pathToNearestHealth)); }
public static IEnumerable <Location> Dijkstra(LevelView levelView, Func <Location, bool> isTarget) { var costs = new InfluenceMap(levelView); var current = levelView.Player.Location; var dist = new Dictionary <Location, int> { [current] = 0 }; var prev = new Dictionary <Location, Location>(); var notOpened = new HashSet <Location> { current }; for (var y = 0; y < levelView.Field.Height; y++) { for (var x = 0; x < levelView.Field.Width; x++) { var location = new Location(x, y); var cellType = levelView.Field[location]; if ((cellType == CellType.Empty || cellType == CellType.PlayerStart) && (location != current) && !levelView.GetItemAt(location).HasValue) { notOpened.Add(location); dist[location] = int.MaxValue; } } } while (notOpened.Any()) { var toOpen = default(Location); var bestPrice = int.MaxValue; foreach (var node in notOpened) { if (dist.ContainsKey(node) && (dist[node] < bestPrice)) { bestPrice = dist[node]; toOpen = node; } } notOpened.Remove(toOpen); if (isTarget(toOpen)) { return(RevertPath(levelView, toOpen, prev)); } foreach (var stepOffset in Offset.StepOffsets) { var neighbour = toOpen + stepOffset; if (!notOpened.Contains(neighbour)) { continue; } var alt = dist[toOpen] + costs[neighbour]; if (alt < dist[neighbour]) { dist[neighbour] = alt; prev[neighbour] = toOpen; } } } return(RevertPath(levelView, current, prev)); }
public static List <Location> FindShortestPathWithInfluenceMap(LevelView levelView, InfluenceMap influenceMap, Location from, Func <Location, bool> isTarget) { var notOpened = new SortedSet <LocationWithPriority>(); var distances = new Dictionary <Location, int>(); var previous = new Dictionary <Location, Location> { [from] = default(Location) }; foreach (var location in levelView.Field.GetAllLocations()) { if ((IsPassable(location, levelView) || isTarget(location)) && location != from) { distances[location] = int.MaxValue; notOpened.Add(new LocationWithPriority(location, int.MaxValue)); } } distances[from] = 0; notOpened.Add(new LocationWithPriority(from, 0)); while (notOpened.Any()) { var toOpen = notOpened.Min; notOpened.Remove(toOpen); if (toOpen.Priority == int.MaxValue) { return(null); } if (isTarget(toOpen.Location)) { return(CreatePath(from, toOpen.Location, previous)); } foreach (var adjacentLocation in GetAdjacentLocations(toOpen.Location, levelView).Where(l => IsPassable(l, levelView) || isTarget(l))) { var currentDistance = toOpen.Priority + influenceMap[adjacentLocation]; if (!previous.ContainsKey(adjacentLocation) || currentDistance < distances[adjacentLocation]) { notOpened.Remove(new LocationWithPriority(adjacentLocation, distances[adjacentLocation])); distances[adjacentLocation] = currentDistance; notOpened.Add(new LocationWithPriority(adjacentLocation, currentDistance)); previous[adjacentLocation] = toOpen.Location; } } } return(null); }