internal static Direction DirectionTo(this Map map, MapPos position, MapPos otherPosition) { var cycle = DirectionCycleCW.CreateDefault(); foreach (var direction in cycle) { if (map.Move(position, direction) == otherPosition) { return(direction); } } return(Direction.None); }
public DirectionCycleCW(DirectionCycleCW other) : base(other) { }
/// <summary> /// Find the shortest path from start to end (using A*) considering that /// the walking time for a serf walking in any direction of the path /// should be minimized.Returns a malloc'ed array of directions and /// the size of this array in length. /// </summary> /// <param name="map"></param> /// <param name="start"></param> /// <param name="end"></param> /// <param name="buildingRoad"></param> /// <returns></returns> public static Road FindShortestPath(Map map, MapPos start, MapPos end, Road buildingRoad = null, int maxLength = int.MaxValue, bool endThere = false) { if (maxLength < 1) { return(new Road()); } var startTime = DateTime.Now; var open = new PriorityQueue <SearchNode>(new SearchNodeComparer()); var closed = new Dictionary <MapPos, SearchNode>(); var maxCost = (uint)maxLength * 511u; // 511 is the max road segment cost // Create start node var node = new SearchNode() { Position = end, GScore = 0, FScore = HeuristicCost(map, start, end) }; open.Push(node); while (open.Count != 0) { if ((DateTime.Now - startTime).TotalMilliseconds > 2 * Global.TICK_LENGTH) { return(new Road()); // tried too long } node = open.Pop(); if (node.Position == start) { // Construct solution var solution = new Road(); solution.Start(start); solution.Cost = node.GScore; while (node.Parent != null) { var direction = node.Direction; solution.Extend(map, direction.Reverse()); node = node.Parent; } return(solution); } // Put current node on closed list. closed.Add(node.Position, node); var cycle = DirectionCycleCW.CreateDefault(); foreach (var direction in cycle) { var newPosition = map.Move(node.Position, direction); var cost = ActualCost(map, node.Position, direction); if (node.GScore + cost > maxCost) { continue; // exceeded max length / max cost } // Check if neighbour is valid. if (!map.IsRoadSegmentValid(node.Position, direction, endThere && node.Position == end) || (map.GetObject(newPosition) == Map.Object.Flag && newPosition != start)) { continue; } if (buildingRoad != null && buildingRoad.HasPosition(map, newPosition) && newPosition != end && newPosition != start) { continue; } // Check if neighbour is in closed list. if (closed.ContainsKey(newPosition)) { continue; } // See if neighbour is already in open list. bool inOpen = false; foreach (var n in open) { if (n.Position == newPosition) { inOpen = true; if (n.GScore > node.GScore + cost) { n.GScore = node.GScore + cost; n.FScore = n.GScore + HeuristicCost(map, newPosition, start); n.Parent = node; n.Direction = direction; // Move element to the back and heapify open.Push(open.Pop()); } break; } } // If not found in the open set, create a new node. if (!inOpen) { var newNode = new SearchNode(); newNode.Position = newPosition; newNode.GScore = node.GScore + cost; newNode.FScore = newNode.GScore + HeuristicCost(map, newPosition, start); newNode.Parent = node; newNode.Direction = direction; open.Push(newNode); } } } return(new Road()); }
/// <summary> /// Find the shortest existing connection between two arbitrary flags. /// /// The returned collection contains the directions at each flag on /// the path. /// </summary> /// <param name="map"></param> /// <param name="start"></param> /// <param name="end"></param> /// <returns></returns> public static List <Direction> FindShortestRoad(Map map, Flag start, Flag end, out uint totalCost) { if (start == end) { totalCost = 0; return(new List <Direction>()); } totalCost = uint.MaxValue; var startTime = DateTime.Now; var open = new PriorityQueue <FlagSearchNode>(new FlagSearchNodeComparer()); var closed = new Dictionary <Flag, FlagSearchNode>(); // Create start node var node = new FlagSearchNode() { Flag = end, GScore = 0, FScore = HeuristicCost(map, start.Position, end.Position) }; open.Push(node); while (open.Count != 0) { if ((DateTime.Now - startTime).TotalMilliseconds > 2 * Global.TICK_LENGTH) { return(null); // tried too long } node = open.Pop(); if (node.Flag == start) { // Construct solution var solution = new List <Direction>(); totalCost = node.GScore; while (node.Parent != null) { solution.Add(node.Direction.Reverse()); node = node.Parent; } return(solution); } // Put current node on closed list. closed.Add(node.Flag, node); var cycle = DirectionCycleCW.CreateDefault(); foreach (var direction in cycle) { var newRoad = node.Flag.GetRoad(direction); var newFlag = node.Flag.GetOtherEndFlag(direction); // Check if neighbour is valid. if (newFlag == null || newRoad == null) { continue; } uint cost = newRoad.Cost; // Check if neighbour is in closed list. if (closed.ContainsKey(newFlag)) { continue; } // See if neighbour is already in open list. bool inOpen = false; foreach (var n in open) { if (n.Flag == newFlag) { inOpen = true; if (n.GScore > node.GScore + cost) { n.GScore = node.GScore + cost; n.FScore = n.GScore + HeuristicCost(map, newFlag, start); n.Parent = node; n.Direction = direction; // Move element to the back and heapify open.Push(open.Pop()); } break; } } // If not found in the open set, create a new node. if (!inOpen) { var newNode = new FlagSearchNode(); newNode.Flag = newFlag; newNode.GScore = node.GScore + cost; newNode.FScore = newNode.GScore + HeuristicCost(map, newFlag, start); newNode.Parent = node; newNode.Direction = direction; open.Push(newNode); } } } return(null); }
public static MapPos FindNearestSpot(Map map, MapPos start, Func <Map, MapPos, bool> searchFunc, Func <Map, MapPos, uint> costFunction = null, int maxDistance = int.MaxValue) { var startTime = DateTime.Now; var open = new PriorityQueue <SimpleSearchNode>(new SimpleSearchNodeComparer()); var visited = new List <MapPos>(); // Create start node var node = new SimpleSearchNode() { Position = start, Distance = 0, }; open.Push(node); while (open.Count != 0) { if ((DateTime.Now - startTime).TotalMilliseconds > 2 * Global.TICK_LENGTH) { return(Global.INVALID_MAPPOS); // tried too long } node = open.Pop(); if (searchFunc(map, node.Position)) { return(node.Position); } // Put current node on closed list. visited.Insert(0, node.Position); if (node.Distance >= maxDistance) { continue; } var cycle = DirectionCycleCW.CreateDefault(); foreach (var direction in cycle) { var newPosition = map.Move(node.Position, direction); var distance = node.Distance + 1; // Check if neighbour was already visited. if (visited.Contains(newPosition)) { continue; } // See if neighbour is already in open list. bool inOpen = false; foreach (var n in open) { if (n.Position == newPosition) { inOpen = true; if (n.Distance > distance) { n.Distance = distance; n.Parent = node; // Move element to the back and heapify open.Push(open.Pop()); } break; } } // If not found in the open set, create a new node. if (!inOpen) { var newNode = new SimpleSearchNode(); newNode.Position = newPosition; newNode.Distance = distance; newNode.Parent = node; newNode.Cost = (costFunction == null) ? 0u : costFunction(map, newPosition); open.Push(newNode); } } } return(Global.INVALID_MAPPOS); }