1.前言
(头图)
(其实最开始是想写恶魔轮盘的,但没想到它竟然更新了···)
(等我有时间在更,最近很忙,玩第五玩的)
想法来源:房间和迷宫:一个地牢生成算法https://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篇总结
下一篇:未完待续