Python-加速寻路
这是我的寻路功能:Python-加速寻路,python,path-finding,Python,Path Finding,这是我的寻路功能: def get_distance(x1,y1,x2,y2): neighbors = [(-1,0),(1,0),(0,-1),(0,1)] old_nodes = [(square_pos[x1,y1],0)] new_nodes = [] for i in range(50): for node in old_nodes: if node[0].x == x2 and node[0].y == y2:
def get_distance(x1,y1,x2,y2):
neighbors = [(-1,0),(1,0),(0,-1),(0,1)]
old_nodes = [(square_pos[x1,y1],0)]
new_nodes = []
for i in range(50):
for node in old_nodes:
if node[0].x == x2 and node[0].y == y2:
return node[1]
for neighbor in neighbors:
try:
square = square_pos[node[0].x+neighbor[0],node[0].y+neighbor[1]]
if square.lightcycle == None:
new_nodes.append((square,node[1]))
except KeyError:
pass
old_nodes = []
old_nodes = list(new_nodes)
new_nodes = []
nodes = []
return 50
问题是人工智能需要很长时间才能做出响应(响应时间你应该用曼哈顿距离来代替你的算法作为启发式。一个相当快的解决方案是实施Dijkstra算法(我已经在中实现了): 构建原始地图。这是一个蒙面阵列,步行者无法在蒙面元素上行走:
%pylab inline
map_size = (20,20)
MAP = np.ma.masked_array(np.zeros(map_size), np.random.choice([0,1], size=map_size))
matshow(MAP)
下面是Dijkstra算法:
def dijkstra(V):
mask = V.mask
visit_mask = mask.copy() # mask visited cells
m = numpy.ones_like(V) * numpy.inf
connectivity = [(i,j) for i in [-1, 0, 1] for j in [-1, 0, 1] if (not (i == j == 0))]
cc = unravel_index(V.argmin(), m.shape) # current_cell
m[cc] = 0
P = {} # dictionary of predecessors
#while (~visit_mask).sum() > 0:
for _ in range(V.size):
#print cc
neighbors = [tuple(e) for e in asarray(cc) - connectivity
if e[0] > 0 and e[1] > 0 and e[0] < V.shape[0] and e[1] < V.shape[1]]
neighbors = [ e for e in neighbors if not visit_mask[e] ]
tentative_distance = [(V[e]-V[cc])**2 for e in neighbors]
for i,e in enumerate(neighbors):
d = tentative_distance[i] + m[cc]
if d < m[e]:
m[e] = d
P[e] = cc
visit_mask[cc] = True
m_mask = ma.masked_array(m, visit_mask)
cc = unravel_index(m_mask.argmin(), m.shape)
return m, P
def shortestPath(start, end, P):
Path = []
step = end
while 1:
Path.append(step)
if step == start: break
if P.has_key(step):
step = P[step]
else:
break
Path.reverse()
return asarray(Path)
以下是一些计时统计数据:
%timeit dijkstra(MAP)
#10 loops, best of 3: 32.6 ms per loop
代码中最大的问题是,您没有采取任何措施来避免多次访问相同的坐标。这意味着您访问的节点数肯定会呈指数增长,因为它可以在前几个节点上来回多次 避免重复的最佳方法是维护已添加到队列中的坐标的
集
(尽管如果您的节点
值是可散列的,您可能可以直接将它们添加到集合中,而不是坐标元组)。由于我们正在进行广度优先搜索,我们将始终通过(其中一个)到达给定的坐标最短的路径,因此我们不必担心以后会找到更好的路径
试着这样做:
def get_distance(x1,y1,x2,y2):
neighbors = [(-1,0),(1,0),(0,-1),(0,1)]
nodes = [(square_pos[x1,y1],0)]
seen = set([(x1, y1)])
for node, path_length in nodes:
if path_length == 50:
break
if node.x == x2 and node.y == y2:
return path_length
for nx, ny in neighbors:
try:
square = square_pos[node.x + nx, node.y + ny]
if square.lightcycle == None and (square.x, square.y) not in seen:
nodes.append((square, path_length + 1))
seen.add((square.x, square.y))
except KeyError:
pass
return 50
我还简化了循环。与在每个深度后切换列表不同,您可以只使用一个循环,并在迭代早期值时添加到其末尾。如果没有找到少于50步的路径(使用存储在2元组中的距离,而不是外部循环的通过次数),我仍然会中止。进一步的改进可能是对队列使用collections.dequeue
,因为您可以从一端高效地pop
,而将追加到另一端。这可能不会产生很大的影响,但可能会避免一点内存使用
我还避免了大多数以1和0进行索引,以便于在for
循环中解压成单独的变量名。我认为这更易于阅读,并且避免了混淆,因为两种不同类型的2元组具有不同的含义(一种是节点,距离元组,另一种是x,y
).它不应该是节点[0]。y==y2
?它也应该是新的\u节点。追加((正方形,节点[1]+1))
。请注意+1
。这会快多少?A*和B*在性能方面相当先进。我不知道与您的实现相比,加速会有多大,但它会存在。A*主要是有用的,最适合路径查找算法。甚至最适合导航系统。
def get_distance(x1,y1,x2,y2):
neighbors = [(-1,0),(1,0),(0,-1),(0,1)]
nodes = [(square_pos[x1,y1],0)]
seen = set([(x1, y1)])
for node, path_length in nodes:
if path_length == 50:
break
if node.x == x2 and node.y == y2:
return path_length
for nx, ny in neighbors:
try:
square = square_pos[node.x + nx, node.y + ny]
if square.lightcycle == None and (square.x, square.y) not in seen:
nodes.append((square, path_length + 1))
seen.add((square.x, square.y))
except KeyError:
pass
return 50