/// <summary> /// Create a new instance of PathFinder /// </summary> /// <param name="searchParameters"></param> public PathFinder(SearchParameters searchParameters) { this.searchParameters = searchParameters; InitializeNodes(searchParameters.Map); this.startNode = this.nodes[searchParameters.StartLocation.X, searchParameters.StartLocation.Y]; this.startNode.State = NodeState.Open; this.endNode = this.nodes[searchParameters.EndLocation.X, searchParameters.EndLocation.Y]; }
/// <summary> /// Returns any nodes that are adjacent to <paramref name="fromNode"/> and may be considered to form the next step in the path /// </summary> /// <param name="fromNode">The node from which to return the next possible nodes in the path</param> /// <returns>A list of next possible nodes in the path</returns> private List<Node> GetAdjacentWalkableNodes(Node fromNode) { List<Node> walkableNodes = new List<Node>(); IEnumerable<Point> nextLocations = GetAdjacentLocations(fromNode.Location); foreach (var location in nextLocations) { int x = location.X; int y = location.Y; // Stay within the grid's boundaries if (x < 0 || x >= this.width || y < 0 || y >= this.height) continue; Node node = this.nodes[x, y]; // Ignore non-walkable nodes if (!node.IsWalkable) continue; // Ignore already-closed nodes if (node.State == NodeState.Closed) continue; // Already-open nodes are only added to the list if their G-value is lower going via this route. if (node.State == NodeState.Open) { float traversalCost = Node.GetTraversalCost(node.Location, node.ParentNode.Location); float gTemp = fromNode.G + traversalCost; if (gTemp < node.G) { node.ParentNode = fromNode; walkableNodes.Add(node); } } else { // If it's untested, set the parent and flag it as 'Open' for consideration node.ParentNode = fromNode; node.State = NodeState.Open; walkableNodes.Add(node); } } return walkableNodes; }
/// <summary> /// Attempts to find a path to the destination node using <paramref name="currentNode"/> as the starting location /// </summary> /// <param name="currentNode">The node from which to find a path</param> /// <returns>True if a path to the destination has been found, otherwise false</returns> private bool Search(Node currentNode) { // Set the current node to Closed since it cannot be traversed more than once currentNode.State = NodeState.Closed; List<Node> nextNodes = GetAdjacentWalkableNodes(currentNode); // Sort by F-value so that the shortest possible routes are considered first nextNodes.Sort((node1, node2) => node1.F.CompareTo(node2.F)); foreach (var nextNode in nextNodes) { // Check whether the end node has been reached if (nextNode.Location == this.endNode.Location) { return true; } else { // If not, check the next set of nodes if (Search(nextNode)) // Note: Recurses back into Search(Node) return true; } } // The method returns false if this path leads to be a dead end return false; }