A*算法 学习记录
来源:互联网 发布:网络售药 京东 编辑:程序博客网 时间:2024/06/05 16:33
从某个国外的网站上看到了一篇介绍路径搜索算法的文章,使用python3编写,非常优秀。我使用的是python2,对代码稍作修改即可实现。作者还用C++和C#编写。
该文章源于一个游戏塔防的策略。点击打开链接
动画演示了不同墙壁下,图上随机生成的粒子点如何经过最短的路径到达目标位置。实际上每个粒子点并不是意义计算如何到达目标,而是当用户改变地图或者改变目标点位置后,重新计算了图上每个位置的最短运动方向。相当于生成了一张表格,粒子落在表格中的哪个区域,就对应项哪个方向运动。
在文章末尾有个链接,详细的介绍了路径搜索的各个思想和步骤。点击打开链接
下面给出python2.7的代码,作者给出的是python3。
首先是implementation.py文件的修改。修改如下
# Sample code from http://www.redblobgames.com/pathfinding/# Copyright 2014 Red Blob Games <redblobgames@gmail.com>## Feel free to use this code in your own projects, including commercial projects# License: Apache v2.0 <http://www.apache.org/licenses/LICENSE-2.0.html>class SimpleGraph: def __init__(self): self.edges = {} def neighbors(self, id): return self.edges[id]example_graph = SimpleGraph()example_graph.edges = { 'A': ['B'], 'B': ['A', 'C', 'D'], 'C': ['A'], 'D': ['E', 'A'], 'E': ['B']}import collectionsclass Queue: def __init__(self): self.elements = collections.deque() def empty(self): return len(self.elements) == 0 def put(self, x): self.elements.append(x) def get(self): return self.elements.popleft()# utility functions for dealing with square gridsdef from_id_width(id, width): return (id % width, id // width)def draw_tile(graph, id, style, width): r = "." if 'number' in style and id in style['number']: r = "%d" % style['number'][id] if 'point_to' in style and style['point_to'].get(id, None) is not None: (x1, y1) = id (x2, y2) = style['point_to'][id] if x2 == x1 + 1: r = ("\u2192").decode('unicode_escape') if x2 == x1 - 1: r = ("\u2190").decode('unicode_escape') if y2 == y1 + 1: r = ("\u2193").decode('unicode_escape') if y2 == y1 - 1: r = ("\u2191").decode('unicode_escape') if 'start' in style and id == style['start']: r = "A" if 'goal' in style and id == style['goal']: r = "Z" if 'path' in style and id in style['path']: r = "@" if id in graph.walls: r = "#" * width return rdef draw_grid(graph, width=1, **style): for y in range(graph.height): for x in range(graph.width): #print("%%-%ds" % width % draw_tile(graph, (x, y), style, width), end="") print draw_tile(graph, (x, y), style, width), print# data from main articleDIAGRAM1_WALLS = [from_id_width(id, width=30) for id in [21,22,51,52,81,82,93,94,111,112,123,124,133,134,141,142,153,154,163,164,171,172,173,174,175,183,184,193,194,201,202,203,204,205,213,214,223,224,243,244,253,254,273,274,283,284,303,304,313,314,333,334,343,344,373,374,403,404,433,434]]class SquareGrid: def __init__(self, width, height): self.width = width self.height = height self.walls = [] def in_bounds(self, id): (x, y) = id return 0 <= x < self.width and 0 <= y < self.height def passable(self, id): return id not in self.walls def neighbors(self, id): (x, y) = id results = [(x+1, y), (x, y-1), (x-1, y), (x, y+1)] if (x + y) % 2 == 0: results.reverse() # aesthetics results = filter(self.in_bounds, results) results = filter(self.passable, results) return resultsclass GridWithWeights(SquareGrid): def __init__(self, width, height): #super().__init__(width, height) SquareGrid.__init__(self, width, height) self.weights = {} def cost(self, from_node, to_node): return self.weights.get(to_node, 1)diagram4 = GridWithWeights(10, 10)diagram4.walls = [(1, 7), (1, 8), (2, 7), (2, 8), (3, 7), (3, 8)]diagram4.weights = {loc: 5 for loc in [(3, 4), (3, 5), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (4, 7), (4, 8), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5), (5, 6), (5, 7), (5, 8), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6), (6, 7), (7, 3), (7, 4), (7, 5)]}import heapqclass PriorityQueue: def __init__(self): self.elements = [] def empty(self): return len(self.elements) == 0 def put(self, item, priority): heapq.heappush(self.elements, (priority, item)) def get(self): return heapq.heappop(self.elements)[1]def dijkstra_search(graph, start, goal): frontier = PriorityQueue() frontier.put(start, 0) came_from = {} cost_so_far = {} came_from[start] = None cost_so_far[start] = 0 while not frontier.empty(): current = frontier.get() if current == goal: break for next in graph.neighbors(current): new_cost = cost_so_far[current] + graph.cost(current, next) if next not in cost_so_far or new_cost < cost_so_far[next]: cost_so_far[next] = new_cost priority = new_cost frontier.put(next, priority) came_from[next] = current return came_from, cost_so_fardef reconstruct_path(came_from, start, goal): current = goal path = [current] while current != start: current = came_from[current] path.append(current) path.append(start) # optional path.reverse() # optional return pathdef heuristic(a, b): (x1, y1) = a (x2, y2) = b return abs(x1 - x2) + abs(y1 - y2)def a_star_search(graph, start, goal): frontier = PriorityQueue() frontier.put(start, 0) came_from = {} cost_so_far = {} came_from[start] = None cost_so_far[start] = 0 while not frontier.empty(): current = frontier.get() if current == goal: break for next in graph.neighbors(current): new_cost = cost_so_far[current] + graph.cost(current, next) if next not in cost_so_far or new_cost < cost_so_far[next]: cost_so_far[next] = new_cost priority = new_cost + heuristic(goal, next) frontier.put(next, priority) came_from[next] = current return came_from, cost_so_far
作者在代码中自己实现了一个简单地Queue,,不清楚为何不import python自带的Queue。
作者对于图的理解认为越简单表示越好,于是不定义任何图的class,用元组代替图中的每个节点,或者是边。
尤其要注意的是在作者提供的算法中,python里的字典变量起到了非常大的作用。
class SquareGrid中有一个filter的用法非常棒,作为python入门人员,这个函数值得学习吸收!
作者在画图时把墙壁的width设置为2,我们这儿设置为1即可。
文章最后给出了许多优化建议,以及链接,也都值得细读。
0 0
- A*算法 学习记录
- A星寻路学习记录
- 算法学习 A*算法
- 算法学习记录
- 分块算法学习记录
- KMP算法学习记录
- 学习记录 蝙蝠算法
- [记录] 算法学习集合
- A*算法学习笔记
- 学习笔记:A*算法
- 算法学习 -- a+b
- ACM 算法类学习记录
- 算法学习记录-希尔排序
- 基本排序算法学习记录
- 数据结构与算法学习记录
- 牛客网算法学习记录-排序
- lca倍增算法学习记录
- 牛客网算法学习记录-字符串
- Codeforces Round #364 (Div. 2) C. They Are Everywhere __ two pointers or binary search
- java编程思想读书笔记 第十章内部类(中)
- javaIO之对象流
- 使用命令行展开功能来完成练习
- JAVA语言遗漏
- A*算法 学习记录
- 【软工】初识软工-《软件工程导论》
- 我的博文之路由此开启
- |洛谷|分治|P1010 幂次方
- 小话设计模式(五)原型模式
- UGUI研究院之不添加摄像机解决UI与UI特效叠层问题
- [深度学习基础] 1. 图像识别问题的挑战及数据驱动过程
- 5-2 派生类的构造函数
- 大数据之Linux+大数据开发篇