迷宫算法之递归回溯python实现

目录

没有目录了,别看了。

0. 概要

上一张我们谈到prim算法,这一张我们使用递归回溯算法来实现迷宫算法,相对于随机prim算法,这个算法更容易理解,并且提出的概念相对较小。但原理不太一样,,这也导致两种算法得出的迷宫也存在一定的差异,随机prim算法得到的迷宫随机性更高,如果你自己调试过一两个迷宫,就能发现随机prim迷宫的岔路非常多。相反,递归回溯算法计算出的迷宫直线通路会稍微更多一些,并且长的岔路会较随机prim算法更少一些。但这都不是什么特别重要的事情。

1.算法流程

先大概阐述一下递归回溯的流程。

首先,你需要把一个n*n的地图初始化。初始化的方法是将整个迷宫变为田字格的形式具体你可以参照下图。
0 1 0 1 0
1 1 1 1 1
0 1 0 1 0
1 1 1 1 1
0 1 0 1 0

没错,和上一篇是一样的,至于为什么我一定要先把迷宫做这个样子的规划待会下面会分析道。其中0代表没被访问的路径,1表示没被访问的有效墙。

先了解几个概念:

1:seeker代表当前访问点。

2:未访问路径:表示这个点未被踏足

3:墙:挡住前进路线,这个概念没什么好讲的,于随机prim算法不同,没有什么有效墙的概念,这一篇文章中,墙就是墙。

4:以访问路径,当墙被摧毁和某一个点被访问,都会将他们标记为以访问路径。

由于这是个递归,我实在是不想画流程图了。

关于递归也不进行详细的阐述了,主要就是讲下程序在实际实现的时候的逻辑,有关递归的想法后面可能单独拿出来讲。

首先,我们先要想清楚这个算法要如何实现递归的思想,先大概厘清这么一个概念:这个算法同样适用于找出迷宫路径解,其实相对于找出路径这个功能,没有任何区别。找出路径解的算法核心思想在于,一直随机前进,当遇到一个点没有可访问路径的时候退回上一个格子继续搜索可前进的路线。我们在这里用一个栈的模型来实现,创建一个空的列表,频繁的往里面添加新的被访问的地点,当一个地点无法前进的时候便把这个元素弹出来,继续访问栈顶单元格的可访问路线。直到栈空的时候整个迷宫就创建完成了。

2。数据组织

先规划好待会写程序时候的各种标准

第一点:迷宫最后返回一个numpy库的ndarray类型数组对象。

第二点:标记选择。

0:未访问路径

1:墙就是墙

2:被访问路径,路径被访问和墙背摧毁都会被标记为2.

3实现代码
import numpy as np
import random
import matplotlib.pyplot as plt
import matplotlib.cm as cm


class RecBack:
    def __init__(self):
        self.size = (15, 15)	# 大小
        self.seeker = []		# 当前访问坐标
        self.maze = []			# 迷宫矩阵
        self.createmaze()
	
    # 初始化为田字格
    def initmaze(self):

        # x, y = self.size
        maze = np.zeros(self.size)
        for i in range(self.size[0]):
            for j in range(self.size[1]):
                if i % 2 == 1 or j % 2 == 1:
                    maze[i, j] = 1
        print(maze)
        return maze

    # 初始化创建迷宫的方法
    def createmaze(self):
        self.maze = self.initmaze()
        x = 0
        y = 0
        history = [[x, y]]
        while history:
			
            # 收集当前可行进的路线放在tag中
            self.maze[x, y] = 2
            tag = []
            # left
            if y - 2 >= 0 and self.maze[x, y - 2] == 0:
                tag.append('l')
            # right
            if y + 2 < self.size[1] and self.maze[x, y + 2] == 0:
                tag.append('r')
            # up
            if x - 2 >= 0 and self.maze[x - 2, y] == 0:
                tag.append('u')
            # down
            if x + 2 < self.size[0] and self.maze[x + 2, y] == 0:
                tag.append('d')
                
			# 随机前进、其中history包含你是怎么走过来的
            if len(tag):
                history.append([x, y])
                step = random.choice(tag)
				
                # 给地板画标记
                self.maze[x, y] = 2
                if step == 'l':
                    self.maze[x, y - 1] = 2
                    y = y - 2
                if step == 'r':
                    self.maze[x, y + 1] = 2
                    y = y + 2
                if step == 'd':
                    self.maze[x + 1, y] = 2
                    x = x + 2
                if step == 'u':
                    self.maze[x - 1, y] = 2
                    x = x - 2
            # 当没有可前行的路了就倒退
            else:
                x, y = history.pop()
	
    # 用matplotlib粗略画个图看看
    def dispaly(self):
        plt.imshow(self.maze, cmap=cm.Greys_r, interpolation='none')
        plt.show()

        
recback = RecBack()
recback.dispaly()

说明:和之前的一样,你只需要创建这个类的对象去访问display方法或者自己写个方法调用maze这个成员就可以直接得到一个迷宫的ndarray矩阵,size是大小。这个算法相对于随机prim算法要简单很多,并且把这个模型用栈来实现的话也会非常的简单和容易理解。下面是随便画了个图可以参考一下。
在这里插入图片描述

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值