迷宫寻路算法——流水算法

目录

算法前提

算法思路

广度优先算法(BFS)

迷宫灌水

本算法思路

算法实现

算法输出


以下为个人拙见和粗略思考,如有宝贵建议或想法欢迎您留言或私信交流!

  • 算法前提

首先说明,该算法可进行寻路的迷宫样式需要为二维数组形式的迷宫,其中以0表示道路,以1表示墙壁,且路宽为1。如下图1。该图转化为迷宫地图可以看作图2。

                        图1                                                                                        图2

 符合上述条件的迷宫或处理成上述的迷宫便可进行该算法的本种实现。

  • 算法思路

该算法总结经验于广度优先搜索和使用水找出迷宫出路的物理实验。

  • 广度优先算法(BFS)

该算法致力于找出一个迷宫中从A到B的最短路径,思想上是每次寻得一个路口时(第一个路口除外)或走到死路时就返回到上一个路口,并选择另一方向进行探索。这样做的好处在于能尽可能大范围的探索迷宫,以来找到可能的最短路径,但同样的这样的方式带来了更大的计算量和计算时间。其算法的实现和缺点的解决在此不做具体阐述。

  • 迷宫灌水

这是一个物理实验,只要迷宫的大小、密封性等符合条件,由于水的流动性和迷宫死路导致的气压,水就可以从入口进入并找到最短的出迷宫的道路。在这个实验里我们看到的反而是在迷宫气密性不足时水会尽力探索迷宫,并且所有道路都几乎同时探索的特性。水可以找到最短出路的迷宫如下图3。水可能无法顺利找到最短出路如下图4。

                        图3                                                                                       图4

  • 本算法思路

该算法的目的在于能否减少BFS的计算量达到快速并且有效的寻找最短迷宫解的方式,那么水的这种同时流淌探索的特性可以很好的解决,同时再从迷宫的终点开始“注水”,再利用迷宫中0与1的特性,便可以实现。

在这个算法中,水便是迷宫中的某个点距离目标点的走的步数长度,因为道路均为0,可以设目标点为2,则目标点周围上下左右四个内的全部0都赋值为3,代表多一格。再将所有赋为3的点的上下左右的为0的点赋值为4,以此类推,直到赋值进行到起点为止。然后再从起点开始,根据倒序寻找出一条唯一的且最短的迷宫解。

  • 算法实现

import copy

#迷宫
maze= [
   [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1],
[1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1],
[1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1],
[1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1],
[1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1],
[1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1],
[1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1],
[1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1],
[1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1],
[1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1],
[1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1],
[1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1],
[1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1],
[1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1],
[1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,1],
[1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1],
[1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
]
#基础参数设置
start=(19,1)
end=(1,19)
head=['right']
end_h,end_l=end

#迷宫建立
maze_value=copy.deepcopy(maze)
maze_value[end_h][end_l] = 2
list_value_now=[end]
s_h,s_l = start

# print(s_h,s_l)
value = 3 
while True:
    for value_now in list_value_now:
        v_h,v_l=value_now
        # print(v_h,v_l)
        if maze_value[v_h + 1][v_l] == 0:
            maze_value[v_h + 1][v_l] = value
        if maze_value[v_h][v_l - 1] == 0:
            maze_value[v_h][v_l - 1] = value
        if maze_value[v_h][v_l + 1] == 0:
            maze_value[v_h][v_l + 1] = value
        if maze_value[v_h - 1][v_l] == 0:
            maze_value[v_h -1][v_l] = value
    # print(maze_value)
    list_value_now=[]
    
    for i in range(21):
        for j in range(21):
            if maze_value[i][j] == value:
                list_value_now.append((i,j))
    value=value+1
    if maze_value[19][1] !=0:
        break
print("value OK")
# print(maze_value)

list_run=[start]
list_run_crossing=[]
list_run_value=[]

while True:
    now = list_run[-1]
    if now == end:
        print(list_run)
        print(list_run_crossing)
        break
    n_h,n_l = now
    # print(n_h,n_l) 
      
    list_run_value.append(maze_value[n_h - 1][n_l])    
    list_run_value.append(maze_value[n_h][n_l - 1])    
    list_run_value.append(maze_value[n_h + 1][n_l])
    list_run_value.append(maze_value[n_h][n_l + 1])
    # print(list_run_value)
    # print(maze_value[n_h][n_l])
    
    for j in range(4):    
        if list_run_value[j] - maze_value[n_h][n_l] == -1:
            flag_run = j
            
            # print(flag_run)
    list_run_value=[]
    
    if head[-1] == 'right':
        
        if flag_run == 0:
            list_run.append((n_h - 1,n_l))
            head.append('up')
            if maze[n_h][n_l +1] + maze[n_h + 1][n_l] + maze[n_h - 1][n_l] + maze[n_h][n_l-1] <= 1:
                list_run_crossing.append("2")
                
        if flag_run == 1:
            list_run.append((n_h,n_l - 1))
            head.append('left')
            if maze[n_h][n_l +1] + maze[n_h + 1][n_l] + maze[n_h - 1][n_l] + maze[n_h][n_l-1] <= 1:
                list_run_crossing.append("3")
        if flag_run == 2:
            list_run.append((n_h + 1,n_l))
            head.append('down')
            if maze[n_h][n_l +1] + maze[n_h + 1][n_l] + maze[n_h - 1][n_l] + maze[n_h][n_l-1] <= 1:
                list_run_crossing.append("4")
        if flag_run == 3:
            list_run.append((n_h,n_l + 1))
            head.append('right')
            if maze[n_h][n_l +1] + maze[n_h + 1][n_l] + maze[n_h - 1][n_l] + maze[n_h][n_l-1] <= 1:
                list_run_crossing.append("1")
        continue
    if head[-1] == 'up':
        if flag_run == 0:
            list_run.append((n_h - 1,n_l))
            head.append('up')
            if maze[n_h][n_l +1] + maze[n_h + 1][n_l] + maze[n_h - 1][n_l] + maze[n_h][n_l-1] <= 1:
                list_run_crossing.append("1")
        if flag_run == 1:
            list_run.append((n_h,n_l - 1))
            head.append('left')
            if maze[n_h][n_l +1] + maze[n_h + 1][n_l] + maze[n_h - 1][n_l] + maze[n_h][n_l-1] <= 1:
                list_run_crossing.append("2")
        if flag_run == 2:
            list_run.append((n_h + 1,n_l))
            head.append('down')
            if maze[n_h][n_l +1] + maze[n_h + 1][n_l] + maze[n_h - 1][n_l] + maze[n_h][n_l-1] <= 1:
                list_run_crossing.append("3")
        if flag_run == 3:
            list_run.append((n_h,n_l + 1))
            head.append('right')
            if maze[n_h][n_l +1] + maze[n_h + 1][n_l] + maze[n_h - 1][n_l] + maze[n_h][n_l-1] <= 1:
                list_run_crossing.append("4")
        continue
    if head[-1] == 'down':
        if flag_run == 0:
            list_run.append((n_h - 1,n_l))
            head.append('up')
            if maze[n_h][n_l +1] + maze[n_h + 1][n_l] + maze[n_h - 1][n_l] + maze[n_h][n_l-1] <= 1:
                list_run_crossing.append("3")
        if flag_run == 1:
            list_run.append((n_h,n_l - 1))
            head.append('left')
            if maze[n_h][n_l +1] + maze[n_h + 1][n_l] + maze[n_h - 1][n_l] + maze[n_h][n_l-1] <= 1:
                list_run_crossing.append("4")
        if flag_run == 2:
            list_run.append((n_h + 1,n_l))
            head.append('down')
            if maze[n_h][n_l +1] + maze[n_h + 1][n_l] + maze[n_h - 1][n_l] + maze[n_h][n_l-1] <= 1:
                list_run_crossing.append("1")
        if flag_run == 3:
            list_run.append((n_h,n_l + 1))
            head.append('right')
            if maze[n_h][n_l +1] + maze[n_h + 1][n_l] + maze[n_h - 1][n_l] + maze[n_h][n_l-1] <= 1:
                list_run_crossing.append("2")
        continue
    if head[-1] == 'left':
        if flag_run == 0:
            list_run.append((n_h - 1,n_l))
            head.append('up')
            if maze[n_h][n_l +1] + maze[n_h + 1][n_l] + maze[n_h - 1][n_l] + maze[n_h][n_l-1] <= 1:
                list_run_crossing.append("4")
        if flag_run == 1:
            list_run.append((n_h,n_l - 1))
            head.append('left')
            if maze[n_h][n_l +1] + maze[n_h + 1][n_l] + maze[n_h - 1][n_l] + maze[n_h][n_l-1] <= 1:
                list_run_crossing.append("1")
        if flag_run == 2:
            list_run.append((n_h + 1,n_l))
            head.append('down')
            if maze[n_h][n_l +1] + maze[n_h + 1][n_l] + maze[n_h - 1][n_l] + maze[n_h][n_l-1] <= 1:
                list_run_crossing.append("2")
        if flag_run == 3:
            list_run.append((n_h,n_l + 1))
            head.append('right')
            if maze[n_h][n_l +1] + maze[n_h + 1][n_l] + maze[n_h - 1][n_l] + maze[n_h][n_l-1] <= 1:
                list_run_crossing.append("3")
        continue
  • 算法输出

该算法最终可以输出:

1.迷宫解的走法坐标信息2.一个普通小车的迷宫解走法信息(如左转右转)3.一个普通小车在所有拐点(如普通直角转弯、路口)的走法信息。

个人拙见,欢迎留言私信交流。

 图3图4来自:【SteveMould双语】水能自己找到迷宫出口吗?做实验试试吧_哔哩哔哩_bilibili

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值