数据结构试验迷宫问题_三种迷宫算法在Grasshopper中的实现(一)

84d040bb4c70049a3927e90dc91d9059.png

最近在学习Gh的循环插件,无意中看到有关迷宫算法的内容,就想尝试着用Anemone插件实现。不过因为根本不懂编程,磕磕绊绊还是做出来了,不过最终性能实现状况不是特别好。因为涉及到每次循环需要遍历整个点集,随着需要计算的格数增加,每次循环计算量就会相应增加,之后试试能不能直接通过点之间数据结构的关系重新实现一下。参考的这篇文章

CSDN-专业IT技术社区-登录​blog.csdn.net

(一)深度优先
人话就是不撞南墙不回头:随机从一个点开始随机“钻洞”,如果碰墙无路可走,就往回走直到周围有可以选择的路径,然后再 次随机“钻洞”,重复这个过程,直到迷宫所有的部分都被走过。GIF演示:

7f2719eaa302f18884353d58ba8efd0f.gif


可能比较麻烦的地方就是把这个思路转换成电池,这里说一下我在Grasshopper中实现的思路:
1.square运算器生成点阵,将生成的对应方格中心点点集作为“陆地”,初始状态下每个点四周都被“墙”包围

5a3ed66ea7ab15ca2c49fe2d5a1381a7.png
初始点集


2.随机选择一个“陆地”点作为初始点(以下简称“头”),然后将这个点从“陆地”之中除去,这是循环的初始条件。

26830cfc18a5f7429acda801834c67ce.png
随机选择初始点:“头”


3.利用布尔值与0和1的关系判定运算点周围点的个数:

计算运算点与每个剩余点的距离,判断它们是否等于方格的边长,将得到的这些布尔值(1=True,0=False)累加,结果大于0则四周有可选择的点,反之没有。

e966130bd5396ecda2fdab40f21d80c4.png
判定四周点

72d249aa28f8a80ebbb28bf5e4532d1e.png
判定个数是否为0


4.利用stream filter运算器实现不同情况下的分流

4fab0af104151e2c5523ec704bbae898.png
stream filter运算器


“有路可走”时,随机选取“头”周围的点,并将其从剩余点中剔除,可以把这个点与起始点连线作为路径记录;
“无路可走”时,剩余点不变并且参与下一次循环。
5.定义一个列表存储已经走过的点(insert item运算器)用于“无路可走”时运算点的选取
“有路可走”时,将选择的点插入到列表的第一项
“无路可走”时,将该列表第一项作为运算点,并将其剔除列表

e6fdee4bc48e5ad0dc3891e0404a275a.png
用于无路可走时的点集


6.最后定义一下循环结束的条件,如果剩余点的列表个数等于0则循环终止

e6bae8aa94397e5c9649d702b5be2869.png
循环终止判定


调整电池图,这个时候就可以执行一个完整的循环了。不过目前只有点参与运算,可以在循环中增加“有路可走”时起始点与末尾点的连线,这个时候可以看到每次循环两点的连线,不过需要右键选择Collect Data才能保留所有连线,或者利用Data Recorder运算器保留每次发生变化的值。

d7b1b1eb81ab012d53c0d096148324e2.png
右键有“record data”选项

8b7e1b6738d25820d44c80c9bf321c52.png
Data recorder 运算器


但是这样就会有一些问题:

如果循环CollectData就会有很多无效的数据冗余,比如剩余点集以及回退点集每循环一次都会存储所有的数据;

如果使用DataRecorder,每次更改生成条件需要重新设置,而且我不仅需要路的数据,更需要墙的数据。
7.这样的话就需要稍微修改一下生成逻辑了。“墙”与“路”是有关系的,每形成一条路径就摧毁一堵墙,也就是他们之间是一一对应的(他们的中点是重合的)。那么可以预先生成全部的墙与路径,之后每次循环保留或者剔除相应的数据即可。甚至不需要这些点参与循环,只需要拿到他们的序号就好(利用member index运算器)。这样可以大大减小运算量。

c54c3117050d6e9eda4c296212170b98.png
循环前生成的路径端点数据

114745c3dda3d8c045f4bbf8893e4f18.png
member index运算器获取对应路径的编号

最后根据循环得到的索引值数据提取保留的端点数据,并将每个分支下的两个点相连,这样就大功告成了;

de3b52b8d4a81e0eaf67613310165efb.png


之后要做的就是点击button,等待循环了,也可以在输出的“头”位置连一个circle观察一下这个迷宫的生成过程;

376a95d52ac8cb974a297169f6ed7b30.png
生成过程

d8537044690e67f02faa7dde9bec2f96.png
最终迷宫


8.最后join一下offset一下loft一下Union一下extrude一下就可以拿到一个迷宫了。

ccfdf4ea6fca51d243e63a19c939e865.png
成功!

迷宫电池图:

3c914ee1ccbbbe799730ecb8192935e2.png

百度网盘地址:
链接:https://pan.baidu.com/s/1PBBTozTboIev7HoAUWLjIQ
提取码:vmy0

需要Grasshopper插件Anemone

下载地址:

https://www.food4rhino.com/app/anemone​www.food4rhino.com
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
/* ****迷宫算法求解************* */ /**计目标:教学演示**************/ #include<stdio.h> #define rows 10 #define cols 10 typedef struct {int row; int col; }PosType;/* //坐标点结构 */ typedef struct {int ord;/*//通道块在路径上的“序号” */ PosType seat;/*//通道块在迷宫的“坐标位置”*/ int di;/*//从此通道快走向下一通道块的“方向” */ }SElemType;/*//栈的元素类型 */ typedef struct {SElemType *base; SElemType *top; int stacksize; }SqStack;/*//堆栈结构 */ void InitStack(SqStack &s)/*//初始化堆栈 */ { s.base=(SElemType *)malloc(100*sizeof(SElemType)); if(!s.base) return NULL; s.top=s.base; s.stacksize=100; } int StackEmpty(SqStack s)/* //栈空判别*/ {return(s.top==s.base); } void Pop(SqStack &s ,SelemType &e)/*//弹栈 */ {e=*--s.top); } void Push(SqStack &s,SElemType e)/*//将元素压入堆栈*/ { *s.top++=e; } /*static int maze[rows][cols]= {{0,0,0,0,0,0,0,0,0,0}, {0,1,1,0,1,1,1,0,1,0}, {0,1,1,0,1,0,1,0,1,0}, {0,1,1,0,1,0,0,1,1,0}, {0,1,1,0,0,1,1,1,1,0}, {0,1,1,1,0,1,1,1,1,0}, {0,1,0,1,1,1,0,1,1,0}, {0,1,0,0,0,1,0,0,1,0}, {0,0,1,1,1,1,1,1,1,0}, {0,0,0,0,0,0,0,0,0,0}, }; */ /* //初始迷宫数据(1-通,0-不通)*/ static int maze[rows][cols]= {{0,0,0,0,0,0,0,0,0,0}, {0,1,1,0,1,1,1,0,1,0}, {0,1,1,0,1,0,1,1,1,0}, {0,1,1,1,0,0,0,0,1,0}, {0,1,0,0,0,1,1,1,1,0}, {0,1,0,1,0,1,0,0,0,0}, {0,1,0,1,1,1,0,1,1,0}, {0,1,0,1,0,0,0,0,1,0}, {0,0,1,1,1,1,1,1,1,0}, {0,0,0,0,0,0,0,0,0,0}, }; /* //初始迷宫数据(1-通,0-不通)*/ static int foot[10][10]={0};/*//标记某点是否走过(1-走过,0-未走过)*/ void printpath(SqStack &s)/*//打印迷宫通路*/ {int i,j; SElemType e; while(!StackEmpty(s)) { Pop(s,e); foot[e.seat.row][e.seat.col]=1; } for(i=0;i<10;i++) {printf("\n"); for(j=0;j<10;j++) if(foot[i][j]) printf(" # "); else printf(" . "); } } int Pass(PosType pos)/*//判断当前的通道块是否可通*/ { return(maze[pos.row][pos.col]); }; void FootPrint(PosType pos) { maze[pos.row][pos.col]=0; } PosType NextPos(PosType curpos,int dir)/*//取当前通道块的下一个通道块*/ { switch(dir) {case 1: curpos.row++; break; case 2: curpos.col++; break; case 3: curpos.row--; break; case 4: curpos.col--; } return curpos;/*//将下一个通道块变为当前通道块*/ } int END(PosType curpos,PosType end) {return(curpos.row==end.row && curpos.col==end.col); } void MazePath(SqStack &s,PosType start,PosType end) {PosType curpos,nextpos; int curstep; SElemType e; SqStack *s; s=InitStack(); curpos=start; curstep=1; do{ if(Pass(curpos)) {FootPrint(curpos); e.ord=curstep;e.seat=curpos;e.di=1; Push(s,e); if(END(curpos,end)) return s; curpos=NextPos(curpos,1); curstep++; }/* end of if */ else { if(!StackEmpty(s)) { e=Pop(s); while(e.di==4 && !StackEmpty(s)) {FootPrint(e.seat);/* The same fuction as MarkPrint ? */ e=Pop(s); }/* end of while */ if(e.di<4) {e.di++;Push(s,e); curpos=NextPos(e.seat,e.di); } /* end of if */ } /* end of if */ } /* end of else */ }while(!StackEmpty(s)); curstep=0; return NULL; } void main() {SqStack *s; static PosType start={1,1},end={8,8}; s=MazePath(start,end); if(s) printpath(s); else printf("\n NO find the path!"); }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值