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.Yvoid 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 2int 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.Yint 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 2int 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.Yvoid 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 2int 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.Yvoid 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 2bool 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.Yvoid 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 2bool 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.mzph.cn/diannao/6399.shtml

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

相关文章

机器学习(五)之损失函数

上面几节讲了监督学习和非监督学习的一些算法&#xff08;目前还不完整&#xff0c;会慢慢补充哒) 如果文章内容有错误&#xff0c;欢迎小伙伴在评论区指出! 前言&#xff1a; 损失函数在机器学习中非常重要&#xff0c;直接关乎模型的好坏&#xff08;so?学好它&#xff09;…

STM32G474 CMAKE VSCODE 开发环境搭建

本篇博文尝试搭建 stm32g474 的开发环境 一. 工具安装 1. 关于 MinGW、OpenOCD、Zadig 这些工具的下载和安装见 JlinkOpenOCDSTM32 Vscode 下载和调试环境搭建_vscode openocd stm32 jlink-CSDN博客 2. 导出一个 STM32 的 CMAKE 工程&#xff0c;这里略过。 3. 安装 ninja …

matlab期末知识

1.期末考什么&#xff1f; 1.1 matlab操作界面 &#xff08;1&#xff09;matlab主界面 &#xff08;2&#xff09;命令行窗口 &#xff08;3&#xff09;当前文件夹窗口 &#xff08;4&#xff09;工作区窗口 &#xff08;5&#xff09;命令历史记录窗口 1.2 matlab搜索…

Elasticsearch:对 Java 对象的 ES|QL 查询

作者&#xff1a;Laura Trotta ES|QL 是 Elasticsearch 引入的一种新的查询语言&#xff0c;它将简化的语法与管道操作符结合起来&#xff0c;使用户能够直观地推断和操作数据。官方 Java 客户端的新版本 8.13.0 引入了对 ES|QL 查询的支持&#xff0c;提供了一个新的 API&…

Redis 实战2

系列文章目录 本文将从字典的实现、哈希算法、解决键冲突、rehash、渐进式rehash几方面来阐述 Redis 实战Ⅱ 系列文章目录字典的实现哈希算法解决键冲突rehash渐进式 rehash渐进式 rehash 执行期间的哈希表操作 字典 API总结 字典的实现 Redis 的字典使用哈希表作为底层实现&…

【大数据】学习笔记

文章目录 [toc]NAT配置IP配置SecureCRT配置PropertiesTerminal Java安装环境变量配置 Hadoop安装修改配置文件hadoop-env.shyarn-env.shslavescore-site.xmlhdfs-site.xmlmapred-site.xmlyarn-site.xml 环境变量配置 IP与主机名映射关系配置hostname配置映射关系配置 关闭防火墙…

分层图像金字塔变压器

文章来源&#xff1a;hierarchical-image-pyramid-transformers 2024 年 2 月 5 日 本文介绍了分层图像金字塔变换器 (HIPT)&#xff0c;这是一种新颖的视觉变换器 (ViT) 架构&#xff0c;设计用于分析计算病理学中的十亿像素全幻灯片图像 (WSI)。 HIPT 利用 WSI 固有的层次结…

【matlab基础知识】(三)二维曲线绘制plot

x[-pi:0.0001:pi]; 选择较小步距 ysin(tan(x))-tan(sin(x));plot(x,y) 条件和函数值做一个点乘 x[-2:0.02:2];y1.1*sign(x).*(abs(x)>1.1)x.*(abs(x)<1.1);plot(x,y) 颜色&#xff0c;线形&#xff0c;曲线上的标志 由于0.01cosx波动太小&#xff0c;所以plotyy绘制多…

正在载入qrc文件 指定的qrc文件无法找到。您想更新这个文件的位置么?

打开Qt的ui文件&#xff0c;弹出提示框 如果需要用到qrc文件&#xff0c;选择Yes&#xff0c;再选择qrc文件所在的位置&#xff1b;如果不需要qrc文件&#xff0c;可以选择No&#xff0c;然后用普通文本编辑器打开&#xff0c;将“ <resources> <include location&q…

ARP欺骗使局域网内设备断网

一、实验准备 kali系统&#xff1a;可使用虚拟机软件模拟 kali虚拟机镜像链接&#xff1a;https://www.kali.org/get-kali/#kali-virtual-machines 注意虚拟机网络适配器采用桥接模式 局域网内存在指定断网的设备 二、实验步骤 打开kali系统命令行&#xff1a;ctrlaltt可快…

Zookeeper服务

一、什么是Zookeeper Zookeeper 是一个分布式应用程序的协调服务&#xff0c;它提供了一个高性能的分布式配置管理、分布式锁服务和分布式协调服务。它是 Apache 软件基金会的一个项目&#xff0c;被设计用来处理大规模的分布式系统中的一些关键问题。 Zookeeper的组成员关系&…

【C语言】——结构体

【C语言】——结构体 一、结构体类型的声明1.1、结构体的声明1.2、结构体变量的创建和初始化1.3、结构体的特殊声明1.4、结构体的自引用1.5、结构体的重命名 二、 结构体的内存对齐2.1、对齐规则2.2、结构体对齐实践2.3、为什么存在内存对齐2.4、修改默认对齐数 三、结构体传参…

VS Code 保存+格式化代码

在 VSCode 中&#xff0c;使用 Ctrl S 快捷键直接保存并格式化代码&#xff1a; 打开 VSCode 的设置界面&#xff1a;File -> Preferences -> Settings在设置界面搜索框中输入“format on save”&#xff0c;勾选“Editor: Format On Save”选项&#xff0c;表示在保存…

《Mask2Former》算法详解

文章地址&#xff1a;《Masked-attention Mask Transformer for Universal Image Segmentation》 代码地址&#xff1a;https://github.com/facebookresearch/Mask2Former 文章为发表在CVPR2022的一篇文章。从名字可以看出文章像提出一个可以统一处理各种分割任务&#xff08;…

C++ | Date 日期类详解

目录 简介 日期类总代码 | Date 类的定义 & 构造 & Print 类的定义 构造函数 & Print 比较类&#xff0c;如<、>、<...... 值加减类&#xff0c;如、-、、-...... 加减类具体分类 判断某个月有多少天 GetMonthDay 日期类 / &#xff08;- / -&…

随便聊一下 显控科技 控制屏 通过 RS485 接口 上位机 通讯 说明

系统搭建&#xff1a; 1、自己研发的一个小系统&#xff08;采集信号&#xff0c;将采集的信号数字化&#xff09;通过COM口&#xff0c;连接显控屏 COM3 口采用 485 协议送到显控屏&#xff08;显控科技&#xff09;的显示屏展示出来&#xff09;。 2、显控屏 将 展示的数据…

Jenkins(超详细的Docker安装Jenkins教程!!!)

Jenkins Jenkins&#xff0c;原名 Hudson&#xff0c;2011 年改为现在的名字。它是一个开源的实现持续集成的软件工具。 官方网站&#xff1a;https://www.jenkins.io/ 中文文档&#xff1a;https://www.jenkins.io/zh/ 为什么需要Jenkins&#xff1f; 我们以前写完代码&a…

Excel中怎样把单元格里的数据拆分成多行?

时常会遇到这种情况&#xff0c;需要将一个单元格里的数据分拆到多行&#xff0c;可以使用公式&#xff0c;这里演示使用基础操作的办法。 按照excel使用经验&#xff0c;可以复制数据&#xff0c;粘贴到MS Word里&#xff0c;这个是excel的同族软件&#xff0c;兼容性好。 在…

Redis的面试

认识Redis 认识NoSQL SQL&#xff08;关系型数据库&#xff09; NoSQL&#xff08;非关系型数据库&#xff09; 1.结构化 非结构化 2.关联的 非关联的 3.SQL查询 非SQL 4.事务 …

[C++基础学习-07]----C++结构体详解

前言 结构体&#xff08;Struct&#xff09;是C中一种用户定义的复合数据类型&#xff0c;用于存储不同类型的数据项。结构体可以包含不同类型的数据成员&#xff0c;这些数据成员可以是基本类型&#xff08;如int、float、char等&#xff09;&#xff0c;也可以是数组、指针、…