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


主要修改的就是print函数,以及super。其中GridWithWeights中如果使用super(GridWithWeights).__init__(width, height)会出错,我不是很理解,于是用了笨的SquareGrid.__init__(self, width, height),不会影响结果。


作者在代码中自己实现了一个简单地Queue,,不清楚为何不import python自带的Queue。

作者对于图的理解认为越简单表示越好,于是不定义任何图的class,用元组代替图中的每个节点,或者是边。

尤其要注意的是在作者提供的算法中,python里的字典变量起到了非常大的作用。


class SquareGrid中有一个filter的用法非常棒,作为python入门人员,这个函数值得学习吸收!

作者在画图时把墙壁的width设置为2,我们这儿设置为1即可。


文章最后给出了许多优化建议,以及链接,也都值得细读。




0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 打了绒促没排卵怎么办 把孩子嘴打肿了怎么办 幼儿孩子被打怎么办 老是忍不住打孩子怎么办 孩子不爱学汉字怎么办 小孩心里有阴影怎么办 性格固执的小孩怎么办 看见小孩子就烦怎么办 孩子吃饭不专心怎么办 上课不专心听怎么办 做作业总是走神怎么办 做事注意力不集中怎么办 做事注意力不能集中怎么办 幼儿争抢玩具老师怎么办 孩子不专心学习怎么办 一年级孩子学习边学边忘怎么办 对爱不专心怎么办 孩子脑子不灵活怎么办 小孩写作业心慌怎么办 4岁写数字怎么办 孩子做事太慢怎么办 小孩子做事不认真怎么办 员工做事不认真怎么办 做事总是不认真怎么办 孩子上课老是讲话怎么办 孩子上课总讲话怎么办 孩子不求上进怎么办 孩子只知道吃完怎么办 孩子演出前紧张怎么办 儿童写字不专心怎么办 孩子上课没精神怎么办 小孩写字太慢怎么办 儿童上课不集中怎么办 突然头晕迷糊眼花怎么办 自己上课不专心怎么办 颈椎病头晕怎么办才好 孩孑记忆力不好怎么办 上课的时候困怎么办 小学生写字太慢怎么办 一年级小学生写字慢怎么办 小学生写字太用力怎么办