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

news2024/11/16 23:33:48

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篇总结

下一篇:未完待续

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

百面算法工程师 | 正则优化函数——BN、LN、Dropout

本文给大家带来的百面算法工程师是正则优化函数&#xff0c;文章内总结了常见的提问问题&#xff0c;旨在为广大学子模拟出更贴合实际的面试问答场景。在这篇文章中&#xff0c;我们将总结一些BN、LN、Dropout的相关知识&#xff0c;并提供参考的回答及其理论基础&#xff0c;以…

redis深入理解之数据存储

1、redis为什么快 1&#xff09;Redis是单线程执行&#xff0c;在执行时顺序执行 redis单线程主要是指Redis的网络IO和键值对读写是由一个线程来完成的&#xff0c;Redis在处理客户端的请求时包括获取(socket 读)、解析、执行、内容返回 (socket 写)等都由一个顺序串行的主线…

网络编程套接字 (二)---udosocket

本专栏内容为&#xff1a;Linux学习专栏&#xff0c;分为系统和网络两部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握Linux。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;网络 &#x1f69a;代码仓库&#xff1a;小小unicorn的代…

mikefile函数与实用模板

文章目录 0.概述1.函数调用语法2.字符串处理函数2.1 subst&#xff08;字符串替换函数&#xff09;2.2 patsubst&#xff08;模式字符串替换函数&#xff09;2.3 strip&#xff08;去空格函数&#xff09;2.4 findstring&#xff08;查找字符串函数&#xff09;2.5 filter&…

大型模型技术构建本地知识库

使用大型模型技术构建本地知识库是一个复杂的过程&#xff0c;涉及到数据科学、机器学习和软件工程等多个领域的知识。以下是构建本地知识库的一般步骤。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.需求分析&#xff1a; 确定知…

java版数据结构:堆,大根堆,小根堆

目录 堆的基本概念&#xff1a; 如何将一个二叉树调整成一个大根堆&#xff1a; 转成大根堆的时间复杂度 根堆中的插入&#xff0c;取出数据&#xff1a; 堆的基本概念&#xff1a; 堆是一种特殊的树形数据结构&#xff0c;它满足以下两个性质&#xff1a; 堆是一个完全二叉…

常见物联网面试题详解

物联网一直是非常火热的行业&#xff0c;G端如智慧城市、智慧工厂、智慧园区、智慧水利、智慧矿山等行业&#xff0c;都会涉及到物联网&#xff0c;基本都是软硬一体&#xff0c;因此当面试相关企业时&#xff0c;物联网平台是面试企业重点考察的项&#xff0c;小伙伴如果从事相…

网络安全在数字时代的重要性:以近期网络安全事件为镜

在当今这个信息化爆炸的时代&#xff0c;互联网如同一张无形的网&#xff0c;将我们的生活、工作、学习紧密相连。然而&#xff0c;这张网在带来便捷的同时&#xff0c;也暗藏着无数的安全隐患。近年来&#xff0c;网络安全事件频发&#xff0c;从个人隐私泄露到企业数据被盗&a…

中国地图(2024版审图号地图)和地图变化说明

2024版shp格式审图号地图预览图&#xff1a; 新版中国地图的变化&#xff08;简述&#xff09; 国土面积的增加&#xff1a;新版中国地图显示&#xff0c;中国的国土面积从960万平方公里增加到1045万平方公里&#xff0c;增加了85万平方公里。 九段线变为十段线&#xff1a;…

如何使用 ArcGIS Pro 制作地震动画

在做某些汇报的时候&#xff0c;除了图文&#xff0c;如果有动画肯定会成为加分项&#xff0c;这里为大家介绍一下如何使用 ArcGIS Pro 制作地震动画&#xff0c;希望能对你有所帮助。 添加时间 在图层属性内&#xff0c;选择时间选项卡&#xff0c;图层时间选择每个要素具有…

每日两题 / 226. 翻转二叉树 98. 验证二叉搜索树(LeetCode热题100)

226. 翻转二叉树 - 力扣&#xff08;LeetCode&#xff09; 以后续遍历的方式交换当前节点的左右指针 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), ri…

自适应调节Q和R的自适应UKF(AUKF_QR)的MATLAB程序

简述 基于三维模型的UKF&#xff0c;设计一段时间的输入状态误差较大&#xff0c;此时通过对比预测的状态值与观测值的残差&#xff0c;在相应的情况下自适应调节系统协方差Q和观测协方差R&#xff0c;构成自适应无迹卡尔曼滤波&#xff08;AUKF&#xff09;&#xff0c;与传统…

你可能喜欢但也许还不知道的好用网站-搜嗖工具箱

在线工具 https://www.zxgj.cn/ 作为一个工作生活好帮手&#xff0c;在线咨询网站提供了丰富的实用功能&#xff0c;从工作中的图表制作、图片修改到生活中的各种测试、健康、娱乐、学习、理财等等涵盖面很广。 在线工具网站从界面和操作上来看对用户也很友好&#xff0c;页面…

提高Rust安装与更新的速度

一、背景 因为rust安装过程中&#xff0c;默认的下载服务器为crates.io&#xff0c;这是一个国外的服务器&#xff0c;国内用户使用时&#xff0c;下载与更新的速度非常慢&#xff0c;因此&#xff0c;我们需要使用一个国内的服务器来提高下载与更新的速度。 本文推荐使用字节…

谷歌地图商家采集在外贸客户开发中的作用和意义

谷歌地图商家采集在外贸客户开发中扮演着至关重要的角色&#xff0c;其主要作用和意义体现在以下几个方面&#xff1a; 精准定位目标市场&#xff1a;通过谷歌地图&#xff0c;外贸人员可以根据特定的行业关键词&#xff08;如“fabric stores”&#xff09;搜索目标国家或地区…

Redis加入系统服务,开机自启

vi /etc/systemd/system/redis.service i :wq #加载服务配置文件 systemctl daemon-reload #启动redis systemctl start redis #设置开机自启 systemctl enable redis #查看启动状态 systemctl status redis

11.买卖股票的最佳时机Ⅰ

文章目录 题目简介题目解答解法一&#xff1a;一次遍历代码&#xff1a;复杂度分析&#xff1a; 题目链接 大家好&#xff0c;我是晓星航。今天为大家带来的是 买卖股票的最佳时机面试题Ⅰ 相关的讲解&#xff01;&#x1f600; 题目简介 题目解答 解法一&#xff1a;一次遍历…

汗之谜语,流产之哀:肾合唤醒生命花园的璀璨绽放

在这个疾驰的时代洪流中&#xff0c;女性宛若四季更迭间绚烂绽放的花朵&#xff0c;她们在风雨的锤炼与暖阳的抚慰下&#xff0c;演绎着生命的绚烂篇章。但当这份细腻柔美的内在花园偶遇冷冽寒潮&#xff0c;诸如汗水的异常涌动与生命的意外流失&#xff0c;就如同春暖花开之际…

01面向类的讲解

指针指向类成员使用 代码&#xff1a; #include<iostream> using namespace std;class Test { public:void func() { cout << "call Test::func" << endl; }static void static_func();int ma;static int mb; //不依赖对象 }; void Test::static…

【强化学习-Mode-Free DRL】深度强化学习如何选择合适的算法?DQN、DDPG、A3C等经典算法Mode-Free DRL算法的四个核心改进方向

【强化学习-DRL】深度强化学习如何选择合适的算法&#xff1f; 引言&#xff1a;本文第一节先对DRL的脉络进行简要介绍&#xff0c;引出Mode-Free DRL。第二节对Mode-Free DRL的两种分类进行简要介绍&#xff0c;并对三种经典的DQL算法给出其交叉分类情况&#xff1b;第三节对…