看一下效果:
思路:用到了c++中的vector,看了迷宫的一些算法,发现prim生成的迷宫还是比较好看的,网上的代码python c#居多,而且不太容易搞懂,那我在这里用C++的STL实现了这个目的
prim算法:随机Prim算法生成的迷宫岔路较多,整体上较为自然而又复杂,算法核心为(根据维基百科)。
1.让迷宫全是墙.
2.选一个单元格作为迷宫的通路(我一般选择起点),然后把它的邻墙(上下左右)放入列表
3.当列表里还有墙时
①.从列表里随机选一个墙,如果这面墙分隔的两个单元格只有一个单元格被访问过
(a)那就从列表里移除这面墙,即把墙打通,让未访问的单元格成为迷宫的通路
(b)把这个格子的墙加入列表
②.如果墙两面的单元格都已经被访问过(都打通了),那就从列表里移除这面墙
看代码辅助理解。
#include <bits/stdc++.h>
using namespace std;
#define m 11//row
#define n 11
#define down 1
#define right 2
#define left 4
#define up 8
#define WALL -1
#define NOTHING 2
struct block{
int row,column,direction;
block(int _row,int _column,int _direction){
row = _row;
column = _column;
direction = _direction;
}
};
struct point {
int x;
int y;
}start,end;
vector<block> myblock;
int x_num=1,y_num=1;//矿工位置
int G[100][100];
void init() {
//将地图全部置为墙
memset(G,WALL,sizeof(G));
//定义起始点
G[1][1] = NOTHING;
start.x = start.y = 1;
}
void FindBlock() {
//找出与当前位置相邻的墙
if(x_num+1<=m && G[x_num+1][y_num] == WALL) {//down
myblock.push_back(block(x_num+1,y_num,down));
}
if(y_num+1<=n && G[x_num][y_num+1] == WALL) {//right
myblock.push_back(block(x_num,y_num+1,right));
}
if(x_num-1>=1 && G[x_num-1][y_num] == WALL) {//up
myblock.push_back(block(x_num-1,y_num,up));
}
if(y_num-1>=1 && G[x_num][y_num-1] == WALL) {//left
myblock.push_back(block(x_num,y_num-1,left));
}
}
int main() {
init();
srand((unsigned)time(NULL));//随机数种子
FindBlock();
//第一步压入两堵墙(起点右边和起点下面)进入循环
while(myblock.size()) {
int BlockSize = myblock.size();
//随机选择一堵墙(生成0 ~ BlockSize-1之间的随机数,同时也是vector里墙的下标)
int randnum = rand() % BlockSize;
block SelectBlock = myblock[randnum];
x_num = SelectBlock.row;//矿工来到我们“选择的墙”这里
y_num = SelectBlock.column;
//根据当前选择的墙的方向进行后续操作
//此时,起始点 选择的墙 目标块 三块区域在同一直线上
//我们让矿工从“选择的墙”继续前进到“目标块”
//矿工有穿墙能力 :)
switch(SelectBlock.direction) {
case down: {
x_num++;
break;
}
case right: {
y_num++;
break;
}
case left: {
y_num--;
break;
}
case up: {
x_num--;
break;
}
}
//目标块如果是墙
if(G[x_num][y_num]==WALL) {
//打通墙和目标块
G[SelectBlock.row][SelectBlock.column] = G[x_num][y_num] = NOTHING;
//再次找出与矿工当前位置相邻的墙
FindBlock();
}
else{//如果不是呢?说明我们的矿工挖到了一个空旷的通路上面 休息一下就好了
//relax
}
//删除这堵墙(把用不了的墙删了,对于那些已经施工过了不必再施工了,同时也是确保我们能跳出循环)
myblock.erase(myblock.begin()+randnum);
}
for (int i=0;i<=m+1;i++) {
for (int j=0;j<=n+1;j++) {
if(i == start.x && j == start.y) {
printf("%c%c",0xa7,0xb0 );
}
else if(G[i][j] == NOTHING) {
printf(" ");
}
else {
printf("%c%c", 0xa8, 0x80);
}
}
printf("\n");
}
return 0;
}
细节:起点随你定,终点无法确定 任何空的地方都可以作为终点 你会发现任何两个空的之间都有路可走
m,n需要均为奇数
PS:你可以在纸上模拟一个比较小的图,来理解这个算法,同时,你会发现这个图是没有环的,形成了一个树的结构。
用我的视频辅助理解:请务必看一下代码再看视频。
https://www.bilibili.com/video/BV1364y1u7LV