C++实现迷宫生成(基于算法:随机prim)

本文介绍了一种使用C++实现Prim算法生成迷宫的方法。通过随机选取墙壁并打通,形成复杂的迷宫路径,最终生成没有环路的树状迷宫结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看一下效果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
思路:用到了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

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值