天天看点

A*寻路算法python版(第一版)伪代码

      最近这一周在自学python,基本语法学的差不多,面向对象学完了,发现真的是节省时间和精力,遂打算用python将c++版本的Astar寻路代码重写一遍,代码量相比于c++确实有了大幅度降低,现在写的这个版本基本上还只是python的外壳,过程还是c,但是代码量已经有了很大的降低,比如python 中最好的就是for的遍历功能。

-------时间线20180325----------------------------

注意:以下贴的代码只是伪代码,可运行版在第二版中贴出

-------时间线20180325----------------------------

如下面的代码:

  1. for (int j = 0; j < OpenListPosition; j++) 
  2.     if ((OpenList[j].ChessUnit_x == CurrentNeibors[i].ChessUnit_x) && (OpenList[j].ChessUnit_y == CurrentNeibors[i].ChessUnit_y))

    实际上用python: if CurrentNeibors in Openlist:这一句就完美解决了,它会自动的去openlist中遍历去找是否有CurrentNeibors这个量。

    我发现python 的列表功能太强大了,根本就不用再去定义类

    就 item = [[0,0],0,0,0,fileLine[j]]这一句代码就顶上了对棋盘类CHESS_BOARD_UNIT的定义

    struct CHESS_BOARD_UNIT

    {

PARENT_POSITION ParentPosition;

int g_value;

int h_value;

int f_value;

char flag;//标识此单元是:2起点/3终点/1障碍物/0通路

    }; 

    好处实在太多,现在还只是学了皮毛,如果深入学一些其他更复杂的函数,代码量应该会更短!

    代码粘贴如下(还得继续调试):     

#coding=utf-8
#定义棋盘、起点、终点、障碍物
#约定:棋盘外框都视为障碍物
########b###########
########b###########
##s#####b###########
########b########e##
########b###########
########b###########
######b#b###########
######b#bbbbbb######
######b######b######
#########b###b######
#########b###b######
#########b###b#bbb##
#########b##########
####################
####################
####################
####################
####################
####################
####################
chess_size =  20
FILE_STORAGE_WAY =  'd:\\AstarFindWay.txt'	#随机数据文件存放路径

Start_x = 0
Start_y = 0
End_x = 0
End_y = 0	

OpenListPosition = 0 #指针标记open列表数组当前存放元素个数(position总指向最后一个元素的后一位置)
CloseListPosition = 0 #指针标记Close列表数组当前存放元素个数(position总指向最后一个元素的后一位置) 

OpenList = []#open列表(定义成数组形式)
CloseList = []#close列表

def openListIncraseSort():
	flag = 0
	i = 0
	#for (int i = 0; i < OpenListPosition; i++)//冒泡法由大到小排序
	while i < OpenListPosition:
		#for (int j = 0; j < OpenListPosition - i; j++)
		j = 0
		while j<OpenListPosition:
			if OpenList[j][2] < OpenList[j + 1][2]:#若OpenList[j].f_value < OpenList[j + 1].f_value,交换,从大到小排列
			
				ChessUnit_x = OpenList[j][0]
				ChessUnit_y = OpenList[j][1]
				f_value 	= OpenList[j][2]

				OpenList[j][0]= OpenList[j + 1][0]
				OpenList[j][1]= OpenList[j + 1][1]
				OpenList[j][2]= OpenList[j + 1][2]

				OpenList[j + 1][0] = ChessUnit_x
				OpenList[j + 1][1] = ChessUnit_y
				OpenList[j + 1][2] = f_value

				flag = 1 #将交换标志位置1
			j+=1 #循环变量增加1
			#if
		#while2
		if (0 == flag):
			break #内层循环一次都没交换,说明已经排好序
		flag = 0 #将标志位重新清0
		i+=1 #循环变量增加1
	#while1

	#for(int i = 0; i < OpenListPosition; i++)
	#{
	#	cout << OpenList[i].ChessUnit_x << ","<< OpenList[i].ChessUnit_y << endl;
	#}

def dealCurrentNeibors(CurrentUnit):#判断当前结点周围8个点状态,计算g、h、f值,将周围每个点的父指针指向当前结点
	global OpenListPosition
	global CloseListPosition
	global OpenList
	global CloseList
	global chessboard
	OpenListFlag = 0
	CloseListFlag = 0

	ObstacleEast = 0	#标识当前点东边是否有障碍物
	ObstacleSouth = 0	#标识当前点南边是否有障碍物
	ObstacleWest = 0	#标识当前点西边是否有障碍物
	ObstacleNorth = 0	#标识当前点北边是否有障碍物

	#CloseListUnit EastUnit, SourthEastUnit, SourthUnit, SourthWestUnit, WestUnit, NorthWestUnit, NorthUnit, NorthEastUnit;//东,东南,南,西南,西,西北,北,东北
	CurrentNeibors = []#列表,按顺序存放当前结点的东,东南,南,西南,西,西北,北,东北方向的邻结点

	#东方y+1
	item = [CurrentUnit[0],CurrentUnit[1] + 1]
	CurrentNeibors.append(item)

	#东南方x+1,y+1
	item = [CurrentUnit[0] + 1,CurrentUnit[1] + 1]
	CurrentNeibors.append(item)

	#南方x+1
	item = [CurrentUnit[0] + 1,CurrentUnit[1]]
	CurrentNeibors.append(item)

	#西南方x+1,y-1
	item = [CurrentUnit[0] + 1,CurrentUnit[1]-1]
	CurrentNeibors.append(item)

	#西方y-1
	item = [CurrentUnit[0],CurrentUnit[1]-1]
	CurrentNeibors.append(item)

	#西北方x-1,y-1
	item = [CurrentUnit[0]-1,CurrentUnit[1]-1]
	CurrentNeibors.append(item)

	#北方x-1
	item = [CurrentUnit[0]-1,CurrentUnit[1]]
	CurrentNeibors.append(item)

	#东北方x-1,y+1
	item = [CurrentUnit[0]-1,CurrentUnit[1]+1]
	CurrentNeibors.append(item)

	#对当前方格东、南、西、北四个方向的临近方格依次检测
	i = 0
	while i<8:
		#当前中间结点到邻近结点的距离。约定:东南西北四个方向距离为10,四个斜方向距离为14
		if i%2 == 0:
			currenToNeibor = 10
		else:
			currenToNeibor = 14

		#终点
		if 'e' == chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][4]:#flag
			chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][0][0] = CurrentUnit[0]#[0][0]parent.x
			chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][0][1] = CurrentUnit[1]#[0][1]parent.y
			return 1
			#break;//找到终点,结束循环
'''
		#超出边界点
		elif CurrentNeibors[i][0] < 0 or CurrentNeibors[i][1]>19 or CurrentNeibors[i][0] < 0 or CurrentNeibors[i][1]>19:
			continue #结束判断
'''
		#障碍物点
		elif 'b' == chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][4]:#flags
			if i == 0:
				ObstacleEast = 1 #标识当前点东边有障碍物
			elif i == 2:
				ObstacleSouth = 1 #标识当前点南边有障碍物
			elif i == 4:
				ObstacleWest = 1 #标识当前点西边有障碍物
			elif i == 6:
				ObstacleNorth = 1 #标识当前点北边有障碍物
			else:

			#continue#结束判断
'''
		#将该临近点与closelist中的点逐个比较
		elif CurrentNeibors[i] in CloseList[j]:#python牛逼!
			#continue#结束判断
'''
		#将该临近点与openlist中的点逐个比较
		elif CurrentNeibors[i] in OpenList[j]:#python牛逼!
			if chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][1] < chessboard[CurrentUnit[0]][CurrentUnit[1]][1] + currenToNeibor:

			else#若该临近点的g值大于从起点经由当前结点到该临近结点的g值,将该临近结点的父指针指向当前结点,并更改该临近结点的g值,f值
				#将该临近结点的父指针指向当前结点
				chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][0][0] = CurrentUnit[0]#[0][0]parent.x
				chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][0][1] = CurrentUnit[1]#[0][1]parent.y
				#更改该临近结点的g值,f值
				chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][1] = chessboard[CurrentUnit[0]][CurrentUnit[1]][1] + currenToNeibor#g_value+currenToNeibor
				chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][3] = chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][1] + chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][2]#[1]g[2]h[3]f
			#continue #若该临近点的g值小于从起点经由当前结点到该临近结点的g值,不做任何操作

		#可作为通路点
		elif '#' == chessboard[CurrentNeibors[i].ChessUnit_x][CurrentNeibors[i].ChessUnit_y][4]:

			#将邻居结点的指针指向当前结点
			chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][0][0] = CurrentUnit[0]#[0][0]parent.x
			chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][0][1] = CurrentUnit[1]#[0][1]parent.y
			#计算该临近结点的g值,h值(曼哈顿距离),f值
			chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][1] = chessboard[CurrentUnit[0]][CurrentUnit[1]][1] + currenToNeibor
			chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][2] = 10 * (abs(CurrentNeibors[i][0] - End_x) + abs(CurrentNeibors[i][1] - End_y))
			chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][3] = chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][1] + chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][2]
			#将该临近点存入openlist中
			OpenList[OpenListPosition][0] = CurrentNeibors[i][0]
			OpenList[OpenListPosition][1] = CurrentNeibors[i][1]
			OpenList[OpenListPosition][2] = chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][3]#f_value
			OpenListPosition+=1
		else:

		i+=2#循环变量增加2
		#if
	#while

	#对当前方格东南、西南、西北、东北四个方向的临近方格依次检测
	i = 1
	while i<8:
		#当前中间结点到邻近结点的距离。约定:东南西北四个方向距离为10,四个斜方向距离为14
		if i%2 == 0:
			currenToNeibor = 10
		else:
			currenToNeibor = 14

		if 1 == ObstacleEast  and (1 == i or 7 == i): #若东方格是障碍物,则东南、东北都不能通行
			continue

		if 1 == ObstacleSouth and (1 == i or 3 == i): #若南方格是障碍物,则东南、西南都不能通行
			continue

		if 1 == ObstacleWest and (3 == i or 5 == i): #若西方格是障碍物,则西南、西北都不能通行
			continue

		if 1 == ObstacleNorth and (5 == i or 7 == i): #若北方格是障碍物,则西北、东北都不能通行
			continue

		#终点
		if 'e' == chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][4]:#flag
			chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][0][0] = CurrentUnit[0]#[0][0]parent.x
			chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][0][1] = CurrentUnit[1]#[0][1]parent.y
			return 1
			#break;//找到终点,结束循环
'''
		#超出边界点
		elif CurrentNeibors[i][0] < 0 or CurrentNeibors[i][1]>19 or CurrentNeibors[i][0] < 0 or CurrentNeibors[i][1]>19:
			#continue #结束判断

		#障碍物点
		elif 'b' == chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][4]:#flag
			#continue#结束判断

		#将该临近点与closelist中的点逐个比较
		elif CurrentNeibors[i] in CloseList[j]:#python牛逼!
			#continue#结束判断
'''
		#将该临近点与openlist中的点逐个比较
		elif CurrentNeibors[i] in OpenList[j]:#python牛逼!

			if chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][1] < chessboard[CurrentUnit[0]][CurrentUnit[1]][1] + currenToNeibor:

			else#若该临近点的g值大于从起点经由当前结点到该临近结点的g值,将该临近结点的父指针指向当前结点,并更改该临近结点的g值,f值
				#将该临近结点的父指针指向当前结点
				chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][0][0] = CurrentUnit[0]#[0][0]parent.x
				chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][0][1] = CurrentUnit[1]#[0][1]parent.y
				#更改该临近结点的g值,f值
				chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][1] = chessboard[CurrentUnit[0]][CurrentUnit[1]][1] + currenToNeibor#g_value+currenToNeibor
				chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][3] = chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][1] + chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][2]#[1]g[2]h[3]f
			#continue #若该临近点的g值小于从起点经由当前结点到该临近结点的g值,不做任何操作

		#可作为通路点
		elif '#' == chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][4]:#flag

			#将邻居结点的指针指向当前结点
			chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][0][0] = CurrentUnit[0]#[0][0]parent.x
			chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][0][1] = CurrentUnit[1]#[0][1]parent.y
			#计算该临近结点的g值,h值(曼哈顿距离),f值
			chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][1] = chessboard[CurrentUnit[0]][CurrentUnit[1]][1] + currenToNeibor
			chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][2] = 10 * (abs(CurrentNeibors[i][0] - End_x) + abs(CurrentNeibors[i][1] - End_y))
			chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][3] = chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][1] + chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][2]
			#将该临近点存入openlist中
			OpenList[OpenListPosition][0] = CurrentNeibors[i][0]
			OpenList[OpenListPosition][1] = CurrentNeibors[i][1]
			OpenList[OpenListPosition][2] = chessboard[CurrentNeibors[i][0]][CurrentNeibors[i][1]][3]
			OpenListPosition+=1
		else:
		#if
		i+=2#循环变量增加2
	#while
	return 0

def FileReadMatrix():	#将文件中的数据读回至chess_size*chess_size矩阵
	global chessboard
	i = 0 
	itemLine = []
	fileLine = []

	#uint uiTemp;	//定义变量存放从文件中读出的数据
	ifile = open(FILE_STORAGE_WAY,'r')	#作为只读文件打开
	#while True:
	fileLine = ifile.readline()
	while len(fileLine)>0:#只要读取的这一行有值,就处理
		j = 0
		while j<10:
			#将棋盘读入到flag中
			if 's' == fileLine[j]: #检测并记录起始点坐标
				Start_x = i
				Start_y = j
			item = [[0,0],0,0,0,fileLine[j]] #结构:A = [[parent.x,parent.y],g_value,h_value,f_value,flag]
			itemLine.append(item) #结构:B = [A,A,A,A,A....,A]一行20个
			j+=1

		chessboard.append(itemLine) #结构:[B,B,B,B,...,B] 20列
		fileLine = ifile.readline()#读取下一行数据
		i+=1
def printPath():
	global chessboard

	i = 0 #循环变量
	PathUnit = [] #逆序存放单路径结点(终点->起点)
	PathUnitList = [] #逆序存放所有路径结点(终点->起点)

	#获取终点的坐标		
	PathUnit = [End_x,End_y];
	print('(%d,%d)'%(PathUnit[0],PathUnit[1])) #输出终点坐标

	#记录从end起第一个最佳路径结点
	PathUnit = [chessboard[End_x][End_y][0][0],chessboard[End_x][End_y][0][1]]

	while not(PathUnit[0] == Start_x and PathUnit[1] == Start_y) #记录从终点到起点之间的最佳路径
		PathUnitList.append(PathUnit) #将PathUnit结点插入PathUnitList列表中
		chessboard[PathUnitList[i][0]][PathUnitList[i][1]][4] = '*' #将最佳路径点用"*"表示
		print('(%d,%d)'%(PathUnitList[i][0],PathUnitList[i][1])) #输出最短路径结点坐标

		#获取当前结点的父结点坐标
		PathUnit = [chessboard[PathUnitList[i].ChessUnit_x][PathUnitList[i].ChessUnit_y][0][0],chessboard[PathUnitList[i].ChessUnit_x][PathUnitList[i].ChessUnit_y][0][1]]
		i+=1
	print('(%d,%d)'%(Start_x,Start_y)) #输出起点坐标

	#打印棋盘及最短路径
	i=0
	while i < chess_size:
	#for (int i = 0; i < chess_size; i++)
		j=0
		while j < chess_size:
			#cout << chessboard[i][j].flag;
			chessboardline.append(chessboard[i][j][4])#将一行数据逐个插入到chessboardline中
			j+=1
		print(chessboardline)#打印一行数据
		i+=1

def main():
	global OpenListPosition
	global CloseListPosition
	global OpenList
	global CloseList

	FileReadMatrix()

	item = [Start_x,Start_y,0]#将起始点x坐标,y坐标,f值封装到列表item中
	OpenList.append(item)#将item插入到Openlist中

	OpenListPosition += 1#将起始结点存入openlist,position标记为1(position总指向最后一个元素的后一位置)

	while OpenListPosition > 0: #若openlist不为空
	
		openListIncraseSort() #openlist列表按f值大小降序排序(将最小f值点放在最后,这样只需将position减1就代表移出该点)
		#将openlist中f值最小的点移入closelist中
		item = [OpenList[OpenListPosition - 1][0],OpenList[OpenListPosition - 1][1]]
		CloseList.append(item)

		#openlist移出f值最小元素,清除原位置该元素信息
		OpenList.pop()#移除openlist中最后的那个元素
		OpenListPosition  -= 1 #将OpenListPosition减1,表示从openlist中移出最后一点,即f值最小的点
		CloseListPosition += 1 #将ClosePosition加1,记录closelist中增加一个元素
		
		#将f最小结点信息插入到CurrentUnit中
		CurrentUnit = [CloseList[CloseListPosition - 1][0],CloseList[CloseListPosition - 1][1]]

		#判断当前结点周围8个点状态,计算g、h、f值,将周围每个点的父指针指向当前结点
		if dealCurrentNeibors(CurrentUnit) == 1:
			break
	#while
	printPath();
	#return 0

main()