利用matlab创建与解决迷宫[深度优先、Prim、递归分割、Wilson]

利用matlab创建与解决迷宫[深度优先、Prim、递归分割、Wilson]

本文利用matlab,实现了常见的三种迷宫算法:深度优先算法、Prim算法、递归分割算法,和Wilson算法(Loop-erased random walk)。并通过求解路径,对比三种迷宫不同的特点。

迷宫均为标准网格化的2维迷宫,规定迷宫内只能进行上下左右4个方向进行移动。入口和出口均只有一个。

对于一般迷宫而言,我们要找的是一种连接所有通路,且不存在回路和死路的方法。入口和出口的位置反而是次要的,而且可以在迷宫生成之后再定义。

基于马尔科夫链思想的MarkovJunior方法生成迷宫可见:
利用MarkovJunior方法生成迷宫和图形的MATLAB演示[迷宫生成、贪吃蛇、地图生成、图案生成]

1 深度优先算法

深度优先(递归回溯)算法可以表示为:

1.设置一个起点。将起点作为当前迷宫单元,并标记为已访问
2.当还存在未标记的迷宫单元,进行循环
	1.如果当前迷宫单元有未被访问过的的相邻的迷宫单元
		1.随机选择一个未访问的相邻迷宫单元
		2.将当前迷宫单元入栈
		3.移除当前迷宫单元与相邻迷宫单元的墙
		4.标记相邻迷宫单元已访问,并用它作为当前迷宫单元
	2.如果当前迷宫单元不存在未访问的相邻迷宫单元,并且栈不空
		1.栈顶的迷宫单元出栈
		2.令其成为当前迷宫单元

大概思路是先随机走,如果走不通了,则保存路径。之后逐步后退,直到能继续随机走。最终走完所有格点,则停止程序。
具体过程可以参考下面动图:
在这里插入图片描述

matlab的实现的代码为:

% 深度优先算法
clear
clc

%初始迷宫
X=8;
Y=8;
Maze=zeros(2*Y+1,2*X+1);
Maze(2:2:end-1,2:2:end-1)=1;%1代表不是墙wall,可以行走的区域room


%未访问
R_n=1:X*Y;
%已访问
R_y=[];
%临时栈
R_t=[];

%定义起点
R_Start=1;
R_Now=R_Start;%将起点作为当前迷宫单元
R_y=[R_y,R_Start];%标记已访问
R_n(R_n==R_Start)=[];%删除未访问


while ~isempty(R_n)
%当还存在未标记的迷宫单元,进行循环
    
    R_N_Beside=R_Not_Beside(X,Y,R_Now,R_n);
    if ~isempty(R_N_Beside)
    %如果当前迷宫单元有未被访问过的的相邻的迷宫单元
        %随机选择一个未访问的相邻迷宫单元
        R_N_Beside_Ri=R_N_Beside(randi(length(R_N_Beside)));
        %将当前迷宫单元入栈
        if ismember(R_Now,R_t)
            Ri=find(R_t==R_Now);
            R_t([Ri,length(R_t)])=R_t([length(R_t),Ri]);
        else
            R_t=[R_t;R_Now];
        end
        
        %移除当前迷宫单元与相邻迷宫单元的墙
        Maze_Sub_New=Move_R1_R2_Wall(X,Y,R_N_Beside_Ri,R_Now);
        Maze(Maze_Sub_New(1),Maze_Sub_New(2))=1;
        %标记相邻迷宫单元并用它作为当前迷宫单元
        R_y=[R_y,R_N_Beside_Ri];%加入已访问
        R_n(R_n==R_N_Beside_Ri)=[];%删除未访问
        R_Now=R_N_Beside_Ri;
        
    elseif ~isempty(R_t)
    %如果当前迷宫单元不存在未访问的相邻迷宫单元,并且栈不空
        %栈顶的迷宫单元出栈,令其成为当前迷宫单元
        R_Now=R_t(end);
        R_t(end)=[];
    end
    

end

%定义终点
Maze(end,end-1)=1;
Maze(1,2)=1;%把起点的墙挖开

figure(1)
imagesc(Maze)
figure(2)
DrawMaze(Maze,1,3)





%记录当前迷宫单元有未被访问过的的相邻的迷宫单元
function R_N_Beside=R_Not_Beside(X,Y,R_Now,R_n)
[I,J] = ind2sub([Y,X],R_Now);
P4=zeros(4,2);
P4(1,:)=[I-1,J];%上
P4(2,:)=[I+1,J];%下
P4(3,:)=[I,J-1];%左
P4(4,:)=[I,J+1];%右

R_N_Beside=[];
for k=1:4
    %对相邻的边依次循环
    
    if (~all(P4(k,:))) || (P4(k,1)==Y+1) || (P4(k,2)==X+1)
        %如果超出边界,跳过
        continue
    else
        R_temp=sub2ind([Y,X],P4(k,1),P4(k,2));
        if ismember(R_temp,R_n)
        %如果该单元属于未被访问过
            R_N_Beside=[R_N_Beside;R_temp];
        end
    end
end


end

function Maze_Sub_New=Move_R1_R2_Wall(X,Y,R1,R2)
[I1,J1]=ind2sub([Y,X],R1);
[I2,J2]=ind2sub([Y,X],R2);

Maze_Sub_New=[0,0];

if I1==I2
    Maze_Sub_New=[2*I1,2*min(J1,J2)+1];
elseif J1==J2
    Maze_Sub_New=[2*min(I1,I2)+1,2*J1];
end

end

function DrawMaze(Maze,Wall_Width,Room_Width)
[I,J]=size(Maze);
Y=(I-1)/2;
X=(J-1)/2;

%先,列方向
Maze_New1=zeros(Y*Room_Width+(Y+1)*Wall_Width,J);

%最开始
t=1;
Maze_New1(t:t+Wall_Width-1,:)=repmat(Maze(1,:),Wall_Width,1);
t=t+Wall_Width;
for k=1:Y
    %先Room行
    Maze_New1(t:t+Room_Width-1,:)=repmat(Maze(2*k,:),Room_Width,1);
    t=t+Room_Width;
    %后Wall行
    Maze_New1(t:t+Wall_Width-1,:)=repmat(Maze(2*k+1,:),Wall_Width,1);
    t=t+Wall_Width;
end

%后,行方向
Maze_New2=zeros(Y*Room_Width+(Y+1)*Wall_Width,X*Room_Width+(X+1)*Wall_Width);
%最开始
t=1;
Maze_New2(:,t:t+Wall_Width-1)=repmat(Maze_New1(:,1),1,Wall_Width);
t=t+Wall_Width;
for k=1:X
    %先Room行
    Maze_New2(:,t:t+Room_Width-1)=repmat(Maze_New1(:,2*k),1,Room_Width);
    t=t+Room_Width;
    %后Wall行
    Maze_New2(:,t:t+Wall_Width-1)=repmat(Maze_New1(:,2*k+1),1,Wall_Width);
    t=t+Wall_Width;
end


colormap(gray)
imagesc(Maze_New2)
axis equal
axis off
end

迷宫求解算法采用最普通的搜索路径方法,遇到死胡同则后退继续前进。

%求解迷宫
M_In=[2,2];%迷宫入口
M_Out=[2*Y,2*X];%迷宫出口
k=0;
M_Now=M_In;%起始点
Maze_S=Maze;%定义求解迷宫
Maze_S(1,:)=0;Maze_S(:,1)=0;Maze_S(:,end)=0;Maze_S(end,
  • 9
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值