利用MarkovJunior方法生成迷宫和图形的MATLAB演示[迷宫生成、贪吃蛇、地图生成、图案生成]

news2024/10/7 20:32:05

利用MarkovJunior方法生成迷宫和图形的MATLAB演示[迷宫生成、贪吃蛇、地图生成、图案生成]

  • 0 前言
  • 1 介绍MarkovJunior
  • 2 迷宫生成
    • 2.1 深度优先迷宫生成
    • 2.2 广度优先迷宫生成
  • 3 其它生成图案
    • 3.1 地牢地图
    • 3.2 贪吃蛇
    • 3.3 植物花

惯例声明:本人没有相关的工程应用经验,只是纯粹对相关算法感兴趣才写此博客。所以如果有错误,欢迎在评论区指正,不胜感激。本文主要关注于算法的实现,对于实际应用等问题本人没有任何经验,所以也不再涉及。

0 前言

MarkovJunior号称是一个概率编程语言,基于马尔科夫算法来生成各种图形结构。

本文根据其思想,利用MATLAB实现了其中的部分示例。

如果对其它迷宫算法感兴趣的,可参见:
利用matlab创建与解决迷宫[深度优先、Prim、递归分割、Wilson]
https://blog.csdn.net/weixin_42943114/article/details/104172146

本文参考:
[1] mxgmn / MarkovJunio - github
https://github.com/mxgmn/MarkovJunior
[2] 1行代码生成随机迷宫,这个概率编程语言登GitHub热榜,作者曾开发著名WFC算法
https://zhuanlan.zhihu.com/p/525217024?utm_id=0

1 介绍MarkovJunior

MarkovJunior会根据一系列的规则,来进行图形的生成。常见规则为替换,比如将某个像素点替换成另一个像素点,或者将某个图案(像素块)替换为另一个大小相同图案。

这种像素的替换是随机的,所以生成的图案通常是随机图案,具有无限的可能。

不同规则之间还有各种逻辑关系,常见的为:
1当执行完上面规则后,再执行下一条规则
2当上面规则无解时,执行下一条规则
3与其它几条规则一起,随机选择一条规则进行执行

有了这些规则,就可以生成复杂而又实用的随机图案。

下图给出了用MarkovJunior生成的一些示例:
请添加图片描述
实际MarkovJunior的语言给的非常的简洁,但是核心部分查找像素、替换像素、以及逻辑和循环部分。这些功能在matlab中都可以

2 迷宫生成

首先搞两个简单的迷宫生成算法。

2.1 深度优先迷宫生成

深度优先迷宫算法的思路为规划一条路到头,如果生成不下去了,再后退开辟另一条路。和下面2.2节介绍的广度优先算法比,由于其追求单条路径的深度,所以通常每条路径都很长,分岔较少。

对于MarkovJunior语言,深度优先迷宫算法规则只有两个:一个是前进,将迷宫中的’兰蓝蓝’替换为’绿绿兰’;另一个是后退,将迷宫中的’绿绿兰’替换为绿黄黄’。

比如下图,初始定义一个绿点,然后根据规则1就可以一直延伸下去路径。

请添加图片描述

但是如果遇到走不通的地方,就需要根据规则2进行后退。等到后退到可以执行规则1时,便继续执行规则1。

请添加图片描述
最终当迷宫全部被黄色填满,规则1和规则2都无法执行时,便结束。最终生成的迷宫如下:

请添加图片描述迷宫生成的动图如下:
请添加图片描述

对应的MATLAB代码见下。其实实际代码很短,大部分都是逻辑的while、if之类的代码和绘图代码。主要的查找和替换代码打包成function函数即可。

clear
clc
close all
%MarkovJunior算法-模拟深度优先算法
%初始迷宫
X=20;
Y=20;
Maze=uint8(zeros(2*Y+1,2*X+1));
SizeMaze=size(Maze);
Maze(2,2)=1;%1代表不是墙wall,可以行走的区域room

%1优先:检测迷宫中的[1,0,0],替换为[2,2,1]。2次优先:检测迷宫中的[1,2,2],替换为[3,3,1]
figure(1)
imagesc(Maze)
caxis([0,3])
axis off
pause(0.01)

while true
    %检测
    %生成4个方向,然后随机排序4个,匹配检测
    Block1=[1,0,0];Block2=[2,2,1];
    [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
    if isempty(indx_k)
        Block1=[1,2,2];Block2=[3,3,1];
        [indx_k,Block_Dir]=FindBlock2(Maze,[1,2,2]);
        if isempty(indx_k)
            break
        end
    end
    %然后按照序号进行替换
    Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
    %绘图
    figure(1)
    imagesc(Maze)
    caxis([0,3])
    axis off
    pause(0.01)

end

%后置函数
function Mat=ReplaceBlock(Mat,indx,Block,Block_Dir)
%根据索引替换
Block_k=rot90(Block,Block_Dir);
Size_Mat=size(Mat);
Size_Block=size(Block_k);
[Mr,Mc]=ind2sub(Size_Mat,indx);
Mat(Mr:Mr+Size_Block(1)-1,Mc:Mc+Size_Block(2)-1)=Block_k;
end


function [indx_Rand,Block_Dir]=FindBlock2(Mat,Block)
%根据Block找到Mat矩阵中的索引。
%2维空间中Block会随机旋转
%找到所有,然后随机选择一个。

Block1=Block;
Block2=rot90(Block,1);
Block3=rot90(Block,2);
Block4=rot90(Block,3);

indx1=FindBlockSame(Mat,Block1);
indx2=FindBlockSame(Mat,Block2);
indx3=FindBlockSame(Mat,Block3);
indx4=FindBlockSame(Mat,Block4);

%随机一个
RandIndx=[[indx1,0*ones(size(indx1,1),1)];
    [indx2,1*ones(size(indx2,1),1)];
    [indx3,2*ones(size(indx3,1),1)];
    [indx4,3*ones(size(indx4,1),1)];
    ];
N_Rand=size(RandIndx,1);
if isempty(RandIndx)
    indx_Rand=[];Block_Dir=[];
else
    Rand_i=randi(N_Rand,1);
    indx_Rand=RandIndx(Rand_i,1);
    Block_Dir=RandIndx(Rand_i,2);
end
end

function indx=FindBlockSame(Mat,Block)
%查找Block相同部分的Mat,所在位置
Size_Mat=size(Mat);
Size_Block=size(Block);
Block_indx=zeros(Size_Mat);
for kr=1:Size_Mat(1)-Size_Block(1)+1
    for kc=1:Size_Mat(2)-Size_Block(2)+1
        Mat_k=Mat(kr:kr+Size_Block(1)-1,kc:kc+Size_Block(2)-1);
        IsSame=isequal(Mat_k,Block);
        if IsSame
            Block_indx(kr,kc)=1;
        end
    end
end
indx=find(Block_indx);
end

2.2 广度优先迷宫生成

广度优先则是在路径规划时,在各个可能的分岔口都尽量分岔,最终用分岔填满整个空间。和深度优先迷宫算法相比,其分岔多,但是每个分岔路径都很短,迷宫最终解法的路径长度也通常较短。

对于MarkovJunior语言,广度优先迷宫算法规则只有一个,就是前进并添加节点,将’兰蓝蓝’替换为’兰黄兰’。
请添加图片描述
最终生成的迷宫如下:
请添加图片描述
MATLAB代码如下:

clear
clc
close all
%MarkovJunior算法-模拟广度优先算法
%初始迷宫
X=15;
Y=15;
Maze=uint8(zeros(2*Y+1,2*X+1));
SizeMaze=size(Maze);
Maze(2,2)=1;%1代表不是墙wall,可以行走的区域room

figure(1)
imagesc(Maze)
caxis([0,3])
axis off
pause(0.01)

%1优先:检测迷宫中的[1,0,0],替换为[1,2,1]。
while true
    %检测
    %生成4个方向,然后随机排序4个,匹配检测
    Block1=[1,0,0];Block2=[1,2,1];
    [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
    if isempty(indx_k)
        break
    end
    %然后按照序号进行替换
    Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
    figure(1)
    imagesc(Maze)
    caxis([0,2])
    pause(0.01)
end

Maze(Maze>1)=1;
figure(1)
imagesc(Maze)
caxis([0,2])
pause(0.01)

figure(2)
Maze2=Maze;Maze(Maze>1)=1;
imagesc(Maze)

%% 后置函数
function Mat=ReplaceBlock(Mat,indx,Block,Block_Dir)
%根据索引替换
Block_k=rot90(Block,Block_Dir);
Size_Mat=size(Mat);
Size_Block=size(Block_k);
[Mr,Mc]=ind2sub(Size_Mat,indx);
Mat(Mr:Mr+Size_Block(1)-1,Mc:Mc+Size_Block(2)-1)=Block_k;
end

function [indx_Rand,Block_Dir]=FindBlock2(Mat,Block)
%根据Block找到Mat矩阵中的索引。
%2维空间中Block会随机旋转
%找到所有,然后随机选择一个。
Block1=Block;
Block2=rot90(Block,1);
Block3=rot90(Block,2);
Block4=rot90(Block,3);

indx1=FindBlockSame(Mat,Block1);
indx2=FindBlockSame(Mat,Block2);
indx3=FindBlockSame(Mat,Block3);
indx4=FindBlockSame(Mat,Block4);

%随机一个
RandIndx=[[indx1,0*ones(size(indx1,1),1)];
    [indx2,1*ones(size(indx2,1),1)];
    [indx3,2*ones(size(indx3,1),1)];
    [indx4,3*ones(size(indx4,1),1)];
    ];
N_Rand=size(RandIndx,1);
if isempty(RandIndx)
    indx_Rand=[];Block_Dir=[];
else
    Rand_i=randi(N_Rand,1);
    indx_Rand=RandIndx(Rand_i,1);
    Block_Dir=RandIndx(Rand_i,2);
end
end

function indx=FindBlockSame(Mat,Block)
%查找Block相同部分的Mat,所在位置
Size_Mat=size(Mat);
Size_Block=size(Block);
Block_indx=zeros(Size_Mat);
for kr=1:Size_Mat(1)-Size_Block(1)+1
    for kc=1:Size_Mat(2)-Size_Block(2)+1
        Mat_k=Mat(kr:kr+Size_Block(1)-1,kc:kc+Size_Block(2)-1);
        IsSame=isequal(Mat_k,Block);
        if IsSame
            Block_indx(kr,kc)=1;
        end
    end
end
indx=find(Block_indx);
end

3 其它生成图案

3.1 地牢地图

地牢地图的MarkovJunior规则见下图,图左侧为生成规则表,代表每个规则的先后顺序以及执行条件。
请添加图片描述
利用MATLAB最终实现的效果如下:
请添加图片描述

MATLAB代码见下面。这里由于规则非常多,所以对于的代码明显要比之前更长。

clear
clc
close all
rng(12)
%MarkovJunior算法-NystromDungeon
%初始迷宫
X=20;
Y=20;
Maze=uint8(zeros(2*Y+1,2*X+1));
SizeMaze=size(Maze);
Maze(2,2)=1;%1代表不是墙wall,可以行走的区域room
colormap([0,0,0;0.4,0.1,0.1;1,1,1;0,1,0;1,0,0])

figure(1)
imagesc(Maze)
caxis([0,4])
axis off
pause(0.01)

%1检测迷宫中的[1,0,0],替换为[1,2,1]
while true
    Block1=[1,0,0];Block2=[1,0,1];
    [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
    if isempty(indx_k)
        break
    end
    %然后按照序号进行替换
    Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
end
%2生成房间
while true
    Block1=zeros(9,11);Block1(1:2:end,1:2:end)=1;
    Block2=2*ones(9,11);
    [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
    if isempty(indx_k)
        break
    end
    %然后按照序号进行替换
    Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
    figure(1)
    imagesc(Maze)
    caxis([0,4])
    pause(0.01)
end
%3生成路径
%[4,0,1]替换为[3,3,4];[3,3,4]替换为[4,2,2];[1]替换为[4]
t=0;
while true
    Block1=[4,0,1];Block2=[3,3,4];
    [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
    if isempty(indx_k)
        Block1=[3,3,4];Block2=[4,2,2];
        [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
        if isempty(indx_k)
            Block1=[1];Block2=[4];
            [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
            if isempty(indx_k)
                break
            end
        end
    end
    %然后按照序号进行替换
    Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);

    figure(1)
    imagesc(Maze)
    caxis([0,4])
    pause(0.01)
    t=t+1;
end
%4删除指引点
Block1=[4];Block2=[3];
[indx_k,Block_Dir]=FindBlock2(Maze,Block1);
%然后按照序号进行替换
Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
while true
    Block1=[4];Block2=[2];
    [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
    if isempty(indx_k)
        break
    end
    %然后按照序号进行替换
    Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
    figure(1)
    imagesc(Maze)
    caxis([0,4])
    pause(0.01)
end
%5打上格点
while true
    Block1=[3,2,2];Block2=[3,2,3];
    [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
    if isempty(indx_k)
        Block1=[3,0,2];Block2=[3,2,3];
        [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
        if isempty(indx_k)
            break
        end
    end
    %然后按照序号进行替换
    Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
    figure(1)
    imagesc(Maze)
    caxis([0,4])
    pause(0.01)
end
%6开放一些路径
for k=1:3
    Block1=[3,0,3];Block2=[3,2,3];
    [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
    if isempty(indx_k)
        break
    end
    %然后按照序号进行替换
    Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
    figure(1)
    imagesc(Maze)
    caxis([0,4])
    pause(0.01)
end
while true
    Block1=[3];Block2=[2];
    [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
    if isempty(indx_k)
        break
    end
    %然后按照序号进行替换
    Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
end
figure(1)
imagesc(Maze)
caxis([0,4])
pause(0.01)

%7删除分支小路
while true
    Block1=[0,0,0;0,2,0];Block2=[0,0,0;0,0,0];
    [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
    if isempty(indx_k)
        break
    end
    %然后按照序号进行替换
    Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
    figure(1)
    imagesc(Maze)
    caxis([0,4])
    pause(0.01) 
end

figure(1)
imagesc(Maze)
caxis([0,4])
pause(0.01)

figure(2)
Maze2=Maze;Maze(Maze>1)=1;
imagesc(Maze)

%% 后置函数
function Mat=ReplaceBlock(Mat,indx,Block,Block_Dir)
%根据索引替换
Block_k=rot90(Block,Block_Dir);
Size_Mat=size(Mat);
Size_Block=size(Block_k);
[Mr,Mc]=ind2sub(Size_Mat,indx);
Mat(Mr:Mr+Size_Block(1)-1,Mc:Mc+Size_Block(2)-1)=Block_k;
end

function [indx_Rand,Block_Dir]=FindBlock2(Mat,Block)
%根据Block找到Mat矩阵中的索引。
%2维空间中Block会随机旋转
%找到所有,然后随机选择一个。
Block1=Block;
Block2=rot90(Block,1);
Block3=rot90(Block,2);
Block4=rot90(Block,3);

indx1=FindBlockSame(Mat,Block1);
indx2=FindBlockSame(Mat,Block2);
indx3=FindBlockSame(Mat,Block3);
indx4=FindBlockSame(Mat,Block4);
%随机一个
RandIndx=[[indx1,0*ones(size(indx1,1),1)];
    [indx2,1*ones(size(indx2,1),1)];
    [indx3,2*ones(size(indx3,1),1)];
    [indx4,3*ones(size(indx4,1),1)];
    ];
N_Rand=size(RandIndx,1);
if isempty(RandIndx)
    indx_Rand=[];Block_Dir=[];
else
    Rand_i=randi(N_Rand,1);
    indx_Rand=RandIndx(Rand_i,1);
    Block_Dir=RandIndx(Rand_i,2);
end
end

function indx=FindBlockSame(Mat,Block)
%查找Block相同部分的Mat,所在位置
Size_Mat=size(Mat);
Size_Block=size(Block);
Block_indx=zeros(Size_Mat);
for kr=1:Size_Mat(1)-Size_Block(1)+1
    for kc=1:Size_Mat(2)-Size_Block(2)+1
        Mat_k=Mat(kr:kr+Size_Block(1)-1,kc:kc+Size_Block(2)-1);
        IsSame=isequal(Mat_k,Block);
        if IsSame
            Block_indx(kr,kc)=1;
        end
    end
end
indx=find(Block_indx);
end

3.2 贪吃蛇

MarkovJunior不仅可以生成静态的地图,还可以运行贪吃蛇,同样规则并不太多,规则见下图,图左侧为生成规则表,代表每个规则的先后顺序以及执行条件。
请添加图片描述
利用MATLAB最终实现的效果如下:

请添加图片描述

实现代码见下。
这里其实不是所有随机情况都能成功吃掉所有食物,因为每次蛇的运行路径是随机的,不能控制,所以也存在自己把自己围到角里无法下一步的情况。

clear
clc
close all
%MarkovJunior算法-贪吃蛇
%有概率死掉,不是必胜方法
rng(3)
X=9;
Y=9;
Maze=uint8(zeros(2*Y+1,2*X+1));
SizeMaze=size(Maze);
Maze(2,2)=1;%1代表空Room
Maze(2*randi([2,X-1],1),2*randi([2,Y-1],1))=2;%2代表得分点

mcp=[0,0,0;0.7,0.7,0.3;1,1,1;0,1,0;1,0,0;1,0,1];%黑灰白绿红紫
colormap(mcp);Ncolor=size(mcp,1);

figure(1)
imagesc(Maze)
caxis([0,3])
axis off
pause(0.01)

%1生成网格点。检测迷宫中的[1,0,0],替换为[1,2,1]。
while true
    Block1=[1,0,0];Block2=[1,0,1];
    [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
    if isempty(indx_k)
        break
    end
    %然后按照序号进行替换
    Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
end
figure(1)
imagesc(Maze);caxis([0,Ncolor-1]);pause(0.01)

%2生成蛇。
while true
    Block1=[2,0,1];Block2=[5,3,4];
    [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
    if isempty(indx_k)
        break
    end
    %然后按照序号进行替换
    Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
end
for k=1:2
    Block1=[4,0,1];Block2=[3,3,4];
    [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
    if isempty(indx_k)
        break
    end
    %然后按照序号进行替换
    Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
    figure(1)
    imagesc(Maze);caxis([0,Ncolor-1]);pause(0.01)
end
%2生成计分点
for k=1:10
    Block1=[1];Block2=[2];
    [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
    if isempty(indx_k)
        break
    end
    %然后按照序号进行替换
    Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
end
figure(1)
imagesc(Maze);caxis([0,Ncolor-1]);pause(0.01)

%3贪吃蛇运动
for k=1:100
    %吃计分点
    Block1=[4,0,2];Block2=[3,3,4];
    [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
    if isempty(indx_k)
        %向前进一格
        Block1=[4,0,1];Block2=[3,3,4];
        [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
        if isempty(indx_k)
            break
        else
            Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
            Block1=[5,3,3];Block2=[1,0,5];
            [indx_k,Block_Dir]=FindBlock2(Maze,Block1);
            Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
        end
    else
        Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
    end
    
    figure(1)
    imagesc(Maze);caxis([0,Ncolor-1]);pause(0.01)
end

figure(1)
imagesc(Maze)
caxis([0,Ncolor-1])
pause(0.01)

%% 后置函数
function Mat=ReplaceBlock(Mat,indx,Block,Block_Dir)
%根据索引替换
Block_k=rot90(Block,Block_Dir);
Size_Mat=size(Mat);
Size_Block=size(Block_k);
[Mr,Mc]=ind2sub(Size_Mat,indx);
Mat(Mr:Mr+Size_Block(1)-1,Mc:Mc+Size_Block(2)-1)=Block_k;
end

function [indx_Rand,Block_Dir]=FindBlock2(Mat,Block)
%根据Block找到Mat矩阵中的索引。
%2维空间中Block会随机旋转
%找到所有,然后随机选择一个。
Block1=Block;
Block2=rot90(Block,1);
Block3=rot90(Block,2);
Block4=rot90(Block,3);

indx1=FindBlockSame(Mat,Block1);
indx2=FindBlockSame(Mat,Block2);
indx3=FindBlockSame(Mat,Block3);
indx4=FindBlockSame(Mat,Block4);
%随机一个
RandIndx=[[indx1,0*ones(size(indx1,1),1)];
    [indx2,1*ones(size(indx2,1),1)];
    [indx3,2*ones(size(indx3,1),1)];
    [indx4,3*ones(size(indx4,1),1)];
    ];
N_Rand=size(RandIndx,1);
if isempty(RandIndx)
    indx_Rand=[];Block_Dir=[];
else
    Rand_i=randi(N_Rand,1);
    indx_Rand=RandIndx(Rand_i,1);
    Block_Dir=RandIndx(Rand_i,2);
end
end

function indx=FindBlockSame(Mat,Block)
%查找Block相同部分的Mat,所在位置
Size_Mat=size(Mat);
Size_Block=size(Block);
Block_indx=zeros(Size_Mat);
for kr=1:Size_Mat(1)-Size_Block(1)+1
    for kc=1:Size_Mat(2)-Size_Block(2)+1
        Mat_k=Mat(kr:kr+Size_Block(1)-1,kc:kc+Size_Block(2)-1);
        IsSame=isequal(Mat_k,Block);
        if IsSame
            Block_indx(kr,kc)=1;
        end
    end
end
indx=find(Block_indx);
end

3.3 植物花

地牢地图的MarkovJunior规则见下图,图左侧为生成规则表,代表每个规则的先后顺序以及执行条件。请添加图片描述

MATLAB运行的效果如下:
请添加图片描述

这里由于查找和替换的图形不是正方的矩形,而是其它形状的图形,所以后置函数和前面的代码有所改动。这里引入了nan来删除非矩形形状的图形的非像素点,然后用isequaln来进行判断。

而且这里和之前不同,也不涉及匹配图形的旋转,所以关于旋转角度也做了一些函数修改。

最终实现代码见下。

clear
clc
close all
%MarkovJunior算法-花
rng(3)
X=30;
Y=60;
Draw=zeros(Y,X);
SizeMaze=size(Draw);
Draw(Y-1:Y,:)=1;%1代表土地
Draw(Y-2,:)=2;%2代表绿地

mcp=[0.39,0.98,0.96;0.65,0.50,0.25;
    0.67,0.99,0.38;0.09,0.59,0.17;
    0.9,0,0;1,1,0];%蓝褐绿墨红黄
colormap(mcp);Ncolor=size(mcp,1);

figure(1)
imagesc(Draw)
caxis([0,5])
set(gcf,'Position',[713,342,335,420])
axis off
pause(0.01)

while true
    %生成叶子,生成方式由下面四种方式共同决定
    %Rand_k=randi([1,4],1);
    Rand_k = randperm(5);
    for k1=1:5
    switch Rand_k(k1)
        case 1 %直线生长
            Block1=[0,0,0;0,0,0;0,4,0];
            Block2=[nan,nan,nan;nan,4,nan;nan,3,nan];
        case 2 %斜向生长
            Block1=[0,0,0;0,0,0;0,0,0;4,0,0;nan,nan,0];
            Block2=[nan,nan,nan;nan,4,nan;nan,3,nan;3,3,nan;nan,nan,nan];
        case 3 %斜向生长
            Block1=[0,0,0;0,0,0;0,0,0;0,0,4;0,nan,nan];
            Block2=[nan,nan,nan;nan,4,nan;nan,3,nan;nan,3,3;nan,nan,nan];
        case 4 %双斜向生长
            Block1=[0,0,0,0,0;0,0,0,0,0;0,0,0,0,0;0,0,4,0,0;0,nan,nan,nan,0];
            Block2=[0,0,0,0,0;0,4,0,4,0;0,3,0,3,0;0,3,3,3,0;nan,nan,nan,nan,nan];
        case 5 %开花
            Block1=[0,0,0;0,4,0;0,3,0;0,3,0];
            Block2=[0,5,0;5,3,5;0,5,0;nan,nan,nan];
    end
    [indx_k,Block_Dir]=FindBlock2(Draw,Block1);
    if ~isempty(indx_k)
        break
    end
    end
    %如果没有树枝,就再从地里长一根
    if isempty(indx_k)
        Block1=[0,0,0,0,0;0,0,0,0,0;0,0,0,0,0;2,2,2,2,2;1,1,1,1,1];
        Block2=[0,0,0,0,0;0,0,4,0,0;0,0,3,0,0;2,2,3,2,2;1,1,3,1,1];
        [indx_k,Block_Dir]=FindBlock2(Draw,Block1);
        if isempty(indx_k)
            break
        end
    end
    %然后按照序号进行替换
    Draw=ReplaceBlock(Draw,indx_k,Block2,Block_Dir);
    figure(1)
    imagesc(Draw)
    caxis([0,Ncolor-1]);set(gcf,'Position',[713,342,335,420]);axis off;pause(0.01)

end
%其余的都开花
while true
    Block1=[nan,nan,nan;nan,4,nan;nan,nan,nan];
    Block2=[nan,5,nan;5,3,5;nan,5,nan];
    [indx_k,Block_Dir]=FindBlock2(Draw,Block1);
    if isempty(indx_k)
        break
    end
    Draw=ReplaceBlock(Draw,indx_k,Block2,Block_Dir);

    figure(1)
    imagesc(Draw);caxis([0,Ncolor-1]);axis off;pause(0.01)
end

figure(1)
imagesc(Draw);caxis([0,Ncolor-1]);axis off;pause(0.01)


%% 后置函数 和上面几个后置函数相比有所改动
function Mat=ReplaceBlock(Mat,indx,Block,Block_Dir)
%根据索引替换
Block_k=rot90(Block,Block_Dir);
Size_Mat=size(Mat);
Size_Block=size(Block_k);
[Mr,Mc]=ind2sub(Size_Mat,indx);
Mat_k=Mat(Mr:Mr+Size_Block(1)-1,Mc:Mc+Size_Block(2)-1);
%如果Block含有nan,则不替换
indx_nan=~isnan(Block_k);
Mat_k(indx_nan)=Block_k(indx_nan);
Mat(Mr:Mr+Size_Block(1)-1,Mc:Mc+Size_Block(2)-1)=Mat_k;
end


function [indx_Rand,Block_Dir]=FindBlock2(Mat,Block)
%根据Block找到Mat矩阵中的索引。
%2维空间中Block会随机旋转
%找到所有,然后随机选择一个。

%这里不需要旋转了,改动了一下

Block1=Block;

indx1=FindBlockSame(Mat,Block1);
RandIndx=[indx1,0*ones(size(indx1,1),1)];
N_Rand=size(RandIndx,1);
if isempty(RandIndx)
    indx_Rand=[];Block_Dir=[];
else
    Rand_i=randi(N_Rand,1);
    indx_Rand=RandIndx(Rand_i,1);
    Block_Dir=RandIndx(Rand_i,2);
end
end

function indx=FindBlockSame(Mat,Block)
%查找Block相同部分的Mat,所在位置
Size_Mat=size(Mat);
Size_Block=size(Block);
Block_indx=zeros(Size_Mat);
for kr=1:Size_Mat(1)-Size_Block(1)+1
    for kc=1:Size_Mat(2)-Size_Block(2)+1
        Mat_k=Mat(kr:kr+Size_Block(1)-1,kc:kc+Size_Block(2)-1);
        Mat_k(isnan(Block))=nan;%如果输入的Block里有nan的,也把对应比对位置替换为nan
        IsSame=isequaln(Mat_k,Block);
        if IsSame
            Block_indx(kr,kc)=1;
        end
    end
end
indx=find(Block_indx);
end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/956686.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python爬虫抓取经过JS加密的API数据的实现步骤

随着互联网的快速发展,越来越多的网站和应用程序提供了API接口,方便开发者获取数据。然而,为了保护数据的安全性和防止漏洞,一些API接口采用了JS加密技术这种加密技术使得数据在传输过程中更加安全,但也给爬虫开发带来…

客路旅行(KLOOK)面试(部分)(未完全解析)

一面 用过Chatgpt的哪个版本,了解Chatgpt版本之间的差异吗 什么是优雅部署?newBing: 服务启动时,检查依赖的组件或容器是否就绪,如果不就绪,等待或重试,直到就绪后再注册到服务中心,对外提供服…

AcWing 844. 走迷宫 (每日一题)

给定一个 nm 的二维整数数组,用来表示一个迷宫,数组中只包含 0 或 1,其中 0 表示可以走的路,1表示不可通过的墙壁。 最初,有一个人位于左上角 (1,1)处,已知该人每次可以向上、下、左、右任意一个方向移动一…

WIFI模块的工作原理及AP模式和STA模式的区别

WiFi模块的运作原理: WiFi模块通常由两大核心组件构成:无线芯片和微处理器。无线芯片专注于处理无线信号的传送与接收,而微处理器则全面管理和调控WiFi模块的各项功能。数据传输过程中,无线芯片利用无线电波进行信号的交互。通过…

网络安全社区与资源分享: 推荐网络安全社区、论坛、博客、培训资源等,帮助从业者拓展人脉和知识。

第一章:引言 在当今数字化的世界中,网络安全问题变得愈发突出。随着各种新型威胁的涌现,网络安全从业者面临着持续不断的挑战。然而,正是因为这些挑战,网络安全社区应运而生,成为从业者们互相交流、学习和…

C语言常见字符串和内存函数详解

字符串和内存函数 1. 前言2. 求字符串长度2.1 strlen 3. 长度不受限制的字符串函数3.1 strcpy3.2 strcat3.3 strcmp 4. 长度受限制的字符串函数4.1 strncpy4.2 strncat4.3 strncmp 5. 字符串查找5.1 strstr5.2 strtok 6. 错误信息报告6.1 strerror 7. 字符操作函数7.1 字符分类…

windows使用vim编辑文本powershell

windows使用vim编辑文本 1、安装 chocolatey 包 以管理员身份打开 PowerShell 进行安装 Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString(https://chocolatey.org/install.ps1))2、管理员身份打开 PowerShell 并使…

C++面试题(吴)-计算机网络部分(2)和常见设计模式

目录 1.网络部分 3.32 说说浏览器从输入 URL 到展现页面的全过程 3.33 简述 HTTP 和 HTTPS 的区别? 3.34 说说 HTTP 中的 referer 头的作用 3.35 说说 HTTP 的方法有哪些 3.36 简述 HTTP 1.0,1.1,2.0 的主要区别 3.37 说说 HTTP 常见的…

【笔记】PyCharm快捷键大全

PyCharm是一种Python集成开发环境(IDE),由JetBrains公司开发。它被认为是Python开发中最强大、最流行的IDE之一。PyCharm具有完整的Python开发工具链,包括先进的代码编辑器、代码分析工具、集成的调试器、版本控制系统集成、自动化…

打车系统网约车系统开发支持APP公众号H5小程序版本源码

一、操作流程 二、业务模式 三、用户端 用户注册登录:未注册的手机号将自动创建账号 通过好友的邀请链接进行注册,将会绑定上下级关系 也可以注册的时候输入好友的邀请码,也可以绑定关系 用户充值: 用户下单支付时,可以…

Window11-Ubuntu双系统安装

一、制作Ubuntu系统盘 1.下载Ubuntu镜像源 阿里云开源镜像站:https://mirrors.aliyun.com/ubuntu-releases/ 清华大学开源软件镜像网站:https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/ 选择想要的版本下载,我用的是20.04版本。 2…

环境异常总结

1.vue项目 npm run dev 运行时报错:webpack-dev-server --inline --progress --config build/webpack.dev.conf.js 不是内部或外部命令 原因:webpack-dev-server存在问题 解决方案:指定 webpack-dev-server 低版本号 方法: 删除 …

meethigher-Apache Poi 实现Excel多级联动下拉框

由于最近做的功能,需要将接口返回的数据列表,输出到excel中,以供后续导入,且网上现有的封装,使用起来都较为麻烦,故参考已有做法封装了工具类。 使用apache poi实现excel联动下拉框思路 创建隐藏单元格&a…

OceanBase 4.x改装:另一种全链路追踪的尝试

本文作者:夏克 OceanBase 社区文档贡献者,曾多次参与 OceanBase 技术征文比赛,获得优秀名次。从事金融行业核心系统设计开发工作多年,服务于某交易所子公司,现阶段负责国产数据库调研。 本文为 OceanBase 第七期技术征…

web端调用本地摄像头麦克风+WebRTC腾讯云,实现直播功能

目录 关于直播直播流程直播视频格式封装推流和拉流 获取摄像头和麦克风权限navigator.getUserMedia()MediaDevices.getUserMedia() WebRTC腾讯云快直播 关于直播 视频直播技术大全、直播架构、技术原理和实现思路方案整理 直播流程 视频采集端: 1、视频采集&#…

说说Flink双流join

分析&回答 Flink双流JOIN主要分为两大类 一类是基于原生State的Connect算子操作另一类是基于窗口的JOIN操作。其中基于窗口的JOIN可细分为window join和interval join两种。 基于原生State的Connect算子操作 实现原理:底层原理依赖Flink的State状态存储&…

深度学习推荐系统(三)NeuralCF及其在ml-1m电影数据集上的应用

深度学习推荐系统(三)NeuralCF及其在ml-1m电影数据集上的应用 在2016年, 随着微软的Deep Crossing, 谷歌的Wide&Deep以及FNN、PNN等一大批优秀的深度学习模型被提出, 推荐系统全面进入了深度学习时代, 时至今日, …

JavaDemo——使用LinkedHashMap实现简单的Cache

继承LinkedHashMap&#xff0c;合理使用构造方法public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)和protected boolean removeEldestEntry(Map.Entry<K,V> eldest)方法就可以自己构建简单的Cache了&#xff1b; LinkedHashMap构造方法…

【三等奖方案】小样本数据分类任务赛题「复兴15号」团队解题思路

第十届CCF大数据与计算智能大赛&#xff08;2022 CCF BDCI&#xff09;已圆满结束。大赛官方竞赛平台DataFountain&#xff08;简称DF平台&#xff09;将陆续释出各赛题获奖队伍的方案思路。 本方案为【小样本数据分类任务】赛题的三等奖获奖方案&#xff0c;赛题地址&#xff…

【暴力DP】2021 icpc上海 I

Problem - I - Codeforces 题意&#xff1a; 思路&#xff1a; 考虑暴力DP即可 设 dp[i][j][k]表示 前 i 个物品&#xff0c;已经翻倍了 j 次&#xff0c;A点数 - B点数为 k 的最大价值和 然后分为这6种决策分类讨论就好了 注意数组里不能有负数&#xff0c;要加个偏移量 P…