博客链接
自动推箱子部分使用双重bfs实现,注释有点多,代码有点乱见谅
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define N 101
using namespace std;
char map[N][N];
char YON;
int show, judge, boom, ph, addb, endgame;
int stax, stay, boxx, boxy, endx, endy, addbx, addby;
int vis[N][N][4], flag[N][N]; // vis用来保存箱子和人的状态
int i, j, step, n, m, showtime, cnt;
int dir[4][2]={-1,0,1,0,0,-1,0,1};
char P[4]= {'W','S','A','D'}; // w,a,s,d分别对应键盘是的按键
char M[4]= {'w','s','a','d'};
string temp, res;
struct Node
{
int x,y;
int px,py;
string ans;
};
int check(int x,int y) // 边界检查
{
if(x < 1 || x > n || y < 1 || y > n || map[x][y] == 5)
return 0;
return 1;
}
queueq;
queueque;
/*
用嵌套BFS,外层BFS是找从箱子到终点找一条箱子移动的路径,用内层BFS来判断人能否从上一个点走到这一个点 .
箱子是可以经过一个点多次的,但是同一个点移动往同一个方向只能一次
*/
int bfs_person(Node a,Node c) // 搜索人的位置
{
memset(flag,0,sizeof(flag));
Node next,b;
b.x=a.px, b.y=a.py;
b.ans="";
while(!q.empty()) // 清空队列
q.pop();
q.push(b);
flag[b.x][b.y]=1;
while(!q.empty())
{
Node now=q.front();
q.pop();
if(now.x==a.x&&now.y==a.y)
{
temp=now.ans;
return 1;
}
for(int i=0; i<4; i++) // 搜索玩家的4个方向
{
next=now;
next.x+=dir[i][0];
next.y+=dir[i][1];
if(!check(next.x,next.y)||(next.x==c.x&&next.y==c.y)) continue;
if(flag[next.x][next.y]) continue;
flag[next.x][next.y]=1;
next.ans=now.ans+M[i]; // 如果是可行解则把M中的方向键加入字符串中
q.push(next);
}
}
return 0;
}
string bfs_box() // 搜索箱子的位置
{
Node next,pre;
Node st;
memset(vis,0,sizeof(vis));
st.ans = "";
st.px = stax; // 玩家位置
st.py = stay;
st.x = boxx; // 箱子位置
st.y = boxy;
while(!que.empty()) // 清空队列
que.pop();
que.push(st);
while(!que.empty())
{
Node now = que.front();
que.pop();
if(map[now.x][now.y] == 4) // 当箱子到达终点时
return now.ans;
for(i=0; i < 4; i++) // 搜索箱子的4个方向
{
next = now;
next.x += dir[i][0];
next.y += dir[i][1];
if(!check(next.x, next.y) || vis[next.x][next.y][i])
continue;
pre=now;
if(i == 0)
pre.x = pre.x + 1;
else if(i == 1)
pre.x = pre.x - 1;
else if(i == 2)
pre.y = pre.y + 1;
else if(i == 3)
pre.y = pre.y - 1;
if(!check(pre.px, pre.py) || !bfs_person(pre, now))
continue;
vis[next.x][next.y][i] = 1;
next.ans = now.ans + temp;
next.ans = next.ans + P[i]; // 如果是可行解则把P中的方向键加入字符串中
next.px = now.x;
next.py = now.y;
que.push(next);
}
}
return "-1"; // 无解返回-1
}
void gotoxy(int x,int y) // 将光标移动到指定坐标
{
COORD pos = {x,y};
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOut,pos);
}
void color(int x) // 给文字上色
{
if(x >= 0 && x <= 15)
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),x);
else
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),7);
}
void createmap() // 随机生成地图
{
int wall[N][N];
srand(time(NULL));
for(i=0;i> n;
if(n > 100)
cout << "输入错误请重新输入:";
}while(n > 100);
cout << "请输入一个数来决定障碍物密度(输入的数字越小,障碍物越多,n>=4):";
do
{
cin >> m;
if(m < 4)
cout << "输入错误请重新输入:";
}while(m < 4);
cout << "请输入一个数来决定地图中炸弹补给点的个数(n<=5):";
do
{
cin >> addb;
if(addb > 5)
cout << "输入错误请重新输入:";
}while(addb > 5);
cout << "地图太大,地图生成的速度可能会很慢";
}
void tips() // 提示栏
{
gotoxy(n+2,0);
color(3);
cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-";
gotoxy(n+2,1);
color(2);
printf("'%c'为小人(玩家可以通过键盘的w,s,a,d控制)",1);
gotoxy(n+2,2);
color(3);
cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-";
gotoxy(n+2,3);
color(2);
printf("'%c'为箱子(玩家可以推动,但不可以拉)",3);
gotoxy(n+2,4);
color(3);
cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-";
gotoxy(n+2,5);
color(2);
printf("'%c'为墙体(玩家和箱子都不可以穿过)",5);
gotoxy(n+2,6);
color(3);
cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-";
gotoxy(n+2,7);
color(2);
printf("'%c'为炸弹补给点,到达该地方炸弹数量+2",6);
gotoxy(n+2,8);
color(3);
cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-";
gotoxy(n+2,9);
color(2);
printf("'.'为自动寻路时玩家和箱子的路径");
gotoxy(n+2,10);
color(3);
cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-";
gotoxy(n+2,11);
color(2);
printf("' '为玩家和箱子都可以通过的地方");
gotoxy(n+2,12);
color(3);
cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-";
gotoxy(n+2,13);
color(2);
cout << "按下h自动寻路";
gotoxy(n+2,14);
color(3);
cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-";
gotoxy(n+2,15);
color(2);
cout << "按下p判断当前是否有解";
gotoxy(n+2,16);
color(3);
cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-";
gotoxy(n+2,17);
color(2);
cout << "按下b破坏周围墙体";
gotoxy(n+2,18);
color(3);
cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-";
gotoxy(n+2,19);
color(2);
cout << "按下q提前结束游戏";
gotoxy(n+2,20);
color(3);
cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-";
}
void ismap() // 地图一定有解
{
do // 用do--while可以先随机生成一次地图,如果不符合则继续生成
{
createmap();
createbox();
addboom();
cnt++;
res = bfs_box();
if(res == "-1")
{
for(i=0;i 0)
{
map[stax-1][stay] = 0;
map[stax+1][stay] = 0;
map[stax][stay-1] = 0;
map[stax][stay+1] = 0;
map[stax-1][stay-1] = 0;
map[stax+1][stay-1] = 0;
map[stax-1][stay+1] = 0;
map[stax+1][stay+1] = 0;
boom--;
}
else
{
gotoxy(n+2,21);
color(4);
cout << "你的炸弹用完了,输入任意键继续游戏......";
getch();
}
}
int main()
{
while(1)
{
system("cls"); // 如果开始游戏则清屏
// 各个变量初始化
endgame = 0;
ph = 0;
judge = 0;
show = 0;
cnt = 0;
stax = 1;
stay = 1;
showtime = 100;
res = "";
memset(map,0,sizeof(map));
menu();
ismap();
while(1) // 游戏主题部分
{
system("cls");
color(8);
drawmap(); // 打印地图
tips();
gotoxy(stay,stax); // 打印玩家符号
color(5);
printf("%c",1);
gotoxy(boxy,boxx); // 打印箱子符号
color(4);
printf("%c",3);
// 以下是打印一些游戏提示
gotoxy(0,n+1);
color(7);
cout << "当前移动步数:" << step;
gotoxy(0,n+2);
color(7);
cout << "当前玩家坐标:" << '(' << stax << ',' << stay << ')';
gotoxy(0,n+3);
color(7);
cout << "生成地图数:" << cnt << endl;
gotoxy(0,n+4);
color(7);
cout << "炸弹剩余数:";
for(i=0;i> showtime;
automove(res);
// 初始化
showtime = 100;
show = 0;
}
gotoxy(0,n+8);
// 判断游戏胜利或者失败
if(res == "-1")
{
cout << "你失败了,是否开始新的游戏Y/N?";
cin >> YON ;
YON = tolower(YON);
break;
}
if(boxx == endx && boxy == endy)
{
cout << "你赢了,是否开始新的游戏Y/N?";
cin >> YON;
YON = tolower(YON);
break;
}
if(endgame == 1)
{
cout << "你提前结束了游戏,是否开始新的游戏Y/N?";
cin >> YON;
YON = tolower(YON);
break;
}
}
if(YON == 'n') // 判断是否需要开始新的游戏
break;
if(YON == 'y')
continue;
}
}