**Toward More Realistic Pathfinding** Authored by: Marco Pinter Presentation Date: 11/17/03 Presented by: Ricky Uy

**Background – A*** • Commonly used in video games • Finds a path from start to goal, if one exists • Finds optimal path given that the heuristic is an underestimate, i.e. always <= actual cheapest path cost from a node X to the goal

**Background – A*** Algorithm • Repeatedly examines the most promising unexplored location it has seen • If an examined location is the goal, algorithm is complete; else, note all neighboring locations for further exploration

**Background – A*** Algorithm • Uses “Open” and “Closed” states for unexamined and examined nodes • “Open” is a priority queue • Priority determined by whatever the path is trying to minimize, e.g. distance traveled • Total cost = actual cost from start to node X + heuristic cost from X to goal

**Background – A*** Algorithm • Initially only the start location is in Open, with start.parent = null • Pop node off Open and examine it • Place node into Closed list • All unblocked neighbors updated and placed into Open queue • If Open list becomes empty before goal is found, there is no path from the start to the goal location

**Background – A*** Demo – taken from an article by Bryan Stout in Game Programming Gems

**Background – A*** Limitations • Worst case time: when there is no path from start to goal • Produces zigzag effect • Does not produce smooth turns • Does not check for “illegal moves” or for abrupt turning when a unit has a particular turning radius • Memory limitations: huge number of nodes in Open and Closed lists

**Background – A*** Optimizations • Hierarchical pathfinding, albeit subject to path failure by choosing impossible locations as midpoints • Use a basic non-priority list with previous and next pointers instead of a priority queue • Loses on search time: O(n) compared to O(log n), but wins on insertions and deletions

**Removing the Zigzag Effect** Can just associate a cost with each turn, but that does not solve the problem entirely. A better smoothing process is to remove as many waypoints as possible.

**Removing the Zigzag Effect** checkPoint = starting point of pathcurrentPoint = next point in pathwhile (currentPoint->next != NULL) if Walkable(checkPoint, currentPoint->next) // Make a straight path between those points: temp = currentPoint currentPoint = currentPoint->next delete temp from the path else checkPoint = currentPoint currentPoint = currentPoint->next

**Removing the Zigzag Effect** Checks path from waypoint to waypoint. If the path traveled intersects a blocked location, the waypoint is not removed. Otherwise, remove the waypoint. Leaves “impossible” sections as is.

**Adding Realistic Turns** Want to be aware of a unit’s turning radius and choose shortest route to destination, in this case the right turn will lead to the shortest route.

**Adding Realistic Turns** • Calculate the length of the arc plus the line segment for both left and right turns. Shortest path is the one to use.

**Adding Legal Turns** Several Postprocess Solutions (cheats) • Ignore blocked tiles – obviously bad • Path recalculations – associate a byte with each tile, each bit denoting the surrounding tiles as legal or illegal; may invalidate legal paths from other directions = bad • Decrease turning radius until it is legal – bad for units with constant turning radius (e.g. truck), good for units such as people • Backing up – make a three point turn – good for units such as trucks, weird for people

**Adding Legal Turns** Problems • Methods shown previously are basically cheats, except for the second one (path recalculations), which can fail to find valid paths • How can we make sure that paths taken are both legal and do not violate the turning radius?

**Directional A*** Sometimes the only legal path that does not violate the turning radius constraints is completely different from the path that the standard A* algorithm produces. To get around this, Pinter proposes a modification known as Directional A*.

**Directional A*** First things first • Add an orientation associated with each node, where the orientation can be any one of the eight compass directions • Each node now represented by three dimensions: [x, y, orientation]

**Directional A*** • Check the path from a parent to a child node, not just whether or not the child is a blocked tile • Consider the orientation at parent and child nodes as well as the turning radius and size of the unit to see if path hits any blocked tiles • Result: a valid path given the size and turning radius of the unit

**Directional A*** Directional A* does not go directly from a to c because it sees that an abrupt right turn would cause the unit to hit blocked tiles. Thus, waypoint b is found as the shortest legal path.

**Directional A*** Problem: adding an end orientation • Four common paths

**Directional A*** • Can easily compute the four common paths and choose the shortest one • Can add smoothing algorithm presented earlier, with the modification of sampling points along a valid curve between two points rather than just a straight line between two points

**Expanding the Search** • So far, have been using a Directional-8 search • Some paths will fail under this method • Try searching more than one tile away • Directional-24: search two tiles away, rarely fails to find a valid path • Directional-48: search three tiles away, almost never fails to find a valid path

**Expanding the Search** Example of a case where Directional-8 fails, but Directional-24 finds a valid path

**Modifying the Heuristic** • Standard A* measures straight line distance from start to goal • Modify so that it measures the shortest curve and line segment as calculated earlier, considering turn radius • If units can go in reverse, consider adding a cost penalty to encourage units to move in reverse only when necessary

**Directional A* Limitations** • Very slow, constantly uses tables as a means to optimize it (directional table, heuristic table, hit-check table, etc) • Directional-48 may still possibly (though rarely) fail • The four common paths from origin to destination are not the only ones; there is an infinite number of paths

**Better Smoothing Algorithm** • Previous method of removing waypoints has some faults

**Better Smoothing Algorithm** • Perform standard A* algorithm • Then, perform Directional-48 algorithm that favors the path found by the standard A* algorithm by modifying the cost heuristic • Finally, perform the smoothing algorithm described earlier (removing waypoints) • This will find the blue line path on the previous slide

**Limitations on Better Smoothing Algorithm** • Fails to find valid paths that a full Directional-48 search would find

**Limitations on Better Smoothing Algorithm** • Does not find blue line path because of its bias towards the original path • Ends up not finding any path at all • To help performance in this worst case scenario, return failure if six or more points have been searched backwards

**More Optimizations** • Timeslice the search • Only use Directional-24 and -48 if a Directional-8 fails • Divide map into regions and pre-compute whether a tile in one region can reach a tile in another • Use two matrices to calculate intermediate search results, one for slow, timesliced searches and the other for faster searches

**One Possible Hybrid Solution** • Perform standard A* search, checking only four tiles at every node • Perform Smoothing-48 pass; if successful, skip to last step, otherwise note farthest node hit • Work backwards from goal using Smoothing-48 pass and note farthest node hit • Take the two farthest point nodes and make sure they are less than, but close to, 12 tiles apart. If more than 12 tiles, return failure. • Perform Directional-8 between the two nodes and connect the three segments into one path • Perform the initial simple smoothing algorithm (the one that removes unnecessary waypoints)

**One Possible Hybrid Solution**

**Speed and Other Considerations** • For sand, add a cost to the heuristic • For speed, add a cost for turns made

**Summary** • Directional A* finds legal paths and realistic turns • Directional A* is slow • Examples only take into account a 2D space partitioned into a grid, but can be extended to support various partitioning methods in 2D or 3D • Suggest standard A* for most units and Directional A* for various large units

**Questions?**