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)

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

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

下一篇:c++游戏小技巧17:局域网联机(全网最详细)

  • 17
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值