/* * public functions */ /// <summary> /// The core function; calls all valid auxiliary functions and returns the path (advanced features can be toggled) /// Includes a boolean toggle for use of advanced pathfinding functions /// </summary> /// <param name="map">The Map</param> /// <param name="start">The starting Cell</param> /// <param name="end">The ending Cell</param> /// <param name="advanced"> A boolean toggle for advanced functions</param> /// <returns>The path as a list of waypoints</returns> public static List<CellComponent> between(Map map, CellComponent start, CellComponent end, bool advanced) { // begin timing the operation DateTime startTime = DateTime.Now; // convert the given Cell-based data to Node-based data NodeMap nodeMap = new NodeMap(map); Node nodeStart = nodeMap.getNode(start.X, start.Y); Node nodeEnd = nodeMap.getNode(end.X, end.Y); // perform advanced pre-calculation tasks if (advanced) { // if the end Node is invalid, replace it with the nearest valid Node if (!nodeEnd.isValid) { nodeEnd = Advanced.nearestValidEnd(nodeMap, nodeStart, nodeEnd); } } // find the path List<Node> nodePath = Basic.findPath(nodeMap, nodeStart, nodeEnd); // convert the path from List<Node> format back to List<Cell> format List<CellComponent> path = new List<CellComponent>(nodePath.Count); for (int i = 0; i < nodePath.Count; i++) path.Add(map.GetCellAt(nodePath[i].X, nodePath[i].Y)); // grab and print path data float dist = (float)(nodePath[nodePath.Count - 1].Gscore); span = DateTime.Now - startTime; //printPath(path, dist); return path; }
/* * public functions */ /// <summary> /// The core function; calls all valid auxiliary functions and returns the path (advanced features can be toggled) /// Includes a boolean toggle for use of advanced pathfinding functions /// </summary> /// <param name="map">The Map</param> /// <param name="start">The starting Cell</param> /// <param name="end">The ending Cell</param> /// <param name="advanced"> A boolean toggle for advanced functions</param> /// <returns>The path as a list of waypoints</returns> public static List <Cell> between(Map map, Cell start, Cell end, bool advanced) { // begin timing the operation startTime = DateTime.Now; intendedEnd = end; // convert the given Cell-based data to Node-based data NodeMap nodeMap = new NodeMap(map); Node nodeStart = nodeMap.getNode(start.Xcoord, start.Ycoord); Node nodeEnd = nodeMap.getNode(end.Xcoord, end.Ycoord); // perform advanced pre-calculation tasks if (advanced) { // if the end Node is invalid, replace it with the nearest valid Node if (!nodeEnd.isValid) { DateTime tempStartTime = DateTime.Now; nodeEnd = Advanced.nearestValidEnd(nodeMap, nodeStart, nodeEnd); TimeSpan tempSpan = DateTime.Now - tempStartTime; Console.WriteLine("-> Path end changed from ({0}, {1}) to ({2}, {3}) in {4}", intendedEnd.Xcoord, intendedEnd.Ycoord, nodeEnd.Xcoord, nodeEnd.Ycoord, tempSpan); } } // find the path List <Node> nodePath = Basic.findPath(nodeMap, nodeStart, nodeEnd); // perform advanced post-calculation tasks if (advanced) { } // convert the path from List<Node> format back to List<Cell> format List <Cell> path = new List <Cell>(nodePath.Count); for (int i = 0; i < nodePath.Count; i++) { path.Add(map.getCell(nodePath[i].Xcoord, nodePath[i].Ycoord)); } // grab and print path data float dist = (float)(nodePath[nodePath.Count - 1].Gscore); span = DateTime.Now - startTime; printPath(path, dist); return(path); }
/* * public functions */ /// <summary> /// The core function; calls all valid auxiliary functions and returns the path (advanced features can be toggled) /// Includes a boolean toggle for use of advanced pathfinding functions /// </summary> /// <param name="map">The Map</param> /// <param name="start">The starting Cell</param> /// <param name="end">The ending Cell</param> /// <param name="advanced"> A boolean toggle for advanced functions</param> /// <returns>The path as a list of waypoints</returns> public static List<Cell> between(Map map, Cell start, Cell end, bool advanced) { // begin timing the operation startTime = DateTime.Now; intendedEnd = end; // convert the given Cell-based data to Node-based data NodeMap nodeMap = new NodeMap(map); Node nodeStart = nodeMap.getNode(start.Xcoord, start.Ycoord); Node nodeEnd = nodeMap.getNode(end.Xcoord, end.Ycoord); // perform advanced pre-calculation tasks if (advanced) { // if the end Node is invalid, replace it with the nearest valid Node if (!nodeEnd.isValid) { DateTime tempStartTime = DateTime.Now; nodeEnd = Advanced.nearestValidEnd(nodeMap, nodeStart, nodeEnd); TimeSpan tempSpan = DateTime.Now - tempStartTime; Console.WriteLine("-> Path end changed from ({0}, {1}) to ({2}, {3}) in {4}", intendedEnd.Xcoord, intendedEnd.Ycoord, nodeEnd.Xcoord, nodeEnd.Ycoord, tempSpan); } } // find the path List<Node> nodePath = Basic.findPath(nodeMap, nodeStart, nodeEnd); // perform advanced post-calculation tasks if (advanced) { } // convert the path from List<Node> format back to List<Cell> format List<Cell> path = new List<Cell>(nodePath.Count); for (int i = 0; i < nodePath.Count; i++) path.Add(map.getCell(nodePath[i].Xcoord, nodePath[i].Ycoord)); // grab and print path data float dist = (float)(nodePath[nodePath.Count - 1].Gscore); span = DateTime.Now - startTime; printPath(path, dist); return path; }
/* * helper functions */ /// <summary> /// Enqueues all valid Nodes in a ring around a center Node, offset from the center by [offset] Nodes. /// For example, an offset of 2 searches a 5x5 ring (x+-2, y+-2) around the center Node. /// Since modifying the Node's Fscores is necessary for enqueueing, each enqueued node's Fscore must be reset after use. /// </summary> /// <param name="map">The NodeMap to search over</param> /// <param name="center">The center Node to search around</param> /// <param name="offset">The ring "radius"</param> /// <returns>A PQueue containing all valid Nodes found in the ring</returns> private static PQueue getRing(NodeMap map, Node center, int offset) { PQueue ring = new PQueue(); int x = center.X; int y = center.Y; // grab left and right columns for (int i = Math.Max(y - offset, 0); i <= y + offset; i++) { Node Xmin = map.getNode(x - offset, i); Node Xmax = map.getNode(x + offset, i); if (Xmin != null && Xmin.isValid) { Xmin.Fscore = map.pathDistance(Xmin, center); ring.enqueue(Xmin); } if (Xmax != null && Xmax.isValid) { Xmax.Fscore = map.pathDistance(Xmax, center); ring.enqueue(Xmax); } } // grab remainder of top and bottom rows for (int i = x - offset + 1; i < x + offset; i++) { Node Ymin = map.getNode(i, Math.Max(0, y - offset)); Node Ymax = map.getNode(i, Math.Min(map.width - 1, y + offset)); if (Ymin != null && Ymin.isValid) { Ymin.Fscore = map.pathDistance(Ymin, center); ring.enqueue(Ymin); } if (Ymax != null && Ymax.isValid) { Ymax.Fscore = map.pathDistance(Ymax, center); ring.enqueue(Ymax); } } return(ring); }
/* * helper functions */ /// <summary> /// Enqueues all valid Nodes in a ring around a center Node, offset from the center by [offset] Nodes. /// For example, an offset of 2 searches a 5x5 ring (x+-2, y+-2) around the center Node. /// Since modifying the Node's Fscores is necessary for enqueueing, each enqueued node's Fscore must be reset after use. /// </summary> /// <param name="map">The NodeMap to search over</param> /// <param name="center">The center Node to search around</param> /// <param name="offset">The ring "radius"</param> /// <returns>A PQueue containing all valid Nodes found in the ring</returns> private static PQueue getRing(NodeMap map, Node center, int offset) { PQueue ring = new PQueue(); int x = center.Xcoord; int y = center.Ycoord; // grab left and right columns for (int i = y - offset; i <= y + offset; i++) { Node Xmin = map.getNode(x - offset, i); Node Xmax = map.getNode(x + offset, i); if (Xmin.isValid) { Xmin.Fscore = map.pathDistance(Xmin, center); ring.enqueue(Xmin); } if (Xmax.isValid) { Xmax.Fscore = map.pathDistance(Xmax, center); ring.enqueue(Xmax); } } // grab remainder of top and bottom rows for (int i = x - offset + 1; i < x + offset; i++) { Node Ymin = map.getNode(i, y - offset); Node Ymax = map.getNode(i, y + offset); if (Ymin.isValid) { Ymin.Fscore = map.pathDistance(Ymin, center); ring.enqueue(Ymin); } if (Ymax.isValid) { Ymax.Fscore = map.pathDistance(Ymax, center); ring.enqueue(Ymax); } } return ring; }
/* * public functions */ /// <summary> /// The core function; calls all valid auxiliary functions and returns the path (advanced features can be toggled) /// Includes a boolean toggle for use of advanced pathfinding functions /// </summary> /// <param name="map">The Map</param> /// <param name="start">The starting Cell</param> /// <param name="end">The ending Cell</param> /// <param name="advanced"> A boolean toggle for advanced functions</param> /// <returns>The path as a list of waypoints</returns> public static List <CellComponent> between(Map map, CellComponent start, CellComponent end, bool advanced) { // begin timing the operation DateTime startTime = DateTime.Now; // convert the given Cell-based data to Node-based data NodeMap nodeMap = new NodeMap(map); Node nodeStart = nodeMap.getNode(start.X, start.Y); Node nodeEnd = nodeMap.getNode(end.X, end.Y); // perform advanced pre-calculation tasks if (advanced) { // if the end Node is invalid, replace it with the nearest valid Node if (!nodeEnd.isValid) { nodeEnd = Advanced.nearestValidEnd(nodeMap, nodeStart, nodeEnd); } } // find the path List <Node> nodePath = Basic.findPath(nodeMap, nodeStart, nodeEnd); // convert the path from List<Node> format back to List<Cell> format List <CellComponent> path = new List <CellComponent>(nodePath.Count); for (int i = 0; i < nodePath.Count; i++) { path.Add(map.GetCellAt(nodePath[i].X, nodePath[i].Y)); } // grab and print path data float dist = (float)(nodePath[nodePath.Count - 1].Gscore); span = DateTime.Now - startTime; //printPath(path, dist); return(path); }
/// <summary> /// Iterates over the full Map and returns a closed List of Nodes /// </summary> /// <param name="map">The NodeMap to search</param> /// <returns>A List of all closed Nodes</returns> private static List <Node> createClosed(NodeMap map) { List <Node> closed = new List <Node>(); for (int j = 0; j < map.height; j++) { for (int i = 0; i < map.width; i++) { Node temp = map.getNode(i, j); if (temp.isClosed) { closed.Add(temp); } } } return(closed); }
/* * helper functions */ /// <summary> /// Puts all valid Nodes adjacent to the given Node in a PQueue and returns it /// </summary> /// <param name="map">The Map</param> /// <param name="closed">The closed list</param> /// <param name="currentNode">The current (center) Node</param> /// <returns>A PQueue of all traversable adjacent Nodes</returns> private static PQueue getAdjacentNodes(NodeMap map, PQueue open, List<Node> closed, Node currentNode) { int x = currentNode.Xcoord; int y = currentNode.Ycoord; List<Node> immediate = new List<Node>(); List<Node> diagonal = new List<Node>(); PQueue adjacentNodes = new PQueue(); // grab all adjacent Nodes (or null values) and store them here Node[,] temp = map.getNodes(x - 1, y - 1, 3, 3); // iterate over all adjacent Nodes; add the ones that are open and in bounds to the appropriate List<Node> for (int j = 0; j < 3; j++) { for (int i = 0; i < 3; i++) { if (temp[i, j] != null && !closed.Contains(temp[i, j])) { // if the Node is horizontally or vertically adjacent, // add the Node to the list of immediately adjacent Nodes if (Math.Abs(2 - i - j) == 1) immediate.Add(temp[i, j]); // otherwise, if the Node is valid, add it to the list of diagonally adjacent Nodes else if (temp[i, j].isValid) diagonal.Add(temp[i, j]); } } } // iterate over all immediately adjacent Nodes. If they are valid, enqueue them; // otherwise, remove the neighboring diagonally adjacent Nodes from the diagonal List for (int i = 0; i < immediate.Count(); i++) { if (!immediate[i].isValid) { Node one, two = null; if (immediate[i].Xcoord == x) // the Node is vertically adjacent { one = map.getNode(x + 1, immediate[i].Ycoord); two = map.getNode(x - 1, immediate[i].Ycoord); } else // the Node is horizontally adjacent { one = map.getNode(immediate[i].Xcoord, y - 1); two = map.getNode(immediate[i].Xcoord, y + 1); } if (one != null) diagonal.Remove(one); if (two != null) diagonal.Remove(two); } else { adjacentNodes.enqueue(immediate[i]); } } // enqueue all remaining diagonally adjacent Nodes for (int i = 0; i < diagonal.Count(); i++) adjacentNodes.enqueue(diagonal[i]); // return the finished PQueue return adjacentNodes; }
/* * helper functions */ /// <summary> /// Puts all valid Nodes adjacent to the given Node in a PQueue and returns it /// </summary> /// <param name="map">The Map</param> /// <param name="closed">The closed list</param> /// <param name="currentNode">The current (center) Node</param> /// <returns>A PQueue of all traversable adjacent Nodes</returns> private static PQueue getAdjacentNodes(NodeMap map, PQueue open, List <Node> closed, Node currentNode) { int x = currentNode.Xcoord; int y = currentNode.Ycoord; List <Node> immediate = new List <Node>(); List <Node> diagonal = new List <Node>(); PQueue adjacentNodes = new PQueue(); // grab all adjacent Nodes (or null values) and store them here Node[,] temp = map.getNodes(x - 1, y - 1, 3, 3); // iterate over all adjacent Nodes; add the ones that are open and in bounds to the appropriate List<Node> for (int j = 0; j < 3; j++) { for (int i = 0; i < 3; i++) { if (temp[i, j] != null && !closed.Contains(temp[i, j])) { // if the Node is horizontally or vertically adjacent, // add the Node to the list of immediately adjacent Nodes if (Math.Abs(2 - i - j) == 1) { immediate.Add(temp[i, j]); } // otherwise, if the Node is valid, add it to the list of diagonally adjacent Nodes else if (temp[i, j].isValid) { diagonal.Add(temp[i, j]); } } } } // iterate over all immediately adjacent Nodes. If they are valid, enqueue them; // otherwise, remove the neighboring diagonally adjacent Nodes from the diagonal List for (int i = 0; i < immediate.Count(); i++) { if (!immediate[i].isValid) { Node one, two = null; if (immediate[i].Xcoord == x) // the Node is vertically adjacent { one = map.getNode(x + 1, immediate[i].Ycoord); two = map.getNode(x - 1, immediate[i].Ycoord); } else // the Node is horizontally adjacent { one = map.getNode(immediate[i].Xcoord, y - 1); two = map.getNode(immediate[i].Xcoord, y + 1); } if (one != null) { diagonal.Remove(one); } if (two != null) { diagonal.Remove(two); } } else { adjacentNodes.enqueue(immediate[i]); } } // enqueue all remaining diagonally adjacent Nodes for (int i = 0; i < diagonal.Count(); i++) { adjacentNodes.enqueue(diagonal[i]); } // return the finished PQueue return(adjacentNodes); }
/// <summary> /// Iterates over the full Map and returns a closed List of Nodes /// </summary> /// <param name="map">The NodeMap to search</param> /// <returns>A List of all closed Nodes</returns> private static List<Node> createClosed(NodeMap map) { List<Node> closed = new List<Node>(); for (int j = 0; j < map.height; j++) { for (int i = 0; i < map.width; i++) { Node temp = map.getNode(i, j); if (temp.isClosed) closed.Add(temp); } } return closed; }