文章来源:http://theory.stanford.edu/~amitp/GameProgramming/ImplementationNotes.html
The A* algorithm, stripped of all the code, is fairly simple. There are two sets, OPEN and CLOSED. The OPEN set contains those nodes that are candidates for examining. Initially, the OPEN set contains just one element: the starting position. The CLOSED set contains those nodes that have already been examined. Initially, the CLOSED set is empty. Graphically, the OPEN set is the “frontier” and the CLOSED set is the “interior” of the visited areas. Each node also keeps a pointer to its parent node so that we can determine how it was found.
A*算法,抛开代码不看的话,是相当简单的。维护OPEN和CLOSED两个集合。OPEN集合包含待评估的候选节点。起初,OPEN集合只包含起始点。CLOSED集合包含经过评估的节点。起初,CLOSED集合是空的,从图形上看,OPEN集合是一个“外圈”,CLOSE集合是一个访问过的“内部”区域。每个节点会保存父节点的指针,所以我们可以确定节点是怎么被查找到的。
There is a main loop that repeatedly pulls out the best node n
in OPEN (the node with the lowest f
value) and examines it. If n
is the goal, then we’re done. Otherwise, node n
is removed from OPEN and added to CLOSED. Then, its neighbors n'
are examined. A neighbor that is in CLOSED has already been seen, so we don’t need to look at it (*). A neighbor that is in OPEN is scheduled to be looked at, so we don’t need to look at it now (*). Otherwise, we add it to OPEN, with its parent set to n
. The path cost to n'
, g(n')
, will be set to g(n) + movementcost(n, n')
.
主循环会反复将最优节点n(该节点拥有最小的f值)从OPEN集合中取出并评估。如果n是目标节点,我们完成寻路。否则将n从OPEN集合中移出并添加到CLOSED集合。然后,其他的邻居节点n'都已经被评估过了。因为在CLOSED中的邻居节点是已经被评估过了的,所以不需要再去查看(*)。在OPEN中的邻居节点因为是计划要查看的节点,所以现在不需要查看(*)。否则,我们添加其到OPEN中,并设置其父节点为n。到达n'的路径开销,g(n')将被设置为g(n) + movementcost(n, n')。
(*) I’m skipping a small detail here. You do need to check to see if the node’s g
value can be lowered, and if so, you re-open it.
在这里我跳过了一些细节,你需要检查节点的g值,看是否更小,如果是的话,将该节点重新放到OPEN中。
OPEN = priority queue containing START
CLOSED = empty set
while lowest rank in OPEN is not the GOAL:
current = remove lowest rank item from OPEN
add current to CLOSED
for neighbors of current:
cost = g(current) + movementcost(current, neighbor)
if neighbor in OPEN and cost less than g(neighbor):
remove neighbor from OPEN, because new path is better
if neighbor in CLOSED and cost less than g(neighbor): **
remove neighbor from CLOSED
if neighbor not in OPEN and neighbor not in CLOSED:
set g(neighbor) to cost
add neighbor to OPEN
set priority queue rank to g(neighbor) + h(neighbor)
set neighbor's parent to current
reconstruct reverse path from goal to start
by following parent pointers
OPEN = 包含“起始点”的优先队列
CLOSED = 空集
当OPEN中的最小值不是目标节点:
current = 从OPEN中移出排名最小节点(最优节点)
添加current 节点到CLOSED集合
遍历current节点的邻居节点neighbor:
cost = g(current) + movementcost(current,neighbor)
如果 neighbor 在OPEN 中,并且 cost值小于g(neighbor):
从OPEN中移出neighbor,因为新的路径更优
如果 neighbor 在CLOSED中,并且 cost值小于g(neighbor):**
从CLOSED中删除neighbor
如果 neighbor 即不在 OPEN中也不在 CLOSED中
设置 cost = g(neighbor)
添加neighbor到OPEN中
设置优先队列排名为:g(neighbor) + h(neighbor)
设置neighbor 的父节点为 current
根据父节点指针创建从目标到起始点的倒推路径
(**) This should never happen if you have an monotone admissible heuristic. However in games we often have inadmissible heuristics.
If your game has situations in which the start and goal are not connected at all by the graph, A* will take a long time to run, since it has to explore every node connected from the start before it realizes there’s no path. Calculate the Connected Components first and only use A* if the start and goal are in the same region.
连通性
如果你的游戏中有起点和终点根本无法连通的情况,A*算法将运行很长时间,在意识到没有可连通的路径之前将遍历所有节点。首先计算连通性,只在起点和终点在同一块区域中时才使用A*算法。