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.Y
void try_()
{
memset(rm,0,sizeof rm);t=0;
for(int i=1;i<=c;i++)
{
int x=rand()%cx,y=rand()%(cy-3),lx=rand()%11+20,ly=rand()%6+7;//房间大小我设定的是位于20,7到30,12之间
bool f=1;
if(x+lx>=cx||y+ly>=cy-3) f=0;
for(int j=1;j<=t&&f;j++)
{
room_ r=rm[j];
if((max(x,r.x)<=min(r.x+r.lx,x+lx))&&(max(-r.y-r.ly,-y-ly)<=min(-r.y,-y))) f=0;//判断是否有房间重合
}
if(f) rm[++t]=(room_){x,y,lx,ly};
}
for(int i=1;i<=t;i++)
for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++)
gotoxy(x,y),printf((x==rm[i].x||x==rm[i].x+rm[i].lx-1||y==rm[i].y||y==rm[i].y+rm[i].ly-1)?"#":" ");
gotoxy(0,cy-3);
for(int i=0;i<cx;i++) printf("-");
}
int main()
{
srand(time(NULL));
full();
hide();
gotoxy(0,cy-3);
for(int i=0;i<cx;i++) printf("-");
puts("");
printf("当前尝试数: %d 次(a增加,d减少,回车启动,Esc退出) ",c);
while(1)
{
if(kd(VK_ESCAPE)) break;
gotoxy(0,cy-2);
printf("当前尝试数: %d 次(a增加,d减少,回车启动,Esc退出) ",c);
gotoxy(0,0);
if(kd('A')) c=max(c-10,10);//c是尝试次数
if(kd('D')) c=min(c+10,1000);
if(kd(VK_RETURN)) cls,try_();
Sleep(30);
}
return 0;
}
2.一个黑暗扭曲的走廊
这个反而还要比上面的简单吧(?)
大意描述就是给一个迷宫,然后找死路的最后一个点,删掉(又是不会描述的一天)
具体见下面代码(我把路和墙反过来,“#”代表的是路)
#include<bits/stdc++.h>
#include<windows.h>
using namespace std;
namespace init_ //小技巧15plus
{
#define kd(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000)?1:0)
#define sl(n) Sleep(n)
#define cls system("cls")
void gotoxy(int x,int y){COORD pos={(short)x,(short)y};HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOut,pos);return;}
void noedit(){HANDLE hStdin=GetStdHandle(STD_INPUT_HANDLE);DWORD mode;GetConsoleMode(hStdin,&mode);mode&=~ENABLE_QUICK_EDIT_MODE;mode&=~ENABLE_INSERT_MODE;mode&=~ENABLE_MOUSE_INPUT;SetConsoleMode(hStdin,mode);}
void hide(){CONSOLE_CURSOR_INFO cur={1,0};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
void show(){CONSOLE_CURSOR_INFO cur={1,1};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
}
using namespace init_;
#define m 239
#define n 61
#define WALL -1
#define KONG 2
int c;
struct play_er{int x,y;}start;
int dt[1010][1010];
int fx[5][5]={{2,0},{-2,0},{0,2},{0,-2}};
int zj[5][5]={{1,0},{-1,0},{0,1},{0,-1}};
bool v[1010][1010]={0};
void init()//迷宫初始化
{
memset(v,0,sizeof v);
start.x=2,start.y=2;
memset(dt,WALL,sizeof dt);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i==1||i==n||j==1||j==m) dt[i][j]=WALL;
if(i%2==0&&j%2==0) dt[i][j]=KONG;
else dt[i][j]=WALL;
}
}
dt[2][2]=KONG;
}
void dfs(int x,int y)//造迷宫
{
bool f[5]={0};
while(1)
{
if(f[0]&&f[1]&&f[2]&&f[3]) return ;
int r=rand()%4;
int nx=fx[r][0],ny=fx[r][1],zx=zj[r][0],zy=zj[r][1];
if(x+nx<1||x+nx>n||y+ny<1||y+ny>m) {f[r]=1;continue;}//return ;
if(dt[x+zx][y+zy]!=WALL||v[x+zx][y+zy]||v[x+nx][y+ny]) {f[r]=1;continue;}//return ;
f[r]=1;
dt[x+zx][y+zy]=KONG;
v[x+zx][y+zy]=v[x+nx][y+ny]=1;
dfs(x+nx,y+ny);
}
return ;
}
void full()//全屏窗口,方便调试
{
system("mode con cols=50 lines=60");//随便设定一个值隐藏滚动条
HWND hwnd=GetForegroundWindow();
int cx=GetSystemMetrics(SM_CXSCREEN),cy=GetSystemMetrics(SM_CYSCREEN);//获得屏幕高度与宽度
LONG lw=GetWindowLong(hwnd,GWL_STYLE);
SetWindowLong(hwnd,GWL_STYLE,(lw|WS_POPUP|WS_MAXIMIZE)&~WS_CAPTION&~WS_THICKFRAME&~WS_BORDER);
SetWindowPos(hwnd,HWND_TOP,0,0,cx,cy,0);
}
CONSOLE_SCREEN_BUFFER_INFO getxy()//小技巧9
{
CONSOLE_SCREEN_BUFFER_INFO bInfo;
HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hConsole,&bInfo);
return bInfo;
}
#define cx getxy().dwMaximumWindowSize.X
#define cy getxy().dwMaximumWindowSize.Y
int MX;//不知道为什么,mx的值是不变的
void get_MX()//取出路径总数
{
MX=0;
init();
dfs(2,2);
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(dt[i][j]==KONG) MX++;
}
play_er e[114514];
int t;
void get_end()//取出思路位置
{
int sx,sy;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(dt[i][j]==KONG) sx=i,sy=j;
queue<play_er> q;
while(!q.empty()) q.pop();
bool vis[1010][1010];
memset(vis,0,sizeof vis);
vis[sx][sy]=1;
q.push((play_er){sx,sy});
while(!q.empty())
{
play_er p=q.front();
q.pop();
bool f=0;
for(int i=0;i<4;i++)
{
int X=p.x+zj[i][0],Y=p.y+zj[i][1];
if(!vis[X][Y]&&dt[X][Y]==KONG)
{
f=1;
q.push((play_er){X,Y});
vis[X][Y]=1;
}
}
if(!f) e[++t]=p;
}
}
void try_()//反复删除
{
init();//先建路
dfs(2,2);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(dt[i][j]==KONG) printf("#");
else printf(" ");
}
printf("\n");
}
get_end();
for(int i=1;i<=c;i++)//删掉awa
{
if(t==0) get_end();
dt[e[t].x][e[t].y]=WALL;
gotoxy(e[t].y-1,e[t].x-1);//没错,我当时把这一行放在了t--下面调了1个小时
t--;
printf(" ");
Sleep(1);
}
gotoxy(0,cy-3);
for(int i=0;i<cx;i++) printf("-");
}
int main()
{
init();
hide();
full();
srand(time(NULL));
get_MX();
c=MX/2;
gotoxy(0,cy-3);
for(int i=0;i<cx;i++) printf("-");
puts("");
printf("当前尝试数: %d 次(a增加,d减少,回车启动,Esc退出) ",c);
while(1)
{
if(kd(VK_ESCAPE)) break;
gotoxy(0,cy-2);
printf("当前尝试数: %d 次(a减少,d增加,回车启动,Esc退出) ",c);
gotoxy(0,0);
if(kd('A')) c=max(c-50,1);
if(kd('D')) c=min(c+50,MX);
if(kd(VK_RETURN)) cls,try_();//c是尝试
Sleep(30);
}
return 0;
}
这个思路比较简单,代码码起也不难(我就码了1.5h)
3.房间,然后是迷宫
我在这里一直很纠结
就一直在想到底是以
#####
#####
###########
##### #
##### #
#
#
##############
##############
##############
##############
的形式,还是以
#####
# ########
# #
# ###### #
##### # #
# #
# #
###### #######
# #
# #
##############
的形式
最后犹豫了很久,选择了好码的方式
这一个板块相对来说比较有模拟性(?)
就是先按造房间、造迷宫
但需要注意的是,先造房间再造迷宫与先造迷宫在造房间是不一样的
1.先造房间再造迷宫
这个注意一点
dfs生成迷宫的方式是给地图初始化成
#############
# # # # # # #
#############
# # # # # # #
#############
然后连接两个空格来造路
如果你先造房间就要注意其中的关系(我指的是不要造着造着路就到房间里面了)
2.先造迷宫再造房间
这个相对来说就简单亿点点了
造房间的时候,清空房间周围一圈的空地
我这边选用作者最开始使用的1号方案
先造房间,在填充迷宫
依然是全屏方便大家查看
#include<conio.h>
#include<windows.h>
#include<bits/stdc++.h>
using namespace std;
namespace init_ //小技巧15
{
#define kd(VK_NONAME) ((GetAsyncKeyState(VK_NONAME)&0x8000)?1:0)
#define sl(n) Sleep(n)
#define cls system("cls")
void gotoxy(int x,int y){COORD pos={(short)x,(short)y};HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOut,pos);return;}
void noedit(){HANDLE hStdin=GetStdHandle(STD_INPUT_HANDLE);DWORD mode;GetConsoleMode(hStdin,&mode);mode&=~ENABLE_QUICK_EDIT_MODE;mode&=~ENABLE_INSERT_MODE;mode&=~ENABLE_MOUSE_INPUT;SetConsoleMode(hStdin,mode);}
void hide(){CONSOLE_CURSOR_INFO cur={1,0};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
void show(){CONSOLE_CURSOR_INFO cur={1,1};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
}
using namespace init_;
namespace Color//加上颜色更加美观
{
void color(int a)
{
/*亮白*/if(a==0) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
/*蓝色*/if(a==1) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN|FOREGROUND_BLUE);
/*绿色*/if(a==2) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN);
/*紫色*/if(a==3) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_BLUE);
/*红色*/if(a==4) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED);
/*黄色*/if(a==5) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN);
/*深蓝*/if(a==6) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_BLUE);
/*金黄*/if(a==7) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_GREEN);
/*灰白*/if(a==8) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
}
void yanse(int ForgC,int BackC)
{
WORD wColor=((BackC&0x0F)<<4)+(ForgC&0x0F);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),wColor);
}
}
using namespace Color;
#define m 239
#define n 61
#define WALL -1
#define KONG 2
int t;
struct room_{int x,y,lx,ly;}rm[150];
struct play_er{int x,y;}start;
int dt[1010][1010];
int fx[5][5]={{2,0},{-2,0},{0,2},{0,-2}};
int zj[5][5]={{1,0},{-1,0},{0,1},{0,-1}};
bool v[1010][1010]={0};
void full()//全屏窗口,方便调试
{
system("mode con cols=50 lines=60");//随便设定一个值隐藏滚动条
HWND hwnd=GetForegroundWindow();
int cx=GetSystemMetrics(SM_CXSCREEN),cy=GetSystemMetrics(SM_CYSCREEN);//获得屏幕高度与宽度
LONG lw=GetWindowLong(hwnd,GWL_STYLE);
SetWindowLong(hwnd,GWL_STYLE,(lw|WS_POPUP|WS_MAXIMIZE)&~WS_CAPTION&~WS_THICKFRAME&~WS_BORDER);
SetWindowPos(hwnd,HWND_TOP,0,0,cx,cy,0);
}
CONSOLE_SCREEN_BUFFER_INFO getxy()//小技巧9
{
CONSOLE_SCREEN_BUFFER_INFO bInfo;
HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hConsole,&bInfo);
return bInfo;
}
#define cx getxy().dwMaximumWindowSize.X
#define cy getxy().dwMaximumWindowSize.Y
void try_()//插房间,为了方便,房间的x,y坐标为偶数,长宽为奇数
{
memset(rm,0,sizeof rm);t=0;
for(int i=1;i<=1000;i++)
{
int x=rand()%cx,y=rand()%(cy-3),lx=rand()%11+20,ly=rand()%6+7;
bool f=1;
if(x%2!=0) x++;
if(y%2!=0) y++;
if(lx%2==0) lx++;
if(ly%2==0) ly++;
if(x+lx>=cx||y+ly>=cy-3) f=0;
for(int j=1;j<=t&&f;j++)
{
room_ r=rm[j];
if((max(x,r.x)<=min(r.x+r.lx,x+lx))&&(max(-r.y-r.ly,-y-ly)<=min(-r.y,-y))) f=0;
}
if(f) rm[++t]=(room_){x,y,lx,ly};
}
}
void dfs(int x,int y)//小技巧6
{
bool f[5]={0};
gotoxy(y-1,x-1),printf("#");
Sleep(5);
while(1)
{
if(f[0]&&f[1]&&f[2]&&f[3]) return ;
int r=rand()%4;
int nx=fx[r][0],ny=fx[r][1],zx=zj[r][0],zy=zj[r][1];
if(x+nx<1||x+nx>n||y+ny<1||y+ny>m) {f[r]=1;continue;}//return ;
if(dt[x+zx][y+zy]!=WALL||v[x+zx][y+zy]||v[x+nx][y+ny]) {f[r]=1;continue;}//return ;
f[r]=1;
dt[x+zx][y+zy]=KONG;
v[x+zx][y+zy]=v[x+nx][y+ny]=1;
gotoxy(y+zy-1,x+zx-1),printf("#");Sleep(5);//输出
gotoxy(y+ny-1,x+nx-1),printf("#");Sleep(5);//输出
dfs(x+nx,y+ny);
}
return ;
}
void init()
{
memset(v,0,sizeof v);//一般的初始化
start.x=2,start.y=2;
memset(dt,WALL,sizeof dt);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i==1||i==n||j==1||j==m) dt[i][j]=WALL;
if(i%2==0&&j%2==0) dt[i][j]=KONG;
else dt[i][j]=WALL;
}
}
for(int i=1;i<=t;i++)//输出并标记房间
{
color(rand()%5);
for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++) dt[y][x]=KONG,v[y][x]=1,gotoxy(x-1,y-1),printf("#");
Sleep(100);
}
gotoxy(0,0);
for(int i=0;i<=n;i++)//建路
for(int j=1;j<=m;j++)
if(dt[i][j]==KONG&&dt[i-1][j]==WALL&&dt[i+1][j]==WALL&&dt[i][j-1]==WALL&&dt[i][j+1]==WALL) color(rand()%4+5),dfs(i,j);
}
void make_way()//造路
{
init();
gotoxy(0,0);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++) printf("%c",dt[i][j]==KONG?'#':' ');
puts("");
}
}
int main()
{
srand(time(NULL));
full();
hide();
gotoxy(0,cy-2);
printf("(回车启动,Esc退出)");
while(1)
{
if(kd(VK_ESCAPE)) break;
gotoxy(0,cy-2);
printf("(回车启动,Esc退出)");
if(kd(VK_RETURN)) cls,try_(),make_way();
Sleep(30);
}
return 0;
}
4.寻找一个连接
这个相对简单
对于每一个房间,遍历周围,找到能与之相连的路
然后玩运气,设定一个值,判断连接
当然,遍历到最后一条路的时候是100%能连上(aaaa语文白学了,感觉描述不出来啊qwq)
(算了,只可意会不可言传)
#define debug 0
#include<conio.h>
#include<windows.h>
#include<bits/stdc++.h>
using namespace std;
namespace init_ //小技巧15
{
#define kd(VK_NONAME) ((GetAsyncKeyState(VK_NONAME)&0x8000)?1:0)
#define sl(n) Sleep(n)
#define cls system("cls")
void gotoxy(int x,int y){COORD pos={(short)x,(short)y};HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOut,pos);return;}
void noedit(){HANDLE hStdin=GetStdHandle(STD_INPUT_HANDLE);DWORD mode;GetConsoleMode(hStdin,&mode);mode&=~ENABLE_QUICK_EDIT_MODE;mode&=~ENABLE_INSERT_MODE;mode&=~ENABLE_MOUSE_INPUT;SetConsoleMode(hStdin,mode);}
void hide(){CONSOLE_CURSOR_INFO cur={1,0};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
void show(){CONSOLE_CURSOR_INFO cur={1,1};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
}
using namespace init_;
namespace Color//加上颜色更加美观
{
void color(int a)
{
/*亮白*/if(a==0) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
/*蓝色*/if(a==1) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN|FOREGROUND_BLUE);
/*绿色*/if(a==2) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN);
/*紫色*/if(a==3) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_BLUE);
/*红色*/if(a==4) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED);
/*黄色*/if(a==5) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN);
/*深蓝*/if(a==6) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_BLUE);
/*金黄*/if(a==7) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_GREEN);
/*灰白*/if(a==8) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
}
void yanse(int ForgC,int BackC)
{
WORD wColor=((BackC&0x0F)<<4)+(ForgC&0x0F);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),wColor);
}
}
using namespace Color;
#define m 239
#define n 61
#define WALL -1
#define KONG 2
int t;
struct room_{int x,y,lx,ly;}rm[150];
struct play_er{int x,y;}start;
int dt[1010][1010];
int fx[5][5]={{2,0},{-2,0},{0,2},{0,-2}};
int zj[5][5]={{1,0},{-1,0},{0,1},{0,-1}};
bool v[1010][1010]={0};
void full()//全屏窗口,方便调试
{
system("mode con cols=50 lines=60");//随便设定一个值隐藏滚动条
HWND hwnd=GetForegroundWindow();
int cx=GetSystemMetrics(SM_CXSCREEN),cy=GetSystemMetrics(SM_CYSCREEN);//获得屏幕高度与宽度
LONG lw=GetWindowLong(hwnd,GWL_STYLE);
SetWindowLong(hwnd,GWL_STYLE,(lw|WS_POPUP|WS_MAXIMIZE)&~WS_CAPTION&~WS_THICKFRAME&~WS_BORDER);
SetWindowPos(hwnd,HWND_TOP,0,0,cx,cy,0);
}
CONSOLE_SCREEN_BUFFER_INFO getxy()//小技巧9
{
CONSOLE_SCREEN_BUFFER_INFO bInfo;
HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hConsole,&bInfo);
return bInfo;
}
#define cx getxy().dwMaximumWindowSize.X
#define cy getxy().dwMaximumWindowSize.Y
void try_()//插房间,为了方便,房间的x,y坐标为偶数,长宽为奇数
{
memset(rm,0,sizeof rm);t=0;
for(int i=1;i<=1000;i++)
{
int x=rand()%cx,y=rand()%(cy-3),lx=rand()%11+20,ly=rand()%6+7;
bool f=1;
if(x%2!=0) x++;
if(y%2!=0) y++;
if(lx%2==0) lx++;
if(ly%2==0) ly++;
if(x+lx>=cx||y+ly>=cy-3) f=0;
for(int j=1;j<=t&&f;j++)
{
room_ r=rm[j];
if((max(x,r.x)<=min(r.x+r.lx,x+lx))&&(max(-r.y-r.ly,-y-ly)<=min(-r.y,-y))) f=0;
}
if(f) rm[++t]=(room_){x,y,lx,ly};
}
}
void dfs(int x,int y)//小技巧6
{
bool f[5]={0};
gotoxy(y-1,x-1),printf("#");
Sleep(debug/2);
while(1)
{
if(f[0]&&f[1]&&f[2]&&f[3]) return ;
int r=rand()%4;
int nx=fx[r][0],ny=fx[r][1],zx=zj[r][0],zy=zj[r][1];
if(x+nx<1||x+nx>n||y+ny<1||y+ny>m) {f[r]=1;continue;}//return ;
if(dt[x+zx][y+zy]!=WALL||v[x+zx][y+zy]||v[x+nx][y+ny]) {f[r]=1;continue;}//return ;
f[r]=1;
dt[x+zx][y+zy]=KONG;
v[x+zx][y+zy]=v[x+nx][y+ny]=1;
gotoxy(y+zy-1,x+zx-1),printf("#");Sleep(debug/2);//输出
gotoxy(y+ny-1,x+nx-1),printf("#");Sleep(debug/2);//输出
dfs(x+nx,y+ny);
}
return ;
}
void init()
{
memset(v,0,sizeof v);//一般的初始化
start.x=2,start.y=2;
memset(dt,WALL,sizeof dt);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i==1||i==n||j==1||j==m) dt[i][j]=WALL;
if(i%2==0&&j%2==0) dt[i][j]=KONG;
else dt[i][j]=WALL;
}
}
for(int i=1;i<=t;i++)//输出并标记房间
{
color(rand()%5);
for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++) dt[y][x]=KONG,v[y][x]=1,gotoxy(x-1,y-1),printf("#");
Sleep(debug*10);
}
gotoxy(0,0);
for(int i=0;i<=n;i++)//建路
for(int j=1;j<=m;j++)
if(dt[i][j]==KONG&&dt[i-1][j]==WALL&&dt[i+1][j]==WALL&&dt[i][j-1]==WALL&&dt[i][j+1]==WALL) color(rand()%4+5),dfs(i,j);
}
void make_way()//造路
{
init();
gotoxy(0,0);
color(0);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++) printf("%c",dt[i][j]==KONG?'#':' ');
puts("");
}
}
void connect()//连接路与房间
{
color(4);
const int ch=3;//3%的概率选中
int sum=0;
for(int i=1;i<=t;i++)//枚举房间
{
//分别枚举上面的边,左边的边,下面的边和右边的边
//先找能与之相连的总数
for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++)
{
if(dt[y][rm[i].x-2]==KONG) sum++;
if(dt[y][rm[i].x+rm[i].lx+1]==KONG) sum++;
}
for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
{
if(dt[rm[i].y-2][x]==KONG) sum++;
if(dt[rm[i].y+rm[i].ly+1][x]==KONG) sum++;
}
//暴力枚举连边
for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++)
{
if(dt[y][rm[i].x-2]==KONG)
{
if(rand()%100<ch||sum==1) dt[y][rm[i].x-1]=KONG,gotoxy(rm[i].x-1-1,y-1),printf("#");
if(rand()%100<ch||sum==1) {sum--;continue;}
sum--;
}
if(dt[y][rm[i].x+rm[i].lx+1]==KONG)
{
if(rand()%100<ch||sum==1) dt[y][rm[i].x+rm[i].lx]=KONG,gotoxy(rm[i].x+rm[i].lx-1,y-1),printf("#");
if(rand()%100<ch||sum==1) {sum--;continue;}
sum--;
}
}
for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
{
if(dt[rm[i].y-2][x]==KONG)
{
if(rand()%100<ch||sum==1) dt[rm[i].y-1][x]=KONG,gotoxy(x-1,rm[i].y-1-1),printf("#");
if(rand()%100<ch||sum==1) {sum--;continue;}
sum--;
}
if(dt[rm[i].y+rm[i].ly+1][x]==KONG)
{
if(rand()%100<ch||sum==1) dt[rm[i].y+rm[i].ly][x]=KONG,gotoxy(x-1,rm[i].y+rm[i].ly-1),printf("#");
if(rand()%100<ch||sum==1) {sum--;continue;}
sum--;
}
}
}
color(0);
return;
}
int main()
{
srand(time(NULL));
full();
hide();
gotoxy(0,cy-2);
printf("(回车启动,Esc退出)");
while(1)
{
if(kd(VK_ESCAPE)) break;
gotoxy(0,cy-2);
printf("(回车启动,Esc退出)");
if(kd(VK_RETURN)) cls,try_(),make_way(),connect();
Sleep(30);
}
return 0;
}
然后事情就简单了,接下来只需要删除多余的边就行了
5.反雕刻
就是把前面2中的删路代码放到里面去
6.最后我们得到什么
把所有代码连到一起,就拥有了一个能大量生成的地牢捏
这边给一个观赏类的代码
//建议在用这个生成地图的时候加一个判断是否全联通的搜索,zzb实验后发现有概率房间与道路不连通(zzb已经+了)
#define debug 4//停顿时间,最好0~10
#include<conio.h>
#include<windows.h>
#include<bits/stdc++.h>
using namespace std;
namespace init_ //小技巧15
{
#define kd(VK_NONAME) ((GetAsyncKeyState(VK_NONAME)&0x8000)?1:0)
#define sl(n) Sleep(n)
#define cls system("cls")
void gotoxy(int x,int y){COORD pos={(short)x,(short)y};HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOut,pos);return;}
void noedit(){HANDLE hStdin=GetStdHandle(STD_INPUT_HANDLE);DWORD mode;GetConsoleMode(hStdin,&mode);mode&=~ENABLE_QUICK_EDIT_MODE;mode&=~ENABLE_INSERT_MODE;mode&=~ENABLE_MOUSE_INPUT;SetConsoleMode(hStdin,mode);}
void hide(){CONSOLE_CURSOR_INFO cur={1,0};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
void show(){CONSOLE_CURSOR_INFO cur={1,1};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
}
using namespace init_;
namespace Color//加上颜色更加美观
{
void color(int ForgC)
{
int BackC=0;
WORD wColor=((BackC&0x0F)<<4)+(ForgC&0x0F);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),wColor);
}
}
using namespace Color;
#define m 239
#define n 61
#define WALL -1
#define KONG 2
bool D=0;
int t;
struct room_{int x,y,lx,ly;}rm[150];
struct play_er{int x,y;}start;
int dt[1010][1010];
int fx[5][5]={{2,0},{-2,0},{0,2},{0,-2}};
int zj[5][5]={{1,0},{-1,0},{0,1},{0,-1}};
bool v[1010][1010]={0};
play_er e[114514];
void print()
{
color(15);
gotoxy(0,0);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++) printf("%c",dt[i][j]==KONG?'#':' ');
puts("");
}
}
void full()//全屏窗口,方便调试
{
system("mode con cols=50 lines=60");//随便设定一个值隐藏滚动条
HWND hwnd=GetForegroundWindow();
int cx=GetSystemMetrics(SM_CXSCREEN),cy=GetSystemMetrics(SM_CYSCREEN);//获得屏幕高度与宽度
LONG lw=GetWindowLong(hwnd,GWL_STYLE);
SetWindowLong(hwnd,GWL_STYLE,(lw|WS_POPUP|WS_MAXIMIZE)&~WS_CAPTION&~WS_THICKFRAME&~WS_BORDER);
SetWindowPos(hwnd,HWND_TOP,0,0,cx,cy,0);
}
CONSOLE_SCREEN_BUFFER_INFO getxy()//小技巧9
{
CONSOLE_SCREEN_BUFFER_INFO bInfo;
HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hConsole,&bInfo);
return bInfo;
}
#define cx getxy().dwMaximumWindowSize.X
#define cy getxy().dwMaximumWindowSize.Y
void try_()//插房间,为了方便,房间的x,y坐标为偶数,长宽为奇数
{
memset(rm,0,sizeof rm);t=0;
for(int i=1;i<=1000;i++)
{
int x=rand()%cx,y=rand()%(cy-3),lx=rand()%11+20,ly=rand()%6+7;
bool f=1;
if(x%2!=0) x++;
if(y%2!=0) y++;
if(lx%2==0) lx++;
if(ly%2==0) ly++;
if(x+lx>=cx||y+ly>=cy-3) f=0;
for(int j=1;j<=t&&f;j++)
{
room_ r=rm[j];
if((max(x,r.x)<=min(r.x+r.lx,x+lx))&&(max(-r.y-r.ly,-y-ly)<=min(-r.y,-y))) f=0;
}
if(f) rm[++t]=(room_){x,y,lx,ly};
}
}
void dfs(int x,int y)//小技巧6
{
bool f[5]={0};
gotoxy(y-1,x-1),printf("#");
Sleep(debug/2);
while(1)
{
if(f[0]&&f[1]&&f[2]&&f[3]) return ;
int r=rand()%4;
int nx=fx[r][0],ny=fx[r][1],zx=zj[r][0],zy=zj[r][1];
if(x+nx<1||x+nx>n||y+ny<1||y+ny>m) {f[r]=1;continue;}//return ;
if(dt[x+zx][y+zy]!=WALL||v[x+zx][y+zy]||v[x+nx][y+ny]) {f[r]=1;continue;}//return ;
f[r]=1;
dt[x+zx][y+zy]=KONG;
v[x+zx][y+zy]=v[x+nx][y+ny]=1;
gotoxy(y+zy-1,x+zx-1),printf("#");Sleep(debug/2);//输出
gotoxy(y+ny-1,x+nx-1),printf("#");Sleep(debug/2);//输出
dfs(x+nx,y+ny);
}
return ;
}
void init()
{
memset(v,0,sizeof v);//一般的初始化
start.x=2,start.y=2;
memset(dt,WALL,sizeof dt);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i==1||i==n||j==1||j==m) dt[i][j]=WALL;
if(i%2==0&&j%2==0) dt[i][j]=KONG;
else dt[i][j]=WALL;
}
}
for(int i=1;i<=t;i++)//输出并标记房间
{
color(rand()%14+1);
for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++) dt[y][x]=KONG,v[y][x]=1,gotoxy(x-1,y-1),printf("#");
Sleep(debug*10);
}
gotoxy(0,0);
for(int i=0;i<=n;i++)//建路
for(int j=1;j<=m;j++)
if(dt[i][j]==KONG&&dt[i-1][j]==WALL&&dt[i+1][j]==WALL&&dt[i][j-1]==WALL&&dt[i][j+1]==WALL) color(rand()%14+1),dfs(i,j);
}
void make_way()//造路
{
init();
gotoxy(0,0);
color(0);
// for(int i=1;i<=n;i++)
// {
// for(int j=1;j<=m;j++) printf("%c",dt[i][j]==KONG?'#':' ');
// puts("");
// }
}
void connect()//连接路与房间
{
color(4);
const int ch=3;//3%的概率选中
int sum=0;
for(int i=1;i<=t;i++)//枚举房间
{
//分别枚举上面的边,左边的边,下面的边和右边的边
//先找能与之相连的总数
for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++)
{
if(dt[y][rm[i].x-2]==KONG) sum++;
if(dt[y][rm[i].x+rm[i].lx+1]==KONG) sum++;
}
for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
{
if(dt[rm[i].y-2][x]==KONG) sum++;
if(dt[rm[i].y+rm[i].ly+1][x]==KONG) sum++;
}
//暴力枚举连边
bool b=0;
while(!b)
{
for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++)
{
if(dt[y][rm[i].x-2]==KONG)
{
if(rand()%100<ch||sum==1) dt[y][rm[i].x-1]=KONG,gotoxy(rm[i].x-1-1,y-1),printf("#"),b=1;
if(rand()%100<ch||sum==1) {sum--;continue;}
sum--;
}
if(dt[y][rm[i].x+rm[i].lx+1]==KONG)
{
if(rand()%100<ch||sum==1) dt[y][rm[i].x+rm[i].lx]=KONG,gotoxy(rm[i].x+rm[i].lx-1,y-1),printf("#"),b=1;
if(rand()%100<ch||sum==1) {sum--;continue;}
sum--;
}
}
for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
{
if(dt[rm[i].y-2][x]==KONG)
{
if(rand()%100<ch||sum==1) dt[rm[i].y-1][x]=KONG,gotoxy(x-1,rm[i].y-1-1),printf("#"),b=1;
if(rand()%100<ch||sum==1) {sum--;continue;}
sum--;
}
if(dt[rm[i].y+rm[i].ly+1][x]==KONG)
{
if(rand()%100<ch||sum==1) dt[rm[i].y+rm[i].ly][x]=KONG,gotoxy(x-1,rm[i].y+rm[i].ly-1),printf("#"),b=1;
if(rand()%100<ch||sum==1) {sum--;continue;}
sum--;
}
}
}
}
gotoxy(0,0);
color(15);
return;
}
void get_end()//取出死路位置,但注意之前的代码有bug,现在改了
{
int sx=0,sy=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(dt[i][j]==KONG) sx=i,sy=j;
queue<play_er> q;
while(!q.empty()) q.pop();
bool vis[1010][1010];
memset(vis,0,sizeof vis);
q.push((play_er){sx,sy});
vis[sx][sy]=1;
while(!q.empty())
{
play_er p=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int X=p.x+zj[i][0],Y=p.y+zj[i][1];
if(!vis[X][Y]&&dt[X][Y]==KONG)
{
q.push((play_er){X,Y});
vis[X][Y]=1;
}
}
//现在删路是判断周围是否只有一个通路
int f=4;
for(int i=0;i<4;i++)
{
int X=p.x+zj[i][0],Y=p.y+zj[i][1];
if(dt[X][Y]==KONG) f--;
}
if(f==3) e[++t]=p;
}
}
void try__()//反复删除
{
get_end();
while(1)//删掉awa
{
if(t==0) get_end();
if(t==0) break;
dt[e[t].x][e[t].y]=WALL;
gotoxy(e[t].y-1,e[t].x-1);//没错,我当时把这一行放在了t--下面调了1个小时
t--;
printf(" ");
Sleep(1);
}
}
void tian()//填充颜色&&判断是否合法
{
int sx=0,sy=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(dt[i][j]==KONG) sx=i,sy=j;
queue<play_er> q;
while(!q.empty()) q.pop();
bool vis[1010][1010];
memset(vis,0,sizeof vis);
vis[sx][sy]=1;
q.push((play_er){sx,sy});
while(!q.empty())
{
play_er p=q.front();
gotoxy(p.y-1,p.x-1);
color(15);
printf("#");Sleep(debug);
q.pop();
for(int i=0;i<4;i++)
{
int X=p.x+zj[i][0],Y=p.y+zj[i][1];
if(!vis[X][Y]&&dt[X][Y]==KONG)
{
q.push((play_er){X,Y});
vis[X][Y]=1;
}
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(dt[i][j]==KONG&&!vis[i][j])
{
MessageBox(NULL,"你的阳寿不够,即将重新设定地图","wrong",MB_ICONEXCLAMATION|MB_OK);
D=1;
return;
}
}
print();
}
void del()
{
tian();//填充+广搜判断是否全联通
if(D) return;
try__();
print();
}
int main()
{
noedit();
srand(time(NULL));
full();
hide();
gotoxy(0,cy-2);
printf("(回车启动,Esc退出)");
while(1)
{
if(kd(VK_ESCAPE)) break;
gotoxy(0,cy-2);
printf("(回车启动,Esc退出)");
if(kd(VK_RETURN)) cls,try_(),make_way(),connect(),del();
if(D)
{
D=0;
cls;
try_(),make_way(),connect(),del();
}
Sleep(30);
}
return 0;
}
如果你想用z_z_b_的代码生成地图,请用下面这一份
//地图生成,是以外放txt的形式,但可能出现格式错误,用devc++打开即可解决
#include<conio.h>
#include<windows.h>
#include<bits/stdc++.h>
using namespace std;
namespace init_ //小技巧15
{
#define kd(VK_NONAME) ((GetAsyncKeyState(VK_NONAME)&0x8000)?1:0)
#define sl(n) Sleep(n)
#define cls system("cls")
void gotoxy(int x,int y){COORD pos={(short)x,(short)y};HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOut,pos);return;}
void noedit(){HANDLE hStdin=GetStdHandle(STD_INPUT_HANDLE);DWORD mode;GetConsoleMode(hStdin,&mode);mode&=~ENABLE_QUICK_EDIT_MODE;mode&=~ENABLE_INSERT_MODE;mode&=~ENABLE_MOUSE_INPUT;SetConsoleMode(hStdin,mode);}
void hide(){CONSOLE_CURSOR_INFO cur={1,0};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
void show(){CONSOLE_CURSOR_INFO cur={1,1};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);}
}
using namespace init_;
namespace Color//加上颜色更加美观
{
void color(int ForgC)
{
int BackC=0;
WORD wColor=((BackC&0x0F)<<4)+(ForgC&0x0F);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),wColor);
}
}
using namespace Color;
#define cx 240
#define cy 65
#define m 239
#define n 61
#define WALL -1
#define KONG 2
bool D=0;
struct room_{int x,y,lx,ly;}rm[150];
struct play_er{int x,y;}start,e[1001000];
int t,dt[1010][1010],fx[5][5]={{2,0},{-2,0},{0,2},{0,-2}},zj[5][5]={{1,0},{-1,0},{0,1},{0,-1}};
bool v[1010][1010]={0};
void try_();//插入房间
void dfs(int,int);//造迷宫
void make_way();//地图初始化
void connect();//连接房间与路
void get_end();//取出死路
void try__();//删路
void tian();//判断合法
void del();//删路总调控
void optimize();//地图优化
void make_dt();//造地图
int main();//main函数
void try_()//插房间,为了方便,房间的x,y坐标为偶数,长宽为奇数
{
memset(rm,0,sizeof rm);t=0;
for(int i=1;i<=1000;i++)
{
int x=rand()%cx,y=rand()%(cy-3),lx=rand()%11+20,ly=rand()%6+7;
bool f=1;
if(x%2!=0) x++;
if(y%2!=0) y++;
if(lx%2==0) lx++;
if(ly%2==0) ly++;
if(x+lx>=cx||y+ly>=cy-3||x==0||y==0) f=0;
for(int j=1;j<=t&&f;j++)
{
room_ r=rm[j];
if((max(x,r.x)<=min(r.x+r.lx,x+lx))&&(max(-r.y-r.ly,-y-ly)<=min(-r.y,-y))) f=0;
}
if(f) rm[++t]=(room_){x,y,lx,ly};
}
}
void dfs(int x,int y)//小技巧6
{
bool f[5]={0};
while(1)
{
if(f[0]&&f[1]&&f[2]&&f[3]) return ;
int r=rand()%4;
int nx=fx[r][0],ny=fx[r][1],zx=zj[r][0],zy=zj[r][1];
if(x+nx<1||x+nx>n||y+ny<1||y+ny>m) {f[r]=1;continue;}
if(dt[x+zx][y+zy]!=WALL||v[x+zx][y+zy]||v[x+nx][y+ny]) {f[r]=1;continue;}
f[r]=1;
dt[x+zx][y+zy]=KONG;
v[x+zx][y+zy]=v[x+nx][y+ny]=1;
dfs(x+nx,y+ny);
}
return ;
}
void make_way()
{
memset(v,0,sizeof v);//一般的初始化
memset(dt,WALL,sizeof dt);
start.x=2,start.y=2;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(i==1||i==n||j==1||j==m) dt[i][j]=WALL;
if(i%2==0&&j%2==0) dt[i][j]=KONG;
else dt[i][j]=WALL;
}
for(int i=1;i<=t;i++)for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)//标记房间
for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++) dt[y][x]=KONG,v[y][x]=1;
for(int i=0;i<=n;i++)for(int j=1;j<=m;j++)//建路
if(dt[i][j]==KONG&&dt[i-1][j]==WALL&&dt[i+1][j]==WALL&&dt[i][j-1]==WALL&&dt[i][j+1]==WALL) dfs(i,j);
}
void connect()//连接路与房间
{
const int ch=3;//3%的概率选中
int sum=0;
for(int i=1;i<=t;i++)//枚举房间,分别枚举上面的边,左边的边,下面的边和右边的边
{
for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++)//先找能与之相连的总数
{
if(dt[y][rm[i].x-2]==KONG) sum++;
if(dt[y][rm[i].x+rm[i].lx+1]==KONG) sum++;
}
for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
{
if(dt[rm[i].y-2][x]==KONG) sum++;
if(dt[rm[i].y+rm[i].ly+1][x]==KONG) sum++;
}
bool b=0;//暴力枚举连边
while(!b)
{
for(int y=rm[i].y;y<=rm[i].y+rm[i].ly-1;y++)
{
if(dt[y][rm[i].x-2]==KONG){if(rand()%100<ch||sum==1){dt[y][rm[i].x-1]=KONG,b=1,sum--;continue;}sum--;}
if(dt[y][rm[i].x+rm[i].lx+1]==KONG){if(rand()%100<ch||sum==1){dt[y][rm[i].x+rm[i].lx]=KONG,b=1,sum--;continue;}sum--;}
}
for(int x=rm[i].x;x<=rm[i].x+rm[i].lx-1;x++)
{
if(dt[rm[i].y-2][x]==KONG){if(rand()%100<ch||sum==1){dt[rm[i].y-1][x]=KONG,b=1,sum--;continue;}sum--;}
if(dt[rm[i].y+rm[i].ly+1][x]==KONG){if(rand()%100<ch||sum==1){dt[rm[i].y+rm[i].ly][x]=KONG,b=1,sum--;continue;}sum--;}
}
}
}
return;
}
void get_end()//取出死路位置,但注意之前的代码有bug,现在改了
{
int sx=0,sy=0;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(dt[i][j]==KONG)sx=i,sy=j;
queue<play_er> q;
while(!q.empty()) q.pop();
bool vis[1010][1010];
memset(vis,0,sizeof vis);
q.push((play_er){sx,sy});
vis[sx][sy]=1;
while(!q.empty())
{
play_er p=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int X=p.x+zj[i][0],Y=p.y+zj[i][1];
if(!vis[X][Y]&&dt[X][Y]==KONG) q.push((play_er){X,Y}),vis[X][Y]=1;
}
int f=4;//删路
for(int i=0;i<4;i++)
{
int X=p.x+zj[i][0],Y=p.y+zj[i][1];
if(dt[X][Y]==KONG) f--;
}
if(f==3) e[++t]=p;
}
}
void try__()//反复删除
{
get_end();
while(1)//删掉awa
{
if(t==0) get_end();
if(t==0) break;
dt[e[t].x][e[t].y]=WALL;
t--;
}
}
void tian()//填充颜色&&判断是否合法
{
int sx=0,sy=0;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(dt[i][j]==KONG)sx=i,sy=j;
queue<play_er> q;
while(!q.empty()) q.pop();
bool vis[1010][1010];
memset(vis,0,sizeof vis);
vis[sx][sy]=1;
q.push((play_er){sx,sy});
while(!q.empty())
{
play_er p=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int X=p.x+zj[i][0],Y=p.y+zj[i][1];
if(!vis[X][Y]&&dt[X][Y]==KONG)q.push((play_er){X,Y}),vis[X][Y]=1;
}
}
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(dt[i][j]==KONG&&!vis[i][j]){D=1;return;}
}
void del()
{
tian();//填充+广搜判断是否全联通
if(D) return;
try__();
}
void optimize()
{
int sx=0,sy=0;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(dt[i][j]==KONG)sx=i,sy=j;
queue<play_er> q;
while(!q.empty()) q.pop();
bool vis[1010][1010],v2[1010][1010];
memset(vis,0,sizeof vis);
memset(v2,0,sizeof v2);
vis[sx][sy]=1;
q.push((play_er){sx,sy});
while(!q.empty())
{
play_er p=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int X=p.x+zj[i][0],Y=p.y+zj[i][1];
if(!vis[X][Y]&&dt[X][Y]==KONG)q.push((play_er){X,Y}),vis[X][Y]=1;
}
}
int fx[]={0,-1,-1,-1,0,0,1,1,1},fy[]={0,-1,0,1,-1,1,-1,0,1};
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(vis[i][j])for(int k=0;k<=8;k++)v2[i+fx[k]][j+fy[k]]=1;
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(!v2[i][j])dt[i][j]=KONG;
}
void make_dt()
{
zzb:
try_(),make_way(),connect(),del();
if(D)
{
D=0;
goto zzb;
}
optimize();
freopen("mp.txt","w",stdout);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++) printf("%c",dt[i][j]==WALL?'#':' ');
puts("");
}
}
int main()
{
srand(time(NULL));
hide();
noedit();
make_dt();
return 0;
}
不过,在我的代码中,你可以把它当头文件生成mp后在读入
也可以直接用数组dt当地图用
注意一点:
dt[i][j]==KONG 代表是可经过的路
dt[i][j]==WALL 代表的是不可经过的墙(直接用KONG和WALL,毕竟KONG是2,WALL是-1···)
警示:
1.注意c++运行框建系后是
0 1 2 3 4 5 5 6 7 8 9
---------------------->x
|1
|2
|3
|4
|5
|6
|7
|8
V
y
(当时卡了我好久啊awa)
2.用color的时候小心,一定要看清颜色是什么
我用color0(0当时是黑色),结果地图隐藏了,调了很久
3.后文
建议这种代码还是要自己写,写这些对你来说可以练习模拟,一些算法,也有心态。写不出来那就多练awa鬼知道我想放弃想了几次
像这些最好看一下注释,多理解一下(能想出更优的办法更好)
(看在zzb这么努力的份上,给个关注吧awa)
(提一嘴,有没有第五的大佬带一下新手awa)
参考文章:房间和迷宫:一个地牢生成算法
上一篇:c++游戏小技巧15:前14篇总结
下一篇:未完待续