c++游戏小技巧16:实例1(地牢生成算法)

1.前言

(头图)

(其实最开始是想写恶魔轮盘的,但没想到它竟然更新了···)

(等我有时间在更,最近很忙,玩第五玩的)

想法来源:房间和迷宫:一个地牢生成算法icon-default.png?t=N7T8https://indienova.com/indie-game-development/rooms-and-mazes-a-procedural-dungeon-generator/

最开始是在c++小技巧6中提到的,但是捏,看着成品效果还是不错的

于是就想着复原一下(很明显,有点难度,不然我早就写了)

(当然,作者说它研究的时间多,我觉得很有道理,反正我没这实力)

这是实例系列的第一篇,希望大家提一点改进建议到评论区

2.正文

(这边我准备按原文章的顺序写)

前置知识:小技巧1~15

1.看得见风景的房间

要求:给定一个地图,在地图里进行n次尝试,每次生成一个处于随机位置的,随机大小的房间

如果它所在的位置没有被覆盖,那么它就是可行的

很简单,但注意:房间是中空的

 这个很简单,应该会一点的都会吧awa(我不会告诉你们我打了半小时才打出来)

#include<conio.h>
#include<windows.h>
#include<bits/stdc++.h>
using namespace std;
 
namespace init//小技巧15plus 
{
	#define kd(VK_NONAME) ((GetAsyncKeyState(VK_NONAME)&0x8000)?1:0)
	#define sl(n) Sleep(n)
	#define cls system("cls")
	void gotoxy(int x,int y){COORD pos={(short)x,(short)y};HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOut,pos);return;}
	void noedit(){HANDLE hStdin=GetStdHandle(STD_INPUT_HANDLE);DWORD mode;GetConsoleMode(hStdin,&mode);mode&=~ENABLE_QUICK_EDIT_MODE;mode&=~ENABLE_INSERT_MODE;mode&=~ENABLE_MOUSE_INPUT;SetConsoleMode(hStdin,mode);}
	void hide(){CONSOLE_CURSOR_INFO cur={1,0};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
	void show(){CONSOLE_CURSOR_INFO cur={1,1};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
}
using namespace init;

int c=500;//屏幕大小,一般是1092*1080 
int t;
struct room_{int x,y,lx,ly;}rm[150];

void full()//全屏窗口,方便调试 
{   
	system("mode con cols=50 lines=60");//随便设定一个值隐藏滚动条 
	HWND hwnd=GetForegroundWindow();
	int cx=GetSystemMetrics(SM_CXSCREEN),cy=GetSystemMetrics(SM_CYSCREEN);//获得屏幕高度与宽度 
	LONG lw=GetWindowLong(hwnd,GWL_STYLE);
	SetWindowLong(hwnd,GWL_STYLE,(lw|WS_POPUP|WS_MAXIMIZE)&~WS_CAPTION&~WS_THICKFRAME&~WS_BORDER);
	SetWindowPos(hwnd,HWND_TOP,0,0,cx,cy,0);
}

CONSOLE_SCREEN_BUFFER_INFO getxy()//取出运行框大小,具体参考小技巧9 
{
	CONSOLE_SCREEN_BUFFER_INFO bInfo;
	HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
	GetConsoleScreenBufferInfo(hConsole,&bInfo);
	return bInfo;
}
#define cx getxy().dwMaximumWindowSize.X
#define cy getxy().dwMaximumWindowSize.Y

void try_()
{
	memset(rm,0,sizeof rm);t=0;
	for(int i=1;i<=c;i++)
	{
		int x=rand()%cx,y=rand()%(cy-3),lx=rand()%11+20,ly=rand()%6+7;//房间大小我设定的是位于20,7到30,12之间
		bool f=1;
		if(x+lx>=cx||y+ly>=cy-3) f=0;
		for(int j=1;j<=t&&f;j++)
		{
			room_ r=rm[j];
			if((max(x,r.x)<=min(r.x+r.lx,x+lx))&&(max(-r.y-r.ly,-y-ly)<=min(-r.y,-y))) f=0;//判断是否有房间重合 
		}
		if(f) rm[++t]=(room_){x,y,lx,ly};
	}
	for(int i=1;i<=t;i++)
		for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
			for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++)
				gotoxy(x,y),printf((x==rm[i].x||x==rm[i].x+rm[i].lx-1||y==rm[i].y||y==rm[i].y+rm[i].ly-1)?"#":" ");
	gotoxy(0,cy-3);
	for(int i=0;i<cx;i++) printf("-");
}

int main()
{
	srand(time(NULL));
	full();
	hide();
	gotoxy(0,cy-3);
	for(int i=0;i<cx;i++) printf("-");
	puts("");
	printf("当前尝试数: %d 次(a增加,d减少,回车启动,Esc退出)    ",c);
	while(1)
	{
		if(kd(VK_ESCAPE)) break;
		gotoxy(0,cy-2);
		printf("当前尝试数: %d 次(a增加,d减少,回车启动,Esc退出)    ",c);
		gotoxy(0,0);
		if(kd('A')) c=max(c-10,10);//c是尝试次数 
		if(kd('D')) c=min(c+10,1000);
		if(kd(VK_RETURN)) cls,try_();
		Sleep(30);
	}
	return 0;
}

2.一个黑暗扭曲的走廊

这个反而还要比上面的简单吧(?)

大意描述就是给一个迷宫,然后找死路的最后一个点,删掉(又是不会描述的一天)

具体见下面代码(我把路和墙反过来,“#”代表的是路)

#include<bits/stdc++.h> 
#include<windows.h>
using namespace std;

namespace init_ //小技巧15plus 
{
	#define kd(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000)?1:0) 
	#define sl(n) Sleep(n)
	#define cls system("cls")
	void gotoxy(int x,int y){COORD pos={(short)x,(short)y};HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOut,pos);return;}
	void noedit(){HANDLE hStdin=GetStdHandle(STD_INPUT_HANDLE);DWORD mode;GetConsoleMode(hStdin,&mode);mode&=~ENABLE_QUICK_EDIT_MODE;mode&=~ENABLE_INSERT_MODE;mode&=~ENABLE_MOUSE_INPUT;SetConsoleMode(hStdin,mode);}
	void hide(){CONSOLE_CURSOR_INFO cur={1,0};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
	void show(){CONSOLE_CURSOR_INFO cur={1,1};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
}
using namespace init_;

#define m 239
#define n 61
#define WALL -1
#define KONG 2

int c; 
struct play_er{int x,y;}start;
int dt[1010][1010];
int fx[5][5]={{2,0},{-2,0},{0,2},{0,-2}};
int zj[5][5]={{1,0},{-1,0},{0,1},{0,-1}};
bool v[1010][1010]={0};
 
void init()//迷宫初始化 
{
	memset(v,0,sizeof v);
	start.x=2,start.y=2;
	memset(dt,WALL,sizeof dt);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(i==1||i==n||j==1||j==m) dt[i][j]=WALL;
			if(i%2==0&&j%2==0) dt[i][j]=KONG;
			else dt[i][j]=WALL;
		}
	}
	dt[2][2]=KONG;
}
 
void dfs(int x,int y)//造迷宫 
{
	bool f[5]={0};
	while(1)
	{
		if(f[0]&&f[1]&&f[2]&&f[3]) return ;
		int r=rand()%4;
		int nx=fx[r][0],ny=fx[r][1],zx=zj[r][0],zy=zj[r][1];
		if(x+nx<1||x+nx>n||y+ny<1||y+ny>m) {f[r]=1;continue;}//return ;
		if(dt[x+zx][y+zy]!=WALL||v[x+zx][y+zy]||v[x+nx][y+ny]) {f[r]=1;continue;}//return ;
		f[r]=1;
		dt[x+zx][y+zy]=KONG;
		v[x+zx][y+zy]=v[x+nx][y+ny]=1;
		dfs(x+nx,y+ny);
	}
	return ;
}

void full()//全屏窗口,方便调试 
{   
	system("mode con cols=50 lines=60");//随便设定一个值隐藏滚动条 
	HWND hwnd=GetForegroundWindow();
	int cx=GetSystemMetrics(SM_CXSCREEN),cy=GetSystemMetrics(SM_CYSCREEN);//获得屏幕高度与宽度 
	LONG lw=GetWindowLong(hwnd,GWL_STYLE);
	SetWindowLong(hwnd,GWL_STYLE,(lw|WS_POPUP|WS_MAXIMIZE)&~WS_CAPTION&~WS_THICKFRAME&~WS_BORDER);
	SetWindowPos(hwnd,HWND_TOP,0,0,cx,cy,0);
}

CONSOLE_SCREEN_BUFFER_INFO getxy()//小技巧9 
{
	CONSOLE_SCREEN_BUFFER_INFO bInfo;
	HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
	GetConsoleScreenBufferInfo(hConsole,&bInfo);
	return bInfo;
}
#define cx getxy().dwMaximumWindowSize.X
#define cy getxy().dwMaximumWindowSize.Y

int MX;//不知道为什么,mx的值是不变的
void get_MX()//取出路径总数 
{
	MX=0;
	init();
	dfs(2,2);
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(dt[i][j]==KONG) MX++;
}

play_er e[114514];
int t;

void get_end()//取出思路位置 
{
	int sx,sy;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(dt[i][j]==KONG) sx=i,sy=j;
	queue<play_er> q;
	while(!q.empty()) q.pop();
	bool vis[1010][1010];
	memset(vis,0,sizeof vis);
	vis[sx][sy]=1;
	q.push((play_er){sx,sy});
	while(!q.empty())
	{
		play_er p=q.front();
		q.pop();
		bool f=0;
		for(int i=0;i<4;i++)
		{
			int X=p.x+zj[i][0],Y=p.y+zj[i][1];
			if(!vis[X][Y]&&dt[X][Y]==KONG)
			{
				f=1;
				q.push((play_er){X,Y});
				vis[X][Y]=1;
			}
		}
		if(!f) e[++t]=p;
	}
}

void try_()//反复删除 
{
	init();//先建路 
	dfs(2,2);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(dt[i][j]==KONG) printf("#");
			else printf(" ");
		}
		printf("\n");
	}
	get_end();
	for(int i=1;i<=c;i++)//删掉awa 
	{
		if(t==0) get_end();
		dt[e[t].x][e[t].y]=WALL;
		gotoxy(e[t].y-1,e[t].x-1);//没错,我当时把这一行放在了t--下面调了1个小时
		t--;
		printf(" ");
		Sleep(1);
	}
	gotoxy(0,cy-3);
	for(int i=0;i<cx;i++) printf("-");
}

int main()
{
	init();
	hide();
	full();
	srand(time(NULL));
	get_MX();
	c=MX/2;
	
	gotoxy(0,cy-3);
	for(int i=0;i<cx;i++) printf("-");
	puts("");
	printf("当前尝试数: %d 次(a增加,d减少,回车启动,Esc退出)    ",c);
	while(1)
	{
		if(kd(VK_ESCAPE)) break;
		gotoxy(0,cy-2);
		printf("当前尝试数: %d 次(a减少,d增加,回车启动,Esc退出)    ",c);
		gotoxy(0,0);
		if(kd('A')) c=max(c-50,1);
		if(kd('D')) c=min(c+50,MX);
		if(kd(VK_RETURN)) cls,try_();//c是尝试 
		Sleep(30);
	}
	return 0;
}

这个思路比较简单,代码码起也不难(我就码了1.5h)

3.房间,然后是迷宫

 我在这里一直很纠结

就一直在想到底是以

#####
##### 
###########        
#####     # 
#####     # 
          # 
		  # 
	##############
	##############
	############## 
	############## 

的形式,还是以

#####
#   ######## 
#          # 
#   ###### # 
#####    # #
         # #
		 # #
	###### #######
	#            #
	#            # 
	############## 

的形式

最后犹豫了很久,选择了好码的方式

这一个板块相对来说比较有模拟性(?)

就是先按造房间、造迷宫

但需要注意的是,先造房间再造迷宫与先造迷宫在造房间是不一样的

1.先造房间再造迷宫

这个注意一点

dfs生成迷宫的方式是给地图初始化成

#############
# # # # # # #
#############
# # # # # # #
#############

然后连接两个空格来造路

如果你先造房间就要注意其中的关系(我指的是不要造着造着路就到房间里面了)

2.先造迷宫再造房间

这个相对来说就简单亿点点了

造房间的时候,清空房间周围一圈的空地

我这边选用作者最开始使用的1号方案

先造房间,在填充迷宫

依然是全屏方便大家查看

#include<conio.h>
#include<windows.h>
#include<bits/stdc++.h>
using namespace std;
 
namespace init_ //小技巧15 
{
	#define kd(VK_NONAME) ((GetAsyncKeyState(VK_NONAME)&0x8000)?1:0)
	#define sl(n) Sleep(n)
	#define cls system("cls")
	void gotoxy(int x,int y){COORD pos={(short)x,(short)y};HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOut,pos);return;}
	void noedit(){HANDLE hStdin=GetStdHandle(STD_INPUT_HANDLE);DWORD mode;GetConsoleMode(hStdin,&mode);mode&=~ENABLE_QUICK_EDIT_MODE;mode&=~ENABLE_INSERT_MODE;mode&=~ENABLE_MOUSE_INPUT;SetConsoleMode(hStdin,mode);}
	void hide(){CONSOLE_CURSOR_INFO cur={1,0};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
	void show(){CONSOLE_CURSOR_INFO cur={1,1};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
}
using namespace init_;

namespace Color//加上颜色更加美观 
{
	void color(int a)
	{
	/*亮白*/if(a==0) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
	/*蓝色*/if(a==1) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN|FOREGROUND_BLUE);
	/*绿色*/if(a==2) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN);
	/*紫色*/if(a==3) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_BLUE);
	/*红色*/if(a==4) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED);
	/*黄色*/if(a==5) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN);
	/*深蓝*/if(a==6) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_BLUE);
	/*金黄*/if(a==7) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_GREEN);
	/*灰白*/if(a==8) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
	}
	void yanse(int ForgC,int BackC)
	{
		WORD wColor=((BackC&0x0F)<<4)+(ForgC&0x0F);
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),wColor);
	}
}
using namespace Color;

#define m 239
#define n 61
#define WALL -1
#define KONG 2

int t;
struct room_{int x,y,lx,ly;}rm[150];
struct play_er{int x,y;}start;
int dt[1010][1010];
int fx[5][5]={{2,0},{-2,0},{0,2},{0,-2}};
int zj[5][5]={{1,0},{-1,0},{0,1},{0,-1}};
bool v[1010][1010]={0};

void full()//全屏窗口,方便调试 
{   
	system("mode con cols=50 lines=60");//随便设定一个值隐藏滚动条 
	HWND hwnd=GetForegroundWindow();
	int cx=GetSystemMetrics(SM_CXSCREEN),cy=GetSystemMetrics(SM_CYSCREEN);//获得屏幕高度与宽度 
	LONG lw=GetWindowLong(hwnd,GWL_STYLE);
	SetWindowLong(hwnd,GWL_STYLE,(lw|WS_POPUP|WS_MAXIMIZE)&~WS_CAPTION&~WS_THICKFRAME&~WS_BORDER);
	SetWindowPos(hwnd,HWND_TOP,0,0,cx,cy,0);
}

CONSOLE_SCREEN_BUFFER_INFO getxy()//小技巧9 
{
	CONSOLE_SCREEN_BUFFER_INFO bInfo;
	HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
	GetConsoleScreenBufferInfo(hConsole,&bInfo);
	return bInfo;
}
#define cx getxy().dwMaximumWindowSize.X
#define cy getxy().dwMaximumWindowSize.Y

void try_()//插房间,为了方便,房间的x,y坐标为偶数,长宽为奇数 
{
	memset(rm,0,sizeof rm);t=0;
	for(int i=1;i<=1000;i++)
	{
		int x=rand()%cx,y=rand()%(cy-3),lx=rand()%11+20,ly=rand()%6+7;
		bool f=1;
		if(x%2!=0) x++;
		if(y%2!=0) y++;
		if(lx%2==0) lx++;
		if(ly%2==0) ly++;
		if(x+lx>=cx||y+ly>=cy-3) f=0;
		for(int j=1;j<=t&&f;j++)
		{
			room_ r=rm[j];
			if((max(x,r.x)<=min(r.x+r.lx,x+lx))&&(max(-r.y-r.ly,-y-ly)<=min(-r.y,-y))) f=0;
		}
		if(f) rm[++t]=(room_){x,y,lx,ly};
	}
}
 
void dfs(int x,int y)//小技巧6 
{
	bool f[5]={0};
	gotoxy(y-1,x-1),printf("#");
	Sleep(5); 
	while(1)
	{
		if(f[0]&&f[1]&&f[2]&&f[3]) return ;
		int r=rand()%4;
		int nx=fx[r][0],ny=fx[r][1],zx=zj[r][0],zy=zj[r][1];
		if(x+nx<1||x+nx>n||y+ny<1||y+ny>m) {f[r]=1;continue;}//return ;
		if(dt[x+zx][y+zy]!=WALL||v[x+zx][y+zy]||v[x+nx][y+ny]) {f[r]=1;continue;}//return ;
		f[r]=1;
		dt[x+zx][y+zy]=KONG;
		v[x+zx][y+zy]=v[x+nx][y+ny]=1;
		gotoxy(y+zy-1,x+zx-1),printf("#");Sleep(5);//输出 
		gotoxy(y+ny-1,x+nx-1),printf("#");Sleep(5);//输出 
		dfs(x+nx,y+ny);
	}
	return ;
}

void init()
{
	memset(v,0,sizeof v);//一般的初始化 
	start.x=2,start.y=2;
	memset(dt,WALL,sizeof dt);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(i==1||i==n||j==1||j==m) dt[i][j]=WALL;
			if(i%2==0&&j%2==0) dt[i][j]=KONG;
			else dt[i][j]=WALL;
		}
	}
	for(int i=1;i<=t;i++)//输出并标记房间 
	{
		color(rand()%5);
		for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
			for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++) dt[y][x]=KONG,v[y][x]=1,gotoxy(x-1,y-1),printf("#");
		Sleep(100);
	}
	gotoxy(0,0);
	for(int i=0;i<=n;i++)//建路 
		for(int j=1;j<=m;j++)
			if(dt[i][j]==KONG&&dt[i-1][j]==WALL&&dt[i+1][j]==WALL&&dt[i][j-1]==WALL&&dt[i][j+1]==WALL) color(rand()%4+5),dfs(i,j);
}

void make_way()//造路 
{
	init();
	gotoxy(0,0);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++) printf("%c",dt[i][j]==KONG?'#':' ');
		puts("");
	}
}

int main()
{
	srand(time(NULL));
	full();
	hide();
	gotoxy(0,cy-2);
	printf("(回车启动,Esc退出)");
	while(1)
	{
		if(kd(VK_ESCAPE)) break;
		gotoxy(0,cy-2);
		printf("(回车启动,Esc退出)");
		if(kd(VK_RETURN)) cls,try_(),make_way();
		Sleep(30);
	}
	return 0;
}

4.寻找一个连接

这个相对简单

对于每一个房间,遍历周围,找到能与之相连的路

然后玩运气,设定一个值,判断连接

当然,遍历到最后一条路的时候是100%能连上(aaaa语文白学了,感觉描述不出来啊qwq)

(算了,只可意会不可言传)

#define debug 0

#include<conio.h>
#include<windows.h>
#include<bits/stdc++.h>
using namespace std;
 
namespace init_ //小技巧15 
{
	#define kd(VK_NONAME) ((GetAsyncKeyState(VK_NONAME)&0x8000)?1:0)
	#define sl(n) Sleep(n)
	#define cls system("cls")
	void gotoxy(int x,int y){COORD pos={(short)x,(short)y};HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOut,pos);return;}
	void noedit(){HANDLE hStdin=GetStdHandle(STD_INPUT_HANDLE);DWORD mode;GetConsoleMode(hStdin,&mode);mode&=~ENABLE_QUICK_EDIT_MODE;mode&=~ENABLE_INSERT_MODE;mode&=~ENABLE_MOUSE_INPUT;SetConsoleMode(hStdin,mode);}
	void hide(){CONSOLE_CURSOR_INFO cur={1,0};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
	void show(){CONSOLE_CURSOR_INFO cur={1,1};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
}
using namespace init_;

namespace Color//加上颜色更加美观 
{
	void color(int a)
	{
	/*亮白*/if(a==0) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
	/*蓝色*/if(a==1) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN|FOREGROUND_BLUE);
	/*绿色*/if(a==2) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN);
	/*紫色*/if(a==3) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_BLUE);
	/*红色*/if(a==4) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED);
	/*黄色*/if(a==5) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN);
	/*深蓝*/if(a==6) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_BLUE);
	/*金黄*/if(a==7) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_GREEN);
	/*灰白*/if(a==8) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
	}
	void yanse(int ForgC,int BackC)
	{
		WORD wColor=((BackC&0x0F)<<4)+(ForgC&0x0F);
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),wColor);
	}
}
using namespace Color;

#define m 239
#define n 61
#define WALL -1
#define KONG 2

int t;
struct room_{int x,y,lx,ly;}rm[150];
struct play_er{int x,y;}start;
int dt[1010][1010];
int fx[5][5]={{2,0},{-2,0},{0,2},{0,-2}};
int zj[5][5]={{1,0},{-1,0},{0,1},{0,-1}};
bool v[1010][1010]={0};

void full()//全屏窗口,方便调试 
{   
	system("mode con cols=50 lines=60");//随便设定一个值隐藏滚动条 
	HWND hwnd=GetForegroundWindow();
	int cx=GetSystemMetrics(SM_CXSCREEN),cy=GetSystemMetrics(SM_CYSCREEN);//获得屏幕高度与宽度 
	LONG lw=GetWindowLong(hwnd,GWL_STYLE);
	SetWindowLong(hwnd,GWL_STYLE,(lw|WS_POPUP|WS_MAXIMIZE)&~WS_CAPTION&~WS_THICKFRAME&~WS_BORDER);
	SetWindowPos(hwnd,HWND_TOP,0,0,cx,cy,0);
}

CONSOLE_SCREEN_BUFFER_INFO getxy()//小技巧9 
{
	CONSOLE_SCREEN_BUFFER_INFO bInfo;
	HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
	GetConsoleScreenBufferInfo(hConsole,&bInfo);
	return bInfo;
}
#define cx getxy().dwMaximumWindowSize.X
#define cy getxy().dwMaximumWindowSize.Y

void try_()//插房间,为了方便,房间的x,y坐标为偶数,长宽为奇数 
{
	memset(rm,0,sizeof rm);t=0;
	for(int i=1;i<=1000;i++)
	{
		int x=rand()%cx,y=rand()%(cy-3),lx=rand()%11+20,ly=rand()%6+7;
		bool f=1;
		if(x%2!=0) x++;
		if(y%2!=0) y++;
		if(lx%2==0) lx++;
		if(ly%2==0) ly++;
		if(x+lx>=cx||y+ly>=cy-3) f=0;
		for(int j=1;j<=t&&f;j++)
		{
			room_ r=rm[j];
			if((max(x,r.x)<=min(r.x+r.lx,x+lx))&&(max(-r.y-r.ly,-y-ly)<=min(-r.y,-y))) f=0;
		}
		if(f) rm[++t]=(room_){x,y,lx,ly};
	}
}
 
void dfs(int x,int y)//小技巧6 
{
	bool f[5]={0};
	gotoxy(y-1,x-1),printf("#");
	Sleep(debug/2); 
	while(1)
	{
		if(f[0]&&f[1]&&f[2]&&f[3]) return ;
		int r=rand()%4;
		int nx=fx[r][0],ny=fx[r][1],zx=zj[r][0],zy=zj[r][1];
		if(x+nx<1||x+nx>n||y+ny<1||y+ny>m) {f[r]=1;continue;}//return ;
		if(dt[x+zx][y+zy]!=WALL||v[x+zx][y+zy]||v[x+nx][y+ny]) {f[r]=1;continue;}//return ;
		f[r]=1;
		dt[x+zx][y+zy]=KONG;
		v[x+zx][y+zy]=v[x+nx][y+ny]=1;
		gotoxy(y+zy-1,x+zx-1),printf("#");Sleep(debug/2);//输出 
		gotoxy(y+ny-1,x+nx-1),printf("#");Sleep(debug/2);//输出 
		dfs(x+nx,y+ny);
	}
	return ;
}

void init()
{
	memset(v,0,sizeof v);//一般的初始化 
	start.x=2,start.y=2;
	memset(dt,WALL,sizeof dt);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(i==1||i==n||j==1||j==m) dt[i][j]=WALL;
			if(i%2==0&&j%2==0) dt[i][j]=KONG;
			else dt[i][j]=WALL;
		}
	}
	for(int i=1;i<=t;i++)//输出并标记房间 
	{
		color(rand()%5);
		for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
			for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++) dt[y][x]=KONG,v[y][x]=1,gotoxy(x-1,y-1),printf("#");
		Sleep(debug*10);
	}
	gotoxy(0,0);
	for(int i=0;i<=n;i++)//建路 
		for(int j=1;j<=m;j++)
			if(dt[i][j]==KONG&&dt[i-1][j]==WALL&&dt[i+1][j]==WALL&&dt[i][j-1]==WALL&&dt[i][j+1]==WALL) color(rand()%4+5),dfs(i,j);
}

void make_way()//造路 
{
	init();
	gotoxy(0,0);
	color(0);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++) printf("%c",dt[i][j]==KONG?'#':' ');
		puts("");
	}
}

void connect()//连接路与房间 
{
	color(4);
	const int ch=3;//3%的概率选中
	int sum=0;
	for(int i=1;i<=t;i++)//枚举房间 
	{
		//分别枚举上面的边,左边的边,下面的边和右边的边
		//先找能与之相连的总数
		for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++)
		{
			if(dt[y][rm[i].x-2]==KONG) sum++;
			if(dt[y][rm[i].x+rm[i].lx+1]==KONG) sum++;
		}
		for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
		{
			if(dt[rm[i].y-2][x]==KONG) sum++;
			if(dt[rm[i].y+rm[i].ly+1][x]==KONG) sum++;
		}
		//暴力枚举连边 
		for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++)
		{
			if(dt[y][rm[i].x-2]==KONG)
			{
				if(rand()%100<ch||sum==1) dt[y][rm[i].x-1]=KONG,gotoxy(rm[i].x-1-1,y-1),printf("#");
				if(rand()%100<ch||sum==1) {sum--;continue;}
				sum--;
			}
			if(dt[y][rm[i].x+rm[i].lx+1]==KONG)
			{
				if(rand()%100<ch||sum==1) dt[y][rm[i].x+rm[i].lx]=KONG,gotoxy(rm[i].x+rm[i].lx-1,y-1),printf("#");
				if(rand()%100<ch||sum==1) {sum--;continue;}
				sum--;
			}
		}
		for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
		{
			if(dt[rm[i].y-2][x]==KONG)
			{
				if(rand()%100<ch||sum==1) dt[rm[i].y-1][x]=KONG,gotoxy(x-1,rm[i].y-1-1),printf("#");
				if(rand()%100<ch||sum==1) {sum--;continue;}
				sum--;
			}
			if(dt[rm[i].y+rm[i].ly+1][x]==KONG)
			{
				if(rand()%100<ch||sum==1) dt[rm[i].y+rm[i].ly][x]=KONG,gotoxy(x-1,rm[i].y+rm[i].ly-1),printf("#");
				if(rand()%100<ch||sum==1) {sum--;continue;}
				sum--;
			}
		}
	} 
	color(0);
	return;
}

int main()
{
	srand(time(NULL));
	full();
	hide();
	gotoxy(0,cy-2);
	printf("(回车启动,Esc退出)");
	while(1)
	{
		if(kd(VK_ESCAPE)) break;
		gotoxy(0,cy-2);
		printf("(回车启动,Esc退出)");
		if(kd(VK_RETURN)) cls,try_(),make_way(),connect();
		Sleep(30);
	}
	return 0;
}

 然后事情就简单了,接下来只需要删除多余的边就行了

5.反雕刻

就是把前面2中的删路代码放到里面去

6.最后我们得到什么

把所有代码连到一起,就拥有了一个能大量生成的地牢捏

这边给一个观赏类的代码

//建议在用这个生成地图的时候加一个判断是否全联通的搜索,zzb实验后发现有概率房间与道路不连通(zzb已经+了) 
#define debug 4//停顿时间,最好0~10 
 
#include<conio.h>
#include<windows.h>
#include<bits/stdc++.h>
using namespace std;
 
namespace init_ //小技巧15 
{
	#define kd(VK_NONAME) ((GetAsyncKeyState(VK_NONAME)&0x8000)?1:0)
	#define sl(n) Sleep(n)
	#define cls system("cls")
	void gotoxy(int x,int y){COORD pos={(short)x,(short)y};HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOut,pos);return;}
	void noedit(){HANDLE hStdin=GetStdHandle(STD_INPUT_HANDLE);DWORD mode;GetConsoleMode(hStdin,&mode);mode&=~ENABLE_QUICK_EDIT_MODE;mode&=~ENABLE_INSERT_MODE;mode&=~ENABLE_MOUSE_INPUT;SetConsoleMode(hStdin,mode);}
	void hide(){CONSOLE_CURSOR_INFO cur={1,0};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
	void show(){CONSOLE_CURSOR_INFO cur={1,1};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
}
using namespace init_;
 
namespace Color//加上颜色更加美观 
{
	void color(int ForgC)
	{
		int BackC=0;
		WORD wColor=((BackC&0x0F)<<4)+(ForgC&0x0F);
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),wColor);
	}
}
using namespace Color;
 
#define m 239
#define n 61
#define WALL -1
#define KONG 2
 
bool D=0;
int t;
struct room_{int x,y,lx,ly;}rm[150];
struct play_er{int x,y;}start;
int dt[1010][1010];
int fx[5][5]={{2,0},{-2,0},{0,2},{0,-2}};
int zj[5][5]={{1,0},{-1,0},{0,1},{0,-1}};
bool v[1010][1010]={0};
play_er e[114514];
 
 
void print()
{
	color(15);
	gotoxy(0,0);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++) printf("%c",dt[i][j]==KONG?'#':' ');
		puts("");
	}
}
 
 
void full()//全屏窗口,方便调试 
{   
	system("mode con cols=50 lines=60");//随便设定一个值隐藏滚动条 
	HWND hwnd=GetForegroundWindow();
	int cx=GetSystemMetrics(SM_CXSCREEN),cy=GetSystemMetrics(SM_CYSCREEN);//获得屏幕高度与宽度 
	LONG lw=GetWindowLong(hwnd,GWL_STYLE);
	SetWindowLong(hwnd,GWL_STYLE,(lw|WS_POPUP|WS_MAXIMIZE)&~WS_CAPTION&~WS_THICKFRAME&~WS_BORDER);
	SetWindowPos(hwnd,HWND_TOP,0,0,cx,cy,0);
}
 
CONSOLE_SCREEN_BUFFER_INFO getxy()//小技巧9 
{
	CONSOLE_SCREEN_BUFFER_INFO bInfo;
	HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
	GetConsoleScreenBufferInfo(hConsole,&bInfo);
	return bInfo;
}
#define cx getxy().dwMaximumWindowSize.X
#define cy getxy().dwMaximumWindowSize.Y
 
void try_()//插房间,为了方便,房间的x,y坐标为偶数,长宽为奇数 
{
	memset(rm,0,sizeof rm);t=0;
	for(int i=1;i<=1000;i++)
	{
		int x=rand()%cx,y=rand()%(cy-3),lx=rand()%11+20,ly=rand()%6+7;
		bool f=1;
		if(x%2!=0) x++;
		if(y%2!=0) y++;
		if(lx%2==0) lx++;
		if(ly%2==0) ly++;
		if(x+lx>=cx||y+ly>=cy-3) f=0;
		for(int j=1;j<=t&&f;j++)
		{
			room_ r=rm[j];
			if((max(x,r.x)<=min(r.x+r.lx,x+lx))&&(max(-r.y-r.ly,-y-ly)<=min(-r.y,-y))) f=0;
		}
		if(f) rm[++t]=(room_){x,y,lx,ly};
	}
}
 
void dfs(int x,int y)//小技巧6 
{
	bool f[5]={0};
	gotoxy(y-1,x-1),printf("#");
	Sleep(debug/2); 
	while(1)
	{
		if(f[0]&&f[1]&&f[2]&&f[3]) return ;
		int r=rand()%4;
		int nx=fx[r][0],ny=fx[r][1],zx=zj[r][0],zy=zj[r][1];
		if(x+nx<1||x+nx>n||y+ny<1||y+ny>m) {f[r]=1;continue;}//return ;
		if(dt[x+zx][y+zy]!=WALL||v[x+zx][y+zy]||v[x+nx][y+ny]) {f[r]=1;continue;}//return ;
		f[r]=1;
		dt[x+zx][y+zy]=KONG;
		v[x+zx][y+zy]=v[x+nx][y+ny]=1;
		gotoxy(y+zy-1,x+zx-1),printf("#");Sleep(debug/2);//输出 
		gotoxy(y+ny-1,x+nx-1),printf("#");Sleep(debug/2);//输出 
		dfs(x+nx,y+ny);
	}
	return ;
}
 
void init()
{
	memset(v,0,sizeof v);//一般的初始化 
	start.x=2,start.y=2;
	memset(dt,WALL,sizeof dt);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(i==1||i==n||j==1||j==m) dt[i][j]=WALL;
			if(i%2==0&&j%2==0) dt[i][j]=KONG;
			else dt[i][j]=WALL;
		}
	}
	for(int i=1;i<=t;i++)//输出并标记房间 
	{
		color(rand()%14+1);
		for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
			for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++) dt[y][x]=KONG,v[y][x]=1,gotoxy(x-1,y-1),printf("#");
		Sleep(debug*10);
	}
	gotoxy(0,0);
	for(int i=0;i<=n;i++)//建路 
		for(int j=1;j<=m;j++)
			if(dt[i][j]==KONG&&dt[i-1][j]==WALL&&dt[i+1][j]==WALL&&dt[i][j-1]==WALL&&dt[i][j+1]==WALL) color(rand()%14+1),dfs(i,j);
}
 
void make_way()//造路 
{
	init();
	gotoxy(0,0);
	color(0);
//	for(int i=1;i<=n;i++)
//	{
//		for(int j=1;j<=m;j++) printf("%c",dt[i][j]==KONG?'#':' ');
//		puts("");
//	}
}
 
void connect()//连接路与房间 
{
	color(4);
	const int ch=3;//3%的概率选中
	int sum=0;
	for(int i=1;i<=t;i++)//枚举房间 
	{
		//分别枚举上面的边,左边的边,下面的边和右边的边
		//先找能与之相连的总数
		for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++)
		{
			if(dt[y][rm[i].x-2]==KONG) sum++;
			if(dt[y][rm[i].x+rm[i].lx+1]==KONG) sum++;
		}
		for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
		{
			if(dt[rm[i].y-2][x]==KONG) sum++;
			if(dt[rm[i].y+rm[i].ly+1][x]==KONG) sum++;
		}
		//暴力枚举连边 
		bool b=0;
		while(!b)
		{
			for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++)
			{
				if(dt[y][rm[i].x-2]==KONG)
				{
					if(rand()%100<ch||sum==1) dt[y][rm[i].x-1]=KONG,gotoxy(rm[i].x-1-1,y-1),printf("#"),b=1;
					if(rand()%100<ch||sum==1) {sum--;continue;}
					sum--;
				}
				if(dt[y][rm[i].x+rm[i].lx+1]==KONG)
				{
					if(rand()%100<ch||sum==1) dt[y][rm[i].x+rm[i].lx]=KONG,gotoxy(rm[i].x+rm[i].lx-1,y-1),printf("#"),b=1;
					if(rand()%100<ch||sum==1) {sum--;continue;}
					sum--;
				}
			}
			for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
			{
				if(dt[rm[i].y-2][x]==KONG)
				{
					if(rand()%100<ch||sum==1) dt[rm[i].y-1][x]=KONG,gotoxy(x-1,rm[i].y-1-1),printf("#"),b=1;
					if(rand()%100<ch||sum==1) {sum--;continue;}
					sum--;
				}
				if(dt[rm[i].y+rm[i].ly+1][x]==KONG)
				{
					if(rand()%100<ch||sum==1) dt[rm[i].y+rm[i].ly][x]=KONG,gotoxy(x-1,rm[i].y+rm[i].ly-1),printf("#"),b=1;
					if(rand()%100<ch||sum==1) {sum--;continue;}
					sum--;
				}
			}
		}
	}
	gotoxy(0,0);
	color(15); 
	return;
}
 
void get_end()//取出死路位置,但注意之前的代码有bug,现在改了 
{
	int sx=0,sy=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(dt[i][j]==KONG) sx=i,sy=j;
	queue<play_er> q;
	while(!q.empty()) q.pop();
	bool vis[1010][1010];
	memset(vis,0,sizeof vis);
	q.push((play_er){sx,sy});
	vis[sx][sy]=1;
	while(!q.empty())
	{
		play_er p=q.front();
		q.pop();
		for(int i=0;i<4;i++)
		{
			int X=p.x+zj[i][0],Y=p.y+zj[i][1];
			if(!vis[X][Y]&&dt[X][Y]==KONG)
			{
				q.push((play_er){X,Y});
				vis[X][Y]=1;
			}
		}
		//现在删路是判断周围是否只有一个通路
		int f=4;
		for(int i=0;i<4;i++)
		{
			int X=p.x+zj[i][0],Y=p.y+zj[i][1];
			if(dt[X][Y]==KONG) f--;
		}
		if(f==3) e[++t]=p;
	}
}
 
void try__()//反复删除 
{
	get_end();
	while(1)//删掉awa 
	{
		if(t==0) get_end();
		if(t==0) break;
		dt[e[t].x][e[t].y]=WALL;
		gotoxy(e[t].y-1,e[t].x-1);//没错,我当时把这一行放在了t--下面调了1个小时
		t--;
		printf(" ");
		Sleep(1);
	}
}
 
void tian()//填充颜色&&判断是否合法 
{
	int sx=0,sy=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(dt[i][j]==KONG) sx=i,sy=j;
	queue<play_er> q;
	while(!q.empty()) q.pop();
	bool vis[1010][1010];
	memset(vis,0,sizeof vis);
	vis[sx][sy]=1;
	q.push((play_er){sx,sy});
	while(!q.empty())
	{
		play_er p=q.front();
		gotoxy(p.y-1,p.x-1);
		color(15);
		printf("#");Sleep(debug);
		q.pop();
		for(int i=0;i<4;i++)
		{
			int X=p.x+zj[i][0],Y=p.y+zj[i][1];
			if(!vis[X][Y]&&dt[X][Y]==KONG)
			{
				q.push((play_er){X,Y});
				vis[X][Y]=1;
			}
		}
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			if(dt[i][j]==KONG&&!vis[i][j])
			{
				MessageBox(NULL,"你的阳寿不够,即将重新设定地图","wrong",MB_ICONEXCLAMATION|MB_OK);
				D=1;
				return;
			}
		} 
	print();
}
 
void del()
{
	tian();//填充+广搜判断是否全联通 
	if(D) return;
	try__();
	print();
}
 
int main()
{
	noedit();
	srand(time(NULL));
	full();
	hide();
	gotoxy(0,cy-2);
	printf("(回车启动,Esc退出)");
	while(1)
	{
		if(kd(VK_ESCAPE)) break;
		gotoxy(0,cy-2);
		printf("(回车启动,Esc退出)");
		if(kd(VK_RETURN)) cls,try_(),make_way(),connect(),del();
		if(D)
		{
			D=0;
			cls;
			try_(),make_way(),connect(),del();
		}
		Sleep(30);
	}
	return 0;
}

如果你想用z_z_b_的代码生成地图,请用下面这一份

//地图生成,是以外放txt的形式,但可能出现格式错误,用devc++打开即可解决 

#include<conio.h>
#include<windows.h>
#include<bits/stdc++.h>
using namespace std;
 
namespace init_ //小技巧15 
{
	#define kd(VK_NONAME) ((GetAsyncKeyState(VK_NONAME)&0x8000)?1:0)
	#define sl(n) Sleep(n)
	#define cls system("cls")
	void gotoxy(int x,int y){COORD pos={(short)x,(short)y};HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOut,pos);return;}
	void noedit(){HANDLE hStdin=GetStdHandle(STD_INPUT_HANDLE);DWORD mode;GetConsoleMode(hStdin,&mode);mode&=~ENABLE_QUICK_EDIT_MODE;mode&=~ENABLE_INSERT_MODE;mode&=~ENABLE_MOUSE_INPUT;SetConsoleMode(hStdin,mode);}
	void hide(){CONSOLE_CURSOR_INFO cur={1,0};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
	void show(){CONSOLE_CURSOR_INFO cur={1,1};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
}
using namespace init_;
 
namespace Color//加上颜色更加美观 
{
	void color(int ForgC)
	{
		int BackC=0;
		WORD wColor=((BackC&0x0F)<<4)+(ForgC&0x0F);
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),wColor);
	}
}
using namespace Color;

#define cx 240
#define cy 65
#define m 239
#define n 61
#define WALL -1
#define KONG 2
 
bool D=0;
struct room_{int x,y,lx,ly;}rm[150];
struct play_er{int x,y;}start,e[1001000];
int t,dt[1010][1010],fx[5][5]={{2,0},{-2,0},{0,2},{0,-2}},zj[5][5]={{1,0},{-1,0},{0,1},{0,-1}};
bool v[1010][1010]={0};

void try_();//插入房间
void dfs(int,int);//造迷宫
void make_way();//地图初始化 
void connect();//连接房间与路
void get_end();//取出死路
void try__();//删路
void tian();//判断合法
void del();//删路总调控 
void optimize();//地图优化
void make_dt();//造地图
int main();//main函数 

void try_()//插房间,为了方便,房间的x,y坐标为偶数,长宽为奇数 
{
	memset(rm,0,sizeof rm);t=0;
	for(int i=1;i<=1000;i++)
	{
		int x=rand()%cx,y=rand()%(cy-3),lx=rand()%11+20,ly=rand()%6+7;
		bool f=1;
		if(x%2!=0) x++;
		if(y%2!=0) y++;
		if(lx%2==0) lx++;
		if(ly%2==0) ly++;
		if(x+lx>=cx||y+ly>=cy-3||x==0||y==0) f=0;
		for(int j=1;j<=t&&f;j++)
		{
			room_ r=rm[j];
			if((max(x,r.x)<=min(r.x+r.lx,x+lx))&&(max(-r.y-r.ly,-y-ly)<=min(-r.y,-y))) f=0;
		}
		if(f) rm[++t]=(room_){x,y,lx,ly};
	}
}
 
void dfs(int x,int y)//小技巧6 
{
	bool f[5]={0};
	while(1)
	{
		if(f[0]&&f[1]&&f[2]&&f[3]) return ;
		int r=rand()%4;
		int nx=fx[r][0],ny=fx[r][1],zx=zj[r][0],zy=zj[r][1];
		if(x+nx<1||x+nx>n||y+ny<1||y+ny>m) {f[r]=1;continue;}
		if(dt[x+zx][y+zy]!=WALL||v[x+zx][y+zy]||v[x+nx][y+ny]) {f[r]=1;continue;}
		f[r]=1;
		dt[x+zx][y+zy]=KONG;
		v[x+zx][y+zy]=v[x+nx][y+ny]=1;
		dfs(x+nx,y+ny);
	}
	return ;
}

void make_way()
{
	memset(v,0,sizeof v);//一般的初始化 
	memset(dt,WALL,sizeof dt);
	start.x=2,start.y=2;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			if(i==1||i==n||j==1||j==m) dt[i][j]=WALL;
			if(i%2==0&&j%2==0) dt[i][j]=KONG;
			else dt[i][j]=WALL;
		}
	for(int i=1;i<=t;i++)for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)//标记房间
		for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++) dt[y][x]=KONG,v[y][x]=1;
	for(int i=0;i<=n;i++)for(int j=1;j<=m;j++)//建路
		if(dt[i][j]==KONG&&dt[i-1][j]==WALL&&dt[i+1][j]==WALL&&dt[i][j-1]==WALL&&dt[i][j+1]==WALL) dfs(i,j);
}
 
void connect()//连接路与房间 
{
	const int ch=3;//3%的概率选中
	int sum=0;
	for(int i=1;i<=t;i++)//枚举房间,分别枚举上面的边,左边的边,下面的边和右边的边
	{
		for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++)//先找能与之相连的总数
		{
			if(dt[y][rm[i].x-2]==KONG) sum++;
			if(dt[y][rm[i].x+rm[i].lx+1]==KONG) sum++;
		}
		for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
		{
			if(dt[rm[i].y-2][x]==KONG) sum++;
			if(dt[rm[i].y+rm[i].ly+1][x]==KONG) sum++;
		}
		bool b=0;//暴力枚举连边 
		while(!b)
		{
			for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++)
			{
				if(dt[y][rm[i].x-2]==KONG){if(rand()%100<ch||sum==1){dt[y][rm[i].x-1]=KONG,b=1,sum--;continue;}sum--;}
				if(dt[y][rm[i].x+rm[i].lx+1]==KONG){if(rand()%100<ch||sum==1){dt[y][rm[i].x+rm[i].lx]=KONG,b=1,sum--;continue;}sum--;}
			}
			for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
			{
				if(dt[rm[i].y-2][x]==KONG){if(rand()%100<ch||sum==1){dt[rm[i].y-1][x]=KONG,b=1,sum--;continue;}sum--;}
				if(dt[rm[i].y+rm[i].ly+1][x]==KONG){if(rand()%100<ch||sum==1){dt[rm[i].y+rm[i].ly][x]=KONG,b=1,sum--;continue;}sum--;}
			}
		}
	}
	return;
}
 
void get_end()//取出死路位置,但注意之前的代码有bug,现在改了 
{
	int sx=0,sy=0;
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(dt[i][j]==KONG)sx=i,sy=j;
	queue<play_er> q;
	while(!q.empty()) q.pop();
	bool vis[1010][1010];
	memset(vis,0,sizeof vis);
	q.push((play_er){sx,sy});
	vis[sx][sy]=1;
	while(!q.empty())
	{
		play_er p=q.front();
		q.pop();
		for(int i=0;i<4;i++)
		{
			int X=p.x+zj[i][0],Y=p.y+zj[i][1];
			if(!vis[X][Y]&&dt[X][Y]==KONG) q.push((play_er){X,Y}),vis[X][Y]=1;
		}
		int f=4;//删路 
		for(int i=0;i<4;i++)
		{
			int X=p.x+zj[i][0],Y=p.y+zj[i][1];
			if(dt[X][Y]==KONG) f--;
		}
		if(f==3) e[++t]=p;
	}
}
 
void try__()//反复删除 
{
	get_end();
	while(1)//删掉awa 
	{
		if(t==0) get_end();
		if(t==0) break;
		dt[e[t].x][e[t].y]=WALL;
		t--;
	}
}

void tian()//填充颜色&&判断是否合法 
{
	int sx=0,sy=0;
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(dt[i][j]==KONG)sx=i,sy=j;
	queue<play_er> q;
	while(!q.empty()) q.pop();
	bool vis[1010][1010];
	memset(vis,0,sizeof vis);
	vis[sx][sy]=1;
	q.push((play_er){sx,sy});
	while(!q.empty())
	{
		play_er p=q.front();
		q.pop();
		for(int i=0;i<4;i++)
		{
			int X=p.x+zj[i][0],Y=p.y+zj[i][1];
			if(!vis[X][Y]&&dt[X][Y]==KONG)q.push((play_er){X,Y}),vis[X][Y]=1;
		}
	}
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(dt[i][j]==KONG&&!vis[i][j]){D=1;return;}
}
 
void del()
{
	tian();//填充+广搜判断是否全联通 
	if(D) return;
	try__();
}

void optimize()
{
	int sx=0,sy=0;
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(dt[i][j]==KONG)sx=i,sy=j;
	queue<play_er> q;
	while(!q.empty()) q.pop();
	bool vis[1010][1010],v2[1010][1010];
	memset(vis,0,sizeof vis);
	memset(v2,0,sizeof v2);
	vis[sx][sy]=1;
	q.push((play_er){sx,sy});
	while(!q.empty())
	{
		play_er p=q.front();
		q.pop();
		for(int i=0;i<4;i++)
		{
			int X=p.x+zj[i][0],Y=p.y+zj[i][1];
			if(!vis[X][Y]&&dt[X][Y]==KONG)q.push((play_er){X,Y}),vis[X][Y]=1;
		}
	}
	int fx[]={0,-1,-1,-1,0,0,1,1,1},fy[]={0,-1,0,1,-1,1,-1,0,1};
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(vis[i][j])for(int k=0;k<=8;k++)v2[i+fx[k]][j+fy[k]]=1;
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(!v2[i][j])dt[i][j]=KONG;
}

void make_dt()
{
	zzb:
	try_(),make_way(),connect(),del();
	if(D)
	{
		D=0;
		goto zzb;
	}
	optimize(); 
	freopen("mp.txt","w",stdout);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++) printf("%c",dt[i][j]==WALL?'#':' ');
		puts("");
	}
}

int main()
{
	srand(time(NULL));
	hide();
	noedit();
	make_dt();
	return 0;
}

不过,在我的代码中,你可以把它当头文件生成mp后在读入

也可以直接用数组dt当地图用

注意一点:

dt[i][j]==KONG 代表是可经过的路
dt[i][j]==WALL 代表的是不可经过的墙(直接用KONG和WALL,毕竟KONG是2,WALL是-1···) 

 警示:

1.注意c++运行框建系后是

0 1 2 3 4 5 5 6 7 8 9
---------------------->x
|1
|2
|3
|4
|5
|6
|7
|8
V
y 

(当时卡了我好久啊awa)

2.用color的时候小心,一定要看清颜色是什么

我用color0(0当时是黑色),结果地图隐藏了,调了很久

3.后文

建议这种代码还是要自己写,写这些对你来说可以练习模拟,一些算法,也有心态。写不出来那就多练awa鬼知道我想放弃想了几次

像这些最好看一下注释,多理解一下(能想出更优的办法更好)

(看在zzb这么努力的份上,给个关注吧awa)

(提一嘴,有没有第五的大佬带一下新手awa)

参考文章:房间和迷宫:一个地牢生成算法

上一篇:c++游戏小技巧15:前14篇总结

下一篇:未完待续

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【牛客】值周

原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 差分。 因为l<100000000,所以数组开1e8。 唯一需要注意的点就是前面给b[0]单独赋值为1&#xff08;因为如果在循环中给b[0]赋值&…

MIT加州理工等革命性KAN破记录,发现数学定理碾压DeepMind!KAN论文解读

KAN的数学原理 如果f是有界域上的多元连续函数&#xff0c;那么f可以被写成关于单个变量和加法二元操作的连续函数的有限组合。更具体地说&#xff0c;对于光滑函数f&#xff1a;[0, 1]ⁿ → R&#xff0c;有 f ( x ) f ( x 1 , … , x n ) ∑ q 1 2 n 1 Φ q ∑ p 1 n …

解决Pyppeteer下载chromium慢或者失败的问题[INFO] Starting Chromium download.

文章目录 1.进入网址2.选择上面对应自己系统的文件夹进去3. 然后找到自己的python环境中的site-packages中pyppeteer中的chromium_downloader.py文件并打开 在首次使用Pyppeteer时需要下载chromium 1.进入网址 https://registry.npmmirror.com/binary.html?pathchromium-bro…

贪心算法应用例题

最优装载问题 #include <stdio.h> #include <algorithm>//排序int main() {int data[] { 8,20,5,80,3,420,14,330,70 };//物体重量int max 500;//船容最大总重量int count sizeof(data) / sizeof(data[0]);//物体数量std::sort(data, data count);//排序,排完数…

品高虚拟化后端存储的发展演进

在品高虚拟化技术不断发展的过程中&#xff0c;虚拟化的后端存储一直是关注的焦点之一。 本文将从最初的文件存储和NFS开始&#xff0c;追溯到集中式存储SAN&#xff0c;然后选择了Ceph的RBD方式&#xff0c;并最终抵达选择支持vhost协议的后端存储的现状&#xff0c;我们将探…

使用wxPython和pandas模块生成Excel文件

介绍&#xff1a; 在Python编程中&#xff0c;有时我们需要根据特定的数据生成Excel文件。本文将介绍如何使用wxPython和pandas模块来实现这个目标。我们将创建一个简单的GUI应用程序&#xff0c;允许用户选择输出文件夹和输入的Excel文件&#xff0c;并根据Excel文件中每个单…

图像处理技术与应用(四)

图像处理技术与应用入门 颜色空间及其转换 颜色空间是一种用于在数字图像中表达和指定颜色的方法。不同的颜色空间使用不同的方式来定义颜色&#xff0c;每种方式都有其特定的用途和优势。以下是一些常见的颜色空间及其特点&#xff1a; RGB&#xff08;红绿蓝&#xff09;&a…

每日一题(PTAL2):列车调度--贪心+二分

选择去维护一个最小区间 代码1&#xff1a; #include<bits/stdc.h> using namespace std; int main() {int n;cin>>n;int num;vector <int> v;int res0;for(int i0;i<n;i){cin>>num;int locv.size();int left0;int rightv.size()-1;while(left<…

AIGC技术带给我们什么?基于AIGC原理及其技术更迭的思考

AIGC技术带给我们什么&#xff1f;基于AIGC原理以及技术更迭的思考 前言 AI&#xff0c;这个词在如今人们的视野中出现频率几乎超过了所有一切其他的事物&#xff0c;更有意思的是&#xff0c;出现频率仅次于这个词的&#xff0c;几乎都会加上一个修饰亦或是前缀——AI&#…

快速排序找出第K大的元素

有序数组里第 K 大的元素就是index 为 array.length - k 的元素。 快速排序的思路主要就是选一个基准值p&#xff0c;然后将小于p的值放在p的左右&#xff0c;大于p的值放在p的右边&#xff0c;然后对左右数组进行递归。 利用这个思路&#xff0c;当我们找到这个基准值对应的 i…

【教学类-50-14】20240505“数一数”图片样式12:数一数(12个“人物”图案)

作品展示 背景需求&#xff1a; 前文做了“”材料”图片的数一数学具&#xff0c;效果不错&#xff0c; https://blog.csdn.net/reasonsummer/article/details/138466325https://blog.csdn.net/reasonsummer/article/details/138466325 为了让图案内容更丰富&#xff0c;我又…

Python Dash库:一个Web应用只需几行代码

大家好&#xff0c;在数据科学领域&#xff0c;数据可视化是将数据以图形化形式展示出来&#xff0c;帮助我们更直观地理解数据。Python中有一个非常流行的数据可视化库叫做Dash&#xff0c;Dash以其简洁、高效和强大的功能而闻名&#xff0c;它允许开发者快速构建交互式Web应用…

【智能算法】人类进化优化算法(HEOA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.代码获取 1.背景 2024年&#xff0c;J Lian受到人类进化启发&#xff0c;提出了人类进化优化算法&#xff08;Human Evolutionary Optimization Algorithm, HEOA&#xff09;。 2.算法原理 2.1算法思想 …

JavaWEB 框架安全:Spring 漏洞序列.(CVE-2022-22965)

什么叫 Spring 框架. Spring 框架是一个用于构建企业级应用程序的开源框架。它提供了一种全面的编程和配置模型&#xff0c;可以简化应用程序的开发过程。Spring 框架的核心特性包括依赖注入&#xff08;Dependency Injection&#xff09;、面向切面编程&#xff08;Aspect-Or…

Springboot项目学习之各组件的用法和逻辑结构

1.Controller层&#xff08;Controller&#xff09;&#xff1a; 也称为前端控制器或请求处理器&#xff0c;它是项目与用户交互的入口。Controller接收HTTP请求&#xff0c;解析请求参数&#xff0c;调用Service层处理业务逻辑&#xff0c;并返回响应给客户端。 Controller通…

IP证书能免费申请吗

IP SSL证书是一种数字证书&#xff0c;用于保护网络服务器和网络浏览器之间的通信。该证书是一种主要保护公网IP地址的专属信任SSL证书。 IP类型的SSL证书对于直接用IP地址传输数据的技术人员来说&#xff0c;十分重要&#xff01;无论是防洪还是防劫持还是数据加密都起到了关…

【C 数据结构-动态内存管理】4. 无用单元收集(垃圾回收机制)

文章目录 【 1. 问题描述与解决方法 】【 2. 中断回收机制 】 【 1. 问题描述与解决方法 】 问题描述 动态存储管理的运行机制可以概括为&#xff1a;当用户发出申请空间的请求后&#xff0c;系统向用户分配内存&#xff1b;用户运行结束释放存储空间后&#xff0c;系统回收内…

【FL常用插件#1】Ozone11臭氧的安装和使用

本文内容收集自互联网&#xff0c;仅供个人学习参考使用&#xff0c;不允许用于商业用途&#xff0c;造成的侵权行为与本文作者无关 安装 VST2、VST3、AAX和NKS是音频技术界常见的几种插件格式&#xff0c;它们在功能和兼容性上有所不同&#xff1a; VST2 (Virtual Studio Tec…

用户管理中心——数据库设计用户注册逻辑设计

用户管理中心——数据库设计&用户注册逻辑设计 规整项目目录1. 数据库自动生成器的使用实现基本的数据库操作&#xff08;操作user表&#xff09; 2. 注册逻辑的设计(1) 写注册逻辑(2) 实现(3) 测试代码 3. 遇到的问题 规整项目目录 utils–存放工具类&#xff0c;比如加密…

关系型数据库MySQL开发要点之多表设计案例详解代码实现

什么是多表设计 项目开发中 在进行数据库表结构设计时 根据数据模型和业务关系 会根据业务需求和业务模块之间的关系分析设计表结构 由于业务之间互相关联 所以表结构之间也存在着各种联系 主要分为以下三种 一对多 每个部门下是有多个员工的 但是一个员工只能归属一个部…