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

利用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)breakendend%然后按照序号进行替换Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);%绘图figure(1)imagesc(Maze)caxis([0,3])axis offpause(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;
endfunction [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=[];
elseRand_i=randi(N_Rand,1);indx_Rand=RandIndx(Rand_i,1);Block_Dir=RandIndx(Rand_i,2);
end
endfunction 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)+1for kc=1:Size_Mat(2)-Size_Block(2)+1Mat_k=Mat(kr:kr+Size_Block(1)-1,kc:kc+Size_Block(2)-1);IsSame=isequal(Mat_k,Block);if IsSameBlock_indx(kr,kc)=1;endend
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,可以行走的区域roomfigure(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)breakend%然后按照序号进行替换Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);figure(1)imagesc(Maze)caxis([0,2])pause(0.01)
endMaze(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;
endfunction [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=[];
elseRand_i=randi(N_Rand,1);indx_Rand=RandIndx(Rand_i,1);Block_Dir=RandIndx(Rand_i,2);
end
endfunction 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)+1for kc=1:Size_Mat(2)-Size_Block(2)+1Mat_k=Mat(kr:kr+Size_Block(1)-1,kc:kc+Size_Block(2)-1);IsSame=isequal(Mat_k,Block);if IsSameBlock_indx(kr,kc)=1;endend
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 trueBlock1=[1,0,0];Block2=[1,0,1];[indx_k,Block_Dir]=FindBlock2(Maze,Block1);if isempty(indx_k)breakend%然后按照序号进行替换Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
end
%2生成房间
while trueBlock1=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)breakend%然后按照序号进行替换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 trueBlock1=[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)breakendendend%然后按照序号进行替换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 trueBlock1=[4];Block2=[2];[indx_k,Block_Dir]=FindBlock2(Maze,Block1);if isempty(indx_k)breakend%然后按照序号进行替换Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);figure(1)imagesc(Maze)caxis([0,4])pause(0.01)
end
%5打上格点
while trueBlock1=[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)breakendend%然后按照序号进行替换Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);figure(1)imagesc(Maze)caxis([0,4])pause(0.01)
end
%6开放一些路径
for k=1:3Block1=[3,0,3];Block2=[3,2,3];[indx_k,Block_Dir]=FindBlock2(Maze,Block1);if isempty(indx_k)breakend%然后按照序号进行替换Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);figure(1)imagesc(Maze)caxis([0,4])pause(0.01)
end
while trueBlock1=[3];Block2=[2];[indx_k,Block_Dir]=FindBlock2(Maze,Block1);if isempty(indx_k)breakend%然后按照序号进行替换Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
end
figure(1)
imagesc(Maze)
caxis([0,4])
pause(0.01)%7删除分支小路
while trueBlock1=[0,0,0;0,2,0];Block2=[0,0,0;0,0,0];[indx_k,Block_Dir]=FindBlock2(Maze,Block1);if isempty(indx_k)breakend%然后按照序号进行替换Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);figure(1)imagesc(Maze)caxis([0,4])pause(0.01) 
endfigure(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;
endfunction [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=[];
elseRand_i=randi(N_Rand,1);indx_Rand=RandIndx(Rand_i,1);Block_Dir=RandIndx(Rand_i,2);
end
endfunction 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)+1for kc=1:Size_Mat(2)-Size_Block(2)+1Mat_k=Mat(kr:kr+Size_Block(1)-1,kc:kc+Size_Block(2)-1);IsSame=isequal(Mat_k,Block);if IsSameBlock_indx(kr,kc)=1;endend
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 trueBlock1=[1,0,0];Block2=[1,0,1];[indx_k,Block_Dir]=FindBlock2(Maze,Block1);if isempty(indx_k)breakend%然后按照序号进行替换Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
end
figure(1)
imagesc(Maze);caxis([0,Ncolor-1]);pause(0.01)%2生成蛇。
while trueBlock1=[2,0,1];Block2=[5,3,4];[indx_k,Block_Dir]=FindBlock2(Maze,Block1);if isempty(indx_k)breakend%然后按照序号进行替换Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);
end
for k=1:2Block1=[4,0,1];Block2=[3,3,4];[indx_k,Block_Dir]=FindBlock2(Maze,Block1);if isempty(indx_k)breakend%然后按照序号进行替换Maze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);figure(1)imagesc(Maze);caxis([0,Ncolor-1]);pause(0.01)
end
%2生成计分点
for k=1:10Block1=[1];Block2=[2];[indx_k,Block_Dir]=FindBlock2(Maze,Block1);if isempty(indx_k)breakend%然后按照序号进行替换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)breakelseMaze=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);endelseMaze=ReplaceBlock(Maze,indx_k,Block2,Block_Dir);endfigure(1)imagesc(Maze);caxis([0,Ncolor-1]);pause(0.01)
endfigure(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;
endfunction [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=[];
elseRand_i=randi(N_Rand,1);indx_Rand=RandIndx(Rand_i,1);Block_Dir=RandIndx(Rand_i,2);
end
endfunction 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)+1for kc=1:Size_Mat(2)-Size_Block(2)+1Mat_k=Mat(kr:kr+Size_Block(1)-1,kc:kc+Size_Block(2)-1);IsSame=isequal(Mat_k,Block);if IsSameBlock_indx(kr,kc)=1;endend
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:5switch 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)breakendend%如果没有树枝,就再从地里长一根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)breakendend%然后按照序号进行替换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 trueBlock1=[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)breakendDraw=ReplaceBlock(Draw,indx_k,Block2,Block_Dir);figure(1)imagesc(Draw);caxis([0,Ncolor-1]);axis off;pause(0.01)
endfigure(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;
endfunction [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=[];
elseRand_i=randi(N_Rand,1);indx_Rand=RandIndx(Rand_i,1);Block_Dir=RandIndx(Rand_i,2);
end
endfunction 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)+1for kc=1:Size_Mat(2)-Size_Block(2)+1Mat_k=Mat(kr:kr+Size_Block(1)-1,kc:kc+Size_Block(2)-1);Mat_k(isnan(Block))=nan;%如果输入的Block里有nan的,也把对应比对位置替换为nanIsSame=isequaln(Mat_k,Block);if IsSameBlock_indx(kr,kc)=1;endend
end
indx=find(Block_indx);
end

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

sql语句中的ddl和dml

操作数据库:CRUD C(create) 创建 *数据库创建出来默认字符集为utf8 如果要更改字符集就 Create database 名称 character set gbk(字符集) *创建数据库:create database 名称 *先检查是否有该数据库在…

zemax混合式非序列模拟

基础设置: 3D视图效果: 接下来用非序列模式设计一个多焦透镜 平行光束经过多焦透镜时,会汇聚在不同焦距处 非序列模式的编辑器如图: 注意不要点击左侧的非序列模式,那个时纯粹的非序列,会清除序列模式的数…

Linux gdb调式的原理

文章目录 一、原理分析二、dmoe测试2.1 hello.s2.2 demo演示 参考资料 一、原理分析 #include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <…

M2DGR数据集各相机话题名与外参名的对应关系

M2DGR数据集除了视觉惯性器件、天向相机&#xff0c;还有6个安装在同一平面、参数一致的鱼眼相机。 本文对这6个相机的安装位置、外参、topic话题进行区分。 安装图&#xff1a; 6个鱼眼相机 fish-eye camera装载在同一层。 外参情况 fish-eye camera在calibration_results…

解决Jackson解析JSON时出现的Illegal Character错误

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Vue2项目练手——通用后台管理项目第五节

Vue2项目练手——通用后台管理项目 首页组件布局面包屑&tag面包屑使用组件使用vuex存储面包屑数据src/store/tab.jssrc/components/CommonAside.vuesrc/components/CommonHeader.vue tag使用组件文件目录CommonTag.vueMain.vuetabs.js 用户管理页新增功能使用的组件页面布局…

第49节:cesium 倾斜模型osgb转3dtiles,并加载(含源码+视频)

结果示例: 完整步骤: 1、启动并登陆cesiumlab 2、准备OSGB模型数据(含下载地址) 链接:https://pan.quark.cn/s/46ac7b0b2bed 提取码:TvWL3、倾斜模型切片 选择倾斜模型data文件夹 空间参考、零点坐标 默认 强制双面关闭、无光照 打开

Debian12搭建Nextcloud最新版并frp到二级域名

起因&#xff1a;因为台风的原因&#xff0c;要居家办公&#xff0c;但正值公司业务最要紧的时刻&#xff0c;所以需要搭建远程共享&#xff0c;结果发现基于原有的经验&#xff0c;已经难以适应版本更新带来的问题&#xff0c;所以就解决方法&#xff0c;进行了一次重新总结&a…

【狂神】Spring5笔记(10-19)

又是美好而努力的一天呀~ __ /|* * * * * * / * * * / * * * * / * * * * * * * happy valentines day * * * * …

stable diffusion实践操作-提示词插件安装与使用

本文专门开一节写提示词相关的内容&#xff0c;在看之前&#xff0c;可以同步关注&#xff1a; stable diffusion实践操作 正文 1、提示词插件安装 1.1、 安装 1.2 加载【应用更改并重载前端】 1.3 界面展示 1.3.-4 使用 里面有个收藏列表&#xff0c;可以收藏以前的所有提示…

gin框架

【狂神说】Gin框架一小时上手 | 快速转型GoWeb开发 | Go语言零基础教程_哔哩哔哩_bilibili 1.介绍 2.简单程序 1&#xff09;gin.GET/POST/PUT/DELETE函数 Go Gin 简明教程 | 快速入门 | 极客兔兔 (geektutu.com) 我的理解是&#xff1a;这类函数就像是在监听接口一样&…

Docker环境搭建Prometheus实验环境

环境&#xff1a; OS&#xff1a;Centos7 Docker: 20.10.9 - Community Centos部署Docker 【Kubernetes】Centos中安装Docker和Minikube_云服务器安装docker和minikube_DivingKitten的博客-CSDN博客 一、拉取Prometheus镜像 ## 拉取镜像 docker pull prom/prometheus ## 启动p…

【MySQL系列】索引的学习及理解

「前言」文章内容大致是MySQL索引的学习。 「归属专栏」MySQL 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 一、索引概念二、从硬件角度理解2.1 磁盘2.2 结论 三、从软件角度理解四、共识五、索引的理解5.1 一个现象和结论5.2 对Page进行建模5.3 索引可以采用的数据结构5.…

同创永益入选首批“金融数字韧性与混沌工程实践试点机构”

8月16日下午&#xff0c;由北京国家金融科技认证中心、北京国家金融标准化研究院联合主办的“传递信任 服务发展”金融科技标准认证生态大会在太原成功举办。中国金融电子化集团有限公司党委书记、董事长周逢民&#xff0c;中国科学院院士冯登国&#xff0c;中国工商银行首席技…

STM32 RTC实验

RTC时钟简介 STM32F103的实时时钟&#xff08;RTC&#xff09;是一个独立的定时器。 STM32的RTC模块拥有一组连续计数的计数器&#xff0c;在相对应的软件配置下&#xff0c;可提供时钟日历的功能。 修改计数器的值可以重新设置系统的当前时间和日期。 RTC模块和时钟配置系统…

DEAP库文档教程三-----创建类型

本节将继续展示如何通过creator创建类型以及如何使用toolbox如何对复杂问题进行初始化。 Particle的初始化--粒子初始化 一个Particle是另一个特殊类型的个体&#xff0c;这是因为通常情况下它有一个速度&#xff0c;并且有一个最优的位置需要去记忆。这种类型个体的创建与通…

Redis 7 第六讲 主从模式(replica)

🌹🌹🌹 此篇开始进入高级篇范围(❤艸`❤) 理论 即主从复制,master以写为主,Slave以读为主。当master数据变化的时候,自动将新的数据异步同步到其它slave数据库。 使用场景 读写分离 容灾备份数据备份水平扩容主从架构 演示案例 注:masterauth、replicaof主…

JDBC连接数据库

目录 一.什么是JDBC 二.JDBC的实现步骤 三.简单使用JDBC 一.什么是JDBC JDBC是Java数据库连接&#xff0c;是java中提供数据库访问的Java API,它为关系型数据库的提供了统一访问规范。 二.JDBC的实现步骤 1.创建数据库连接 这里有两种方式: DataSource创建&#xff0c;提…

【Python从入门到进阶】34、selenium基本概念及安装流程

接上篇《33、使用bs4获取星巴克产品信息》 上一篇我们介绍了如何使用bs4来解析星巴克网站&#xff0c;获取其产品信息。本篇我们来了解selenium技术的基础。 一、什么是selenium&#xff1f; Selenium是一种用于自动化Web浏览器操作的开源工具。它提供了一组API&#xff08;应…

go锁-互斥锁

go锁-互斥锁 sema初始值是0&#xff0c;waitershift等待协程的数量 正常枷锁&#xff1a; 尝试CAS直接加锁&#xff0c;通过原子包给lockerd 为枷锁 若无法直接获取&#xff0c;进行多次自旋尝试&#xff0c;未获取到的锁的g &#xff0c;多次执行空语句&#xff0c;多次尝试…