当前位置 : 主页 > 编程语言 > c语言 >

Matlab利用prim算法实现迷宫的生成

来源:互联网 收集:自由互联 发布时间:2023-02-01
目录 代码使用 迷宫生成 映射图 多起点 完整代码 最近比较忙更新频率也慢了下来,今天带来一个比较有趣的可视化,基于prim算法的迷宫生成并用距离生成图片: 我通过各种向量化编
目录
  • 代码使用
    • 迷宫生成
    • 映射图
    • 多起点
  • 完整代码

    最近比较忙更新频率也慢了下来,今天带来一个比较有趣的可视化,基于prim算法的迷宫生成并用距离生成图片:

    我通过各种向量化编程编写了一个迷宫生成函数,由于代码不是很短因此放在最后面展示代码,以下展示如果将最前面的参数进行改变会有啥效果。

    代码使用

    迷宫生成

    迷宫生成就是用的非常简单的prim算法,大体就是不断的在已经开过门的房间四周随机选择紧挨着的房间,直到所有房间被开过。我的代码编写是专门弄了五个矩阵,一个存已经到过的房间,另外四个分别存上下左右打开过的围墙。

    如果代码最前面的基础信息设置为:

    % 地图基础信息设置
    mazeSize=[30,30];
    SPos=[2,5];
    showMap=true;
    showSurf=false;
    

    就意味着绘制30x30个房间,从第二行第五个房间开始开门,展示迷宫但是不展示距离映射。

    当然设置其他大小和其他起点也可以:

    映射图

    将到起点的距离映射为颜色,只需要将前面的showSurf更改为true:

    % 地图基础信息设置
    mazeSize=[30,30];
    SPos=[2,5];
    showMap=true;
    showSurf=true;
    

    当然如果设置的地图较大,建议将showMap设置为false,不然绘制的太慢了:

    mazeSize=[200,200];
    SPos=[50,50];
    showMap=false;
    showSurf=true;
    

    当然如果把74多行的colormap改成其他颜色,比如pink、bone、turbo、colorcube:

    当然colormap可以自己设置的更复杂:

    % 自定义色带
    if 1
    Cmap=[89,214,179
    140,181,195
    177,156,206
    241,189,239
    215,193,244
    178,199,253
    140,189,234
    145,166,229
    106,85,202]./255;
    Ci=1:size(Cmap,1);Cq=linspace(1,size(Cmap,1),300);
    Cmap=[interp1(Ci,Cmap(:,1),Cq,'linear')',...
         interp1(Ci,Cmap(:,2),Cq,'linear')',...
         interp1(Ci,Cmap(:,3),Cq,'linear')'];
    colormap(Cmap)
    end
    

    多起点

    值得一提的是,多个起点也是支持的!!

    % 地图基础信息设置
    mazeSize=[30,30];
    SPos=[2,5;20,15];
    showMap=true;
    showSurf=true;
    

    依旧可以设置颜色和更大的地图:

    当然不建议将大小设置为300x300以上,???什么玩意这么香????嗷原来是我的电脑!!

    完整代码

    function primMaze
    % @author : slandarer
    % 公众号  : slandarer随笔
    % 知乎    : 已由hikari更名slandarer
    
    % 地图基础信息设置
    mazeSize=[50,50];
    SPos=[2,5];
    showMap=true;
    showSurf=true;
    
    % 初始化可达迷宫及上下左右围墙矩阵
    mazeMat=ones(mazeSize);
    mazeMat(sub2ind(mazeSize,SPos(:,1),SPos(:,2)))=0;
    zerosMat=zeros(mazeSize);
    disMat=zeros(mazeSize);
    [UMat,DMat,LMat,RMat]=...
        deal(ones(mazeSize),ones(mazeSize),ones(mazeSize),ones(mazeSize));
    
    if showMap
        wallHdl=drawMap(UMat,DMat,LMat,RMat);
    end
    
    while any(any(mazeMat))
        % 找到全部已经走到过且周围至少有一个门的房间
        UMazeMat=zerosMat;UMazeMat(2:end,:)=mazeMat(1:end-1,:);
        DMazeMat=zerosMat;DMazeMat(1:end-1,:)=mazeMat(2:end,:);
        LMazeMat=zerosMat;LMazeMat(:,2:end)=mazeMat(:,1:end-1);
        RMazeMat=zerosMat;RMazeMat(:,1:end-1)=mazeMat(:,2:end);
        maze4Mat=UMazeMat+DMazeMat+LMazeMat+RMazeMat;
        [acRow,acCol]=find(mazeMat==0&maze4Mat>0);
        % 随机选择一个当前已经走到过的房间
        tempInd=randi(size(acRow,1),[1,1]);
        tempRow=acRow(tempInd);
        tempCol=acCol(tempInd);
        % 删掉地图外房间位置和不可达房间位置
        nextPos=[tempRow,tempCol]+[-1,0;1,0;0,-1;0,1];
        nextPos(nextPos(:,1)<1,:)=[];
        nextPos(nextPos(:,2)<1,:)=[];
        nextPos(nextPos(:,1)>mazeSize(1),:)=[];
        nextPos(nextPos(:,2)>mazeSize(2),:)=[];
        nextBool=mazeMat(sub2ind(mazeSize,nextPos(:,1),nextPos(:,2)))>0;
        nextPos=nextPos(nextBool,:);
        % 随机选择下一个房间
        nextInd=randi(size(nextPos,1),[1,1]);
        nextRow=nextPos(nextInd,1);
        nextCol=nextPos(nextInd,2);
        mazeMat(nextRow,nextCol)=0;
        disMat(nextRow,nextCol)=disMat(tempRow,tempCol)+1;
        % 打破墙壁
        switch true
            case isequal([nextRow,nextCol]-[tempRow,tempCol],[-1,0])
                UMat(tempRow,tempCol)=0;DMat(nextRow,nextCol)=0;
            case isequal([nextRow,nextCol]-[tempRow,tempCol],[1,0])
                DMat(tempRow,tempCol)=0;UMat(nextRow,nextCol)=0;
            case isequal([nextRow,nextCol]-[tempRow,tempCol],[0,-1])
                LMat(tempRow,tempCol)=0;RMat(nextRow,nextCol)=0;
            case isequal([nextRow,nextCol]-[tempRow,tempCol],[0,1])
                RMat(tempRow,tempCol)=0;LMat(nextRow,nextCol)=0;
        end
        % 用来显示地迷宫的代码
        if showMap
        refreshMap(wallHdl,UMat,DMat,LMat,RMat)
        drawnow
        end
    end
    % =========================================================================
    % 绘制颜色映射图
    if showSurf
    sax=gca;hold on
    [sM,sN]=size(UMat);
    sax.XLim=[0,sN]+.5;
    sax.YLim=[0,sM]+.5;
    sax.DataAspectRatio=[1,1,1];
    surf(flipud(disMat),'EdgeColor','none')
    colormap(pink)
    
    % 自定义色带
    if 0
    Cmap=[89,214,179
    140,181,195
    177,156,206
    241,189,239
    215,193,244
    178,199,253
    140,189,234
    145,166,229
    106,85,202]./255;
    Ci=1:size(Cmap,1);Cq=linspace(1,size(Cmap,1),300);
    Cmap=[interp1(Ci,Cmap(:,1),Cq,'linear')',...
         interp1(Ci,Cmap(:,2),Cq,'linear')',...
         interp1(Ci,Cmap(:,3),Cq,'linear')'];
    colormap(Cmap)
    end
    end
    % =========================================================================
    % CODE: test drawMap
    % UMat(2,3)=0;
    % DMat(1,3)=0;
    % drawMap(UMat,DMat,LMat,RMat)
        function wallHdl=drawMap(UMat,DMat,LMat,RMat)
            ax=gca;hold on
            [M,N]=size(UMat);
            ax.XLim=[0,N]+.5;
            ax.YLim=[0,M]+.5;
            ax.DataAspectRatio=[1,1,1];
            % 绘制上方围墙
            [Y,X]=find(UMat);Y=M+1-Y;
            X=[X.'+[.5;-.5];nan.*(ones(1,length(X)))];
            Y=[Y.'+[.5;.5];nan.*(ones(1,length(Y)))];
            wallHdl{1}=plot(X(:),Y(:),'LineWidth',1,'Color','k');
            % 绘制下方围墙
            [Y,X]=find(DMat);Y=M+1-Y;
            X=[X.'+[.5;-.5];nan.*(ones(1,length(X)))];
            Y=[Y.'+[-.5;-.5];nan.*(ones(1,length(Y)))];
            wallHdl{2}=plot(X(:),Y(:),'LineWidth',1,'Color','k');
            % 绘制左侧围墙
            [Y,X]=find(LMat);Y=M+1-Y;
            X=[X.'+[-.5;-.5];nan.*(ones(1,length(X)))];
            Y=[Y.'+[.5;-.5];nan.*(ones(1,length(Y)))];
            wallHdl{3}=plot(X(:),Y(:),'LineWidth',1,'Color','k');
            % 绘制右侧围墙
            [Y,X]=find(RMat);Y=M+1-Y;
            X=[X.'+[.5;.5];nan.*(ones(1,length(X)))];
            Y=[Y.'+[.5;-.5];nan.*(ones(1,length(Y)))];
            wallHdl{4}=plot(X(:),Y(:),'LineWidth',1,'Color','k');
        end
    % -------------------------------------------------------------------------
        function refreshMap(wallHdl,UMat,DMat,LMat,RMat)
            [M,~]=size(UMat);
            % 绘制上方围墙
            [Y,X]=find(UMat);Y=M+1-Y;
            X=[X.'+[.5;-.5];nan.*(ones(1,length(X)))];
            Y=[Y.'+[.5;.5];nan.*(ones(1,length(Y)))];
            wallHdl{1}.XData=X(:);
            wallHdl{1}.YData=Y(:);
            % 绘制下方围墙
            [Y,X]=find(DMat);Y=M+1-Y;
            X=[X.'+[.5;-.5];nan.*(ones(1,length(X)))];
            Y=[Y.'+[-.5;-.5];nan.*(ones(1,length(Y)))];
            wallHdl{2}.XData=X(:);
            wallHdl{2}.YData=Y(:);
            % 绘制左侧围墙
            [Y,X]=find(LMat);Y=M+1-Y;
            X=[X.'+[-.5;-.5];nan.*(ones(1,length(X)))];
            Y=[Y.'+[.5;-.5];nan.*(ones(1,length(Y)))];
            wallHdl{3}.XData=X(:);
            wallHdl{3}.YData=Y(:);
            % 绘制右侧围墙
            [Y,X]=find(RMat);Y=M+1-Y;
            X=[X.'+[.5;.5];nan.*(ones(1,length(X)))];
            Y=[Y.'+[.5;-.5];nan.*(ones(1,length(Y)))];
            wallHdl{4}.XData=X(:);
            wallHdl{4}.YData=Y(:);
        end
    end

    以上就是Matlab利用prim算法实现迷宫的生成的详细内容,更多关于Matlab prim算法生成迷宫的资料请关注自由互联其它相关文章!

    网友评论