Pathfinding

Pathfinding
Advaith Siddharthan
Context

What is Intelligence?
–
Rational?
•
•
•
–
Search
Optimisation
Reasoning
Impulsive?
•
•
•
Quicker response
Less predictable
Personality/Emotions: Angry/Bored/Curious
Overview
The first half of this course is about classical AI

–
Rational behaviour based on planning, search
and optimisation
You've encountered decision making

Next 2 weeks on Pathfinding

Afterwards, Planning

Introduction to Pathfinding

Perhaps the most ubiquitous task in AI games
Introduction to Pathfinding

Many Algorithms exist
−
Different levels of complexity
−
Different quality of solutions
Pathfinding: Representations

Grid representation (e.g., dungeon worlds)
−
Can move to any of 8 neighbours at each step
−
Which one?
Pathfinding: Representations

Graph Representations (e.g., streetmaps, etc)
–
More general: you can assign costs to edges
–
Best path = Path with lowest cost
–
If all edges have same cost, equivalent to grid
Pathfinding Algorithms



Bug Model
−
Naive, used in many early games
Breadth First Search and Dijkstra's Algorithm
− expensive, but finds the shortest path
Best First Search
−

Quick, but needn't find shortest path
A* Search
−
−
Finds shortest path reasonably fast
Most games use some variation of A*
How this course works (in theory)



Lectures: Introduce and give context to algorithms
Practicals:
−
Implement algorithms in dungeon game
−
Make sure you do this or you risk failing
−
One assessment will likely be a competition of
NPCs coded by you
Tutorials:
−
I'll give some problems on the website.
−
Email solutions to me before the tutorial.
−
We will discuss solutions (anonymously)
How this course works in practice
•
Lectures and tutorials are interchangable
•
Interaction is encouraged in BOTH
Pathfinding Algorithm Properties

Completeness
−

Optimality
−

Will it find a path if one exists
Will it find the shortest path
Efficiency
−
Time: How many nodes need to be searched?
−
Space: How many nodes need to be stored in
memory?
Pathfinding algorithms

Bug models

Breadth First

Dijkestra's Algorithm

A* Algorithm
–
Basically, Dijkestra with Heuristics
–
A* is the objective. You will need to
understand and program this algorithm.
–
Most games use some version of A*
Bug Models
Move towards goal and circumnavigate obstacles:

BugPath(start, goal)
1. current = start
2.
while (current != goal)
(a) next = next square on straight line to goal
(b) if (next is in obstacle)
current = circumnavigate_obstacle (current);
else current = next
3.
return;
Bug Model 1

Circumnavigate_obstacle(current)
1.
2.
walk all around obstacle, keeping track of
distance to goal
return the closest point to goal
Bug Model 2

Circumnavigate_obstacle (current)
1. walk around the obstacle,
until you hit the original line
from source to goal
2. return the point on this line
Which is better?
Which is better?
Bug models




Direction towards goal is known
Obstacles are avoided when encountered
Unlikely to give shortest path
But guaranteed to find some path (if
implemented properly!)
Breadth-first Search
Look at all possible moves at successive depths:

BFS(start, goal)
1. Initialise: queue={start}; start->parent = NULL
2.
while (queue != {})
(a) next = pop from queue
(b) if (next == goal) return path; (the path is the
sequence of parents from goal)
(c) Add new successors of next to queue
(d) Mark next as parent of each successor
3. return no path;
Breadth-first Search

Cells in Queue:
−
Step 2
Breadth-first Search

Cells in Queue:
−
Step 3
Breadth-first Search Demo

http://qiao.github.com/PathFinding.js/visual/
Breadth-first Search

Completeness

Optimality

Efficiency
−
Time:
−
Space:
Answers will be discussed again in tutorial next week
Breadth-first search

Completeness
−

Yes
Optimality
−
Yes, if each movement has same cost
−
No, if different costs
Pathfinding with costs
1
A
C
1
8
2
D
B
1
F
1
2
0.5
E
1
G
Pathfinding with costs


Breadth-first is no longer guaranteed to find
shortest path (in terms of cost)
Which brings us to Dijkstra's Algorithm
−
A very important algorithm in CS
−
Used extensively

for example, in networks and routing
−
Performs similar to breadth-first when
movement costs are equal
−
Guarantees shortest path as long as costs are
non-negative
Dijkstra's Algorithm


Maintains two lists:
−
Open (nodes/squares that need to be
investigated)
−
Closed (nodes/squares that have been
investigated)
Maintains least cost from start to each node. This
is commonly called the G-function
−

We will use notation: g(Node)
Uses a greedy approach
−
Always picks the closest (least cost from start)
node to investigate next
Dijkstra's Algorithm (basics)


Step 1:
a)
Initialise closed list to NULL
b)
Move start (D) to open list
c)
Set g(D)=0
1
A
Step 2 (repeated):
member of open list (D)
(a) Assign cost-from-source to
1
8
2
(a) Pop lowest cost
C
B
D
1
F
1
0 .5
2
E
its neighbours: g(E)=0.5, g(F)=1, g(A)=8
(a) Move D to closed list, and E,F,A to open list
(b) Set parents of E,F,A to D
1
G
Dijkstra's Algorithm (basics)


Now, closed={D}, open={E,F,A}
Step 2 (repeated):
a)
Pop lowest cost member of open list (E)
b)
Assign cost-from-source to its neighbours:
g(B)=0.5+1, g(G)=0.5+1
a)
Move E to closed list,
and B,G to open list
Set parents of B,G to E
C
1
8
2
a)
1
A
B
D
1
F
1
0 .5
2
E
1
G
Dijkstra's Algorithm (Basics)

In Step 2b, when assigning cost-from-source:
−

In Step 2b and 2c:
−

If the node is already in the open list, you need to
check if you have found a less costly path to it. If
yes, update that node's cost and parent to reflect
the cheaper path.
you should ignore any neighbours that are already
in the closed list (do not add members of closed
list back to open list!)
Algorithm ends when
−
Goal is popped from open list in Step 2a (success)
−
Open list is empty (no path to goal)
Dijkstra's Algorithm for Grids

Dijkestra (start, goal)
1. Initialise: Closed={}; Open={start}; g(start)=0;
2. While (Open !={})
(a)
(b)
(c)
(d)
current=square with minimum g-value in Open
If (current==goal) return Path
Push (Closed, current)
For each adjacent square X
i. If (X is Obstacle OR X is in Closed) Ignore X;
ii. Calculate new g(X)
iii. If (X is in Open AND the new g(X) < g(X))
Change parent(X) to current and Update g(X)
Else Add X to Open and change parent(X) to current
3. Return NULL
Dijkstra's Algorithm Demo

http://qiao.github.com/PathFinding.js/visual/
A* Algorithm



Similar to Dijkstra's Algorithm, but with a Heuristic
Function: So for each node in graph (or square in
grid), we associate:
−
g(Node) = Cost of path from Start to Node
−
h(Node) = An estimate of cost of path from
Node to Goal
−
f(Node) = g(Node) + h(Node) is the estimate of
the best path from Start to Goal that passes
through Node
Just replace g() with f() in Dijkstra to get A*
Replace g() with h() to get Best First Algorithm
Heuristics

In simple grid worlds, straight line distance to
goal is often a sensible h() function
1
2
3
6
5
4
6
5
5
6
6
6
Heuristics for A*


If h(n)=0 for all n
−
A* is identical to Dijkstra's Algorithm
If h(n) <= actual cost of moving from `n' to goal
−
A* is guaranteed to find the shortest path
−


The lower h(n) is, the more nodes are expanded
If h(n) > than actual cost of moving from `n' to goal
−
Longer paths can be found first (not optimal).
If h(n) = actual cost of moving from `n' to goal
−
A* will search only the shortest path and nowhere
else.
Heuristics for A*


A good heuristic should be
−
Fast to compute
−
Always less than actual cost
Examples:
−
Euclidean Diatance

−
Manhattan Distance ( diagonals not allowed)

−
h(n) = sqrt((n.x-goal.x)^2 + (n.y-goal.y)^2)
h(n) = abs(n.x-goal.x) + abs(n.y-goal.y)
Chebyshev Distance (diagonals allowed)

h(n) = max(abs(n.x-goal.x), abs(n.y-goal.y))
Negative Weights
E
-0.38
A
0.51
D
0.36
C
-0.29
0.32
B