游戏算法-寻路算法,从BFS到Dijkstra到AStar,pyhton实现

 一、简单BFS算法

bfs即广度优先搜索,最基础的寻路算法

即向出发点向四周无目的扩散,直到到达终点或者无法扩散为止

# coding: utf-8

import random
import bisect


class Solution(object):
	def __init__(self, n, m, bad):
		self.map = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
					[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
					[0, 1, 1, 1, 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, 1, 0, 0, 0],
					[0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
					[0, 0, 0, 0, 1, 0, 0, 1, 1, 0],
					[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
					[0, 0, 0, 0, 1, 0, 0, 0, 0, 0]]

		# 目的点
		self.end_point = (m - 1, n - 2)
		self.max_x = m
		self.max_y = n

	def show_map(self):
		print("##########start###########")
		for map in self.map:
			print(map)
		print("##########end###########")


	def g_bfs(self):
		visited = set([])
		queue = []
		start = (0, 0)

		queue.append(start)
		while queue:
			point = queue.pop(0)
			point_x, point_y = point
			visited.add(point)
			self.map[point_x][point_y] = 9
			if point == self.end_point:
				return

			for add_x, add_y in ((0, -1), (-1, 0), (1, 0), (0, 1)):
				x = point_x + add_x
				y = point_y + add_y
				if x < 0 or x >= self.max_x:
					continue
				if y < 0 or y >= self.max_y:
					continue
				if self.map[x][y] != 0:
					continue
				if (x, y) in queue:
					continue

				queue.append((x, y))


if __name__ == "__main__":
	s = Solution(10, 10, 40)
	s.show_map()
	s.g_bfs()
	s.show_map()

结果:

9为路径

1为墙

计算点与点之间最短距离有以下三种

分别为:曼哈顿估价法、几何估价法、对角线估价法

接下来的算法遍历点时候,根据点与点距离优先遍历,我们一般采用曼哈顿方法计算

二、Dijkstra

Dijkstra算法是从一个顶点到其余各顶点的最短路径算法,其流程仍然与上述算法基本一致。

但是出发点向四周扩散时候,优先从距离出发点更近的点出发

代价函数f(n)的定义,Dijkstra算的f(n)定义为:

f(n)=g(n)

其中g(n)表示从起点到当前点的移动代价

# coding: utf-8

import random
import bisect


class Solution(object):
	def __init__(self, n, m, bad):
		self.map = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
					[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
					[0, 1, 1, 1, 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, 1, 0, 0, 0],
					[0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
					[0, 0, 0, 0, 1, 0, 0, 1, 1, 0],
					[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
					[0, 0, 0, 0, 1, 0, 0, 0, 0, 0]]

		# 目的点
		self.end_point = (m - 1, n - 2)
		self.max_x = m
		self.max_y = n

	def show_map(self):
		print("##########start###########")
		for map in self.map:
			print(map)
		print("##########end###########")


	def g_bfs(self):
		visited = set([])
		queue = []
		start = (0, 0)

		queue.append(start)
		while queue:
			point = queue.pop(0)
			point_x, point_y = point
			visited.add(point)
			self.map[point_x][point_y] = 9
			if point == self.end_point:
				return

			for add_x, add_y in ((0, -1), (-1, 0), (1, 0), (0, 1)):
				x = point_x + add_x
				y = point_y + add_y
				if x < 0 or x >= self.max_x:
					continue
				if y < 0 or y >= self.max_y:
					continue
				if self.map[x][y] != 0:
					continue
				if (x, y) in queue:
					continue
                    
				queue.append((x, y))

			queue.sort(key=self.manhattan)  # 排序优先距离出发点最短的点,可以不用排序,便历一遍找到对应的点即可

	def manhattan(self, start_point):
		return abs(self.end_point[0] - 0) + abs(self.end_point[1] - 0)


if __name__ == "__main__":
	s = Solution(10, 10, 40)
	s.show_map()
	s.g_bfs()
	s.show_map()

结果:

三、A Star

A Start和目的BFS基本一样,优先遍历点的策略不一样

A*算法在运算过程中,每次从优先队列中选取$f(n)$值最小(优先级最高)的节点作为下一个待遍历的节点。

A*算法的启发公式可表示为:

f∗(n)=g∗(n)+h∗(n)

其中

f*(n) 是从初始状态经由状态n到目标状态的最小代价估计

g*(n) 是在状态空间中从初始状态到状态n的最小代价

h*(n) 是从状态n到目标状态的路径的最小估计代价

(注:对于路径搜索问题,状态就是图中的节点,代价就是距离,即就是到达目标点代价代价最小的点)

# coding: utf-8

import random


class Node(object):
    def __init__(self, point, g, h):
        self.point = point
        self.g = g  # 起点到移动点的代价
        self.h = h  # 移动点到终点的代价

    def __hash__(self):
        return self.point

    def cost(self):
        # 起点到移动点的代价 + 移动点到终点的代价
        return self.g + self.h


class AStar(object):
    def __init__(self, n, m, bad):
        self.map = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
                    [0, 1, 1, 1, 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, 1, 0, 0, 0],
                    [0, 1, 1, 1, 1, 0, 1, 1, 0, 0],
                    [0, 0, 0, 0, 1, 0, 0, 1, 1, 0],
                    [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 1, 0, 0, 0, 0, 0]]

        self.openList = []
        self.closeList = {}

        self.startNode = (0, 0)
        self.endNode = (m - 1, n - 2)
        self.max_x = m
        self.max_y = n

    def show_map(self):
        print("##########start###########")
        for map in self.map:
            print(map)
        print("##########end###########")

    def starAStar(self):
        g = manhattan(self.startNode, self.startNode)
        h = manhattan(self.startNode, self.endNode)
        add_node = Node(self.startNode, g, h)
        self.openList.append(add_node)

        self.closeList[add_node.point] = add_node
        while self.openList:
            node = self.openList.pop(0)
            point_x, point_y = node.point
            self.map[point_x][point_y] = 9

            for add_x, add_y in ((0, -1), (-1, 0), (1, 0), (0, 1)):
                x = point_x + add_x
                y = point_y + add_y
                if x < 0 or x >= self.max_x:
                    continue
                if y < 0 or y >= self.max_y:
                    continue
                if self.map[x][y] != 0:
                    continue
                if (x, y) in self.closeList:
                    continue
                if (x, y) == self.endNode:
                    # 结束
                    return                

                g = manhattan(self.startNode, (x, y))  # 目标状态到初始位置最小代价
                h = manhattan((x, y), self.endNode)  # 目标状态的路径的最小估计代价
                add_node = Node((x, y), g, h)
                self.closeList[add_node.point] = add_node
                self.openList.append(add_node)
            
            self.openList.sort(cmp=cmp_point)  # 优先遍历代价最小的点,可以不排序,直接遍历找到最小代的点


def manhattan(point, end_point):
    # 曼哈顿计算距离
    return abs(point[0] - end_point[0]) + abs(point[1] - end_point[1])


def cmp_point(a, b):
    if a.cost() == b.cost():
        return cmp(a.h, b.h)
    return cmp(a.cost(), b.cost())


if __name__ == "__main__":
    s = AStar(10, 10, 40)
    s.show_map()
    s.starAStar()
    s.show_map()

结果:

推荐一个寻路动态显示网站:PathFinding.js

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值