A*算法概述
A*算法是路徑規劃表現較好的算法之一。所謂路規劃是,從A點到B點找到一條合適的路徑,使得智能體完成從A到B的運動。所謂合適,是指智能體定義的參數指標,如步數最少,代價最低等等。不同的應用場景具有不同的參數指標。路徑規劃廣泛應用於智能體尋路、八數碼難題遊戲等場景。
A*算法原理
在路徑規劃中,由於可能有障礙存在,使得路徑上的一些點不可用。在路徑規劃中,需要避開這些點。在尋找合理路徑中,如何評價路徑呢。在A*算法中,通常採用
來評估該路徑。其中G是從起始點A到指定點的移動代價。H是指定點到終點B的代價。其中G是可以通過計算獲得的,而H不可以準確獲得,其原因在於在指定點到終點B的路徑上我們並不知道障礙物是怎麼樣的,因此H是一種估計,通常被稱之爲試探法。這裏我們使用 Manhattan 方法,計算從當前方格橫向或縱向移動到達目標所經過的方格數,忽略對角移動,然後把總數乘以 10 。之所以叫做 Manhattan 方法,是因爲這很像統計從一個地點到另一個地點所穿過的街區數,而你不能斜向穿過街區。重要的是,計算 H 是,要忽略路徑中的障礙物。這是對剩餘距離的估算值,而不是實際值,因此才稱爲試探法。當H爲0時,A*算法退化成迪傑斯特拉算法。
移動代價可以通過距離公式來計算,距離的計算有多種維度,包括曼哈頓距離、歐拉距離等等,應根據具體的場景選取合適的計算方式。
在使用A算法進行路徑規劃時,有兩個重要的列表將被使用,那就是openlist和closelist。openlist存放是路徑可能存放的點,即openlist是個待檢查的列表。而closelist是不在需要關注的點,即某點被openlist移除,就會被放到closelist。
A的算法步驟如下:
1、把起點加入到openlist
2、然後重複下面過程
*.遍歷openlist,找到路徑評價F值最小的節點,把它當做當前要處理的節點。
*.把該節點從openlist移到closelist
*.對該節點的所有鄰居節點做如下處理
**.如果不在openlist裏,則加入openlist,並把當前節點設置爲父節點,記錄該鄰居節的F,G,H值
**.如果在openlist,如果當前節點到該鄰居節點的路徑代價小於當前節點的路徑代價,則用更小的值來代替該 鄰居節點的G,同時把當前節點設置爲鄰居節點的父節點。
3、當把終點加到openlist時候,證明路徑找到,並沿着父節點可以找到路徑,否則查找終點失敗,並且openlist是空的,此時沒有路徑
A*算法代碼實現示例
一個代碼示例如下:
# -*- coding: utf-8 -*-
# @Time : 2019/12/2 22:37
# @Author : HelloWorld!
# @FileName: A_Star.py
# @Software: PyCharm
# @Operating System: Windows 10
# @Python.version: 3.5
class Array2D:
"""
說明:
1.構造方法需要兩個參數,即二維數組的寬和高
2.成員變量w和h是二維數組的寬和高
3.使用:‘對象[x][y]’可以直接取到相應的值
4.數組的默認值都是0
"""
def __init__(self, w, h):
self.w = w
self.h = h
self.data = []
self.data = [[0 for y in range(h)] for x in range(w)]
def showArray2D(self):
for y in range(self.h):
for x in range(self.w):
print(self.data[x][y], end=' ')
print("")
def __getitem__(self, item):
return self.data[item]
class Point:
"""
表示一個點
"""
def __init__(self, x, y):
self.x = x;
self.y = y
def __eq__(self, other):
if self.x == other.x and self.y == other.y:
return True
return False
def __str__(self):
return "x:" + str(self.x) + ",y:" + str(self.y)
class AStar:
"""
AStar算法的Python3.x實現
"""
class Node: # 描述AStar算法中的節點數據
def __init__(self, point, endPoint, g=0):
self.point = point # 自己的座標
self.father = None # 父節點
self.g = g # g值,g值在用到的時候會重新算
self.h = (abs(endPoint.x - point.x) + abs(endPoint.y - point.y)) * 10 # 計算h值
def __init__(self, map2d, startPoint, endPoint, passTag=0):
"""
構造AStar算法的啓動條件
:param map2d: Array2D類型的尋路數組
:param startPoint: Point或二元組類型的尋路起點
:param endPoint: Point或二元組類型的尋路終點
:param passTag: int類型的可行走標記(若地圖數據!=passTag即爲障礙)
"""
# 開啓表
self.openList = []
# 關閉表
self.closeList = []
# 尋路地圖
self.map2d = map2d
# 起點終點
if isinstance(startPoint, Point) and isinstance(endPoint, Point):
self.startPoint = startPoint
self.endPoint = endPoint
else:
self.startPoint = Point(*startPoint)
self.endPoint = Point(*endPoint)
# 可行走標記
self.passTag = passTag
def getMinNode(self):
"""
獲得openlist中F值最小的節點
:return: Node
"""
currentNode = self.openList[0]
for node in self.openList:
if node.g + node.h < currentNode.g + currentNode.h:
currentNode = node
return currentNode
def pointInCloseList(self, point):
for node in self.closeList:
if node.point == point:
return True
return False
def pointInOpenList(self, point):
for node in self.openList:
if node.point == point:
return node
return None
def endPointInCloseList(self):
for node in self.openList:
if node.point == self.endPoint:
return node
return None
def searchNear(self, minF, offsetX, offsetY):
"""
搜索節點周圍的點
:param minF:F值最小的節點
:param offsetX:座標偏移量
:param offsetY:
:return:
"""
# 越界檢測
if minF.point.x + offsetX < 0 or minF.point.x + offsetX > self.map2d.w - 1 or minF.point.y + offsetY < 0 or minF.point.y + offsetY > self.map2d.h - 1:
return
# 如果是障礙,就忽略
if self.map2d[minF.point.x + offsetX][minF.point.y + offsetY] != self.passTag:
return
# 如果在關閉表中,就忽略
currentPoint = Point(minF.point.x + offsetX, minF.point.y + offsetY)
if self.pointInCloseList(currentPoint):
return
# 設置單位花費
if offsetX == 0 or offsetY == 0:
step = 10
else:
step = 14
# 如果不再openList中,就把它加入openlist
currentNode = self.pointInOpenList(currentPoint)
if not currentNode:
currentNode = AStar.Node(currentPoint, self.endPoint, g=minF.g + step)
currentNode.father = minF
self.openList.append(currentNode)
return
# 如果在openList中,判斷minF到當前點的G是否更小
if minF.g + step < currentNode.g: # 如果更小,就重新計算g值,並且改變father
currentNode.g = minF.g + step
currentNode.father = minF
def start(self):
"""
開始尋路
:return: None或Point列表(路徑)
"""
# 判斷尋路終點是否是障礙
if self.map2d[self.endPoint.x][self.endPoint.y] != self.passTag:
return None
# 1.將起點放入開啓列表
startNode = AStar.Node(self.startPoint, self.endPoint)
self.openList.append(startNode)
# 2.主循環邏輯
while True:
# 找到F值最小的點
minF = self.getMinNode()
# 把這個點加入closeList中,並且在openList中刪除它
self.closeList.append(minF)
self.openList.remove(minF)
# 判斷這個節點的上下左右節點
self.searchNear(minF, 0, -1)
self.searchNear(minF, 0, 1)
self.searchNear(minF, -1, 0)
self.searchNear(minF, 1, 0)
# 判斷是否終止
point = self.endPointInCloseList()
if point: # 如果終點在關閉表中,就返回結果
# print("關閉表中")
cPoint = point
pathList = []
while True:
if cPoint.father:
pathList.append(cPoint.point)
cPoint = cPoint.father
else:
# print(pathList)
# print(list(reversed(pathList)))
# print(pathList.reverse())
return list(reversed(pathList))
if len(self.openList) == 0:
return None
if __name__ == '__main__':
#創建一個10*10的地圖
map2d=Array2D(10,10)
#設置障礙
map2d[4][0]= 1
map2d[4][1] = 1
map2d[4][2] = 0
map2d[4][3] = 1
map2d[4][4] = 1
map2d[4][5] = 1
map2d[4][6] = 1
#顯示地圖當前樣子
map2d.showArray2D()
#創建AStar對象,並設置起點爲0,0終點爲9,0
aStar=AStar(map2d,Point(0,0),Point(9,0))
#開始尋路
pathList=aStar.start()
#遍歷路徑點,在map2d上以'8'顯示
for point in pathList:
map2d[point.x][point.y]=8
# print(point)
print("----------------------")
#再次顯示地圖
map2d.showArray2D()
結果如下:
0 0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
----------------------
0 8 8 8 1 8 8 8 8 8
0 0 0 8 1 8 0 0 0 0
0 0 0 8 8 8 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
參考文獻
https://blog.csdn.net/qq_39687901/article/details/88554716
https://blog.csdn.net/ctwy291314/article/details/95055008
https://blog.csdn.net/qq_39687901/article/details/80753433