python3.6實現的A星演算法
阿新 • • 發佈:2019-02-02
A星演算法原理:
原理我就不再贅述,可以參考這篇部落格https://blog.csdn.net/hitwhylz/article/details/23089415
程式碼實現:
首先新增兩個通用類Array2D和Point:
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)
Array2D是為了簡化二維陣列的建立,Point是為了表示一個點,並且過載等號運算子,可以判斷兩個Point座標是否相等.
AStar類:
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 #起點終點 self.startPoint=startPoint self.endPoint=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: :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 #如果在關閉表中,就忽略 if self.pointInCloseList(Point(minF.point.x+offsetX,minF.point.y+offsetY)): return #設定單位花費 if offsetX==0 or offsetY==0: step=10 else: step=14 #如果不再openList中,就把它加入openlist currentNode=self.pointInOpenList(Point(minF.point.x+offsetX,minF.point.y+offsetY)) if not currentNode: currentNode=AStar.Node(Point(minF.point.x+offsetX,minF.point.y+offsetY),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+step currentNode.father=minF def start(self): ''' 開始尋路 :return: None或Point列表(路徑) ''' #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] = 1
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()