# 推箱子c++实现代码

<p>c++  实验课的作业，话说这次算是我花的时间最长的实验课作业了，不过的确感觉自己对搜索的理解和编码能力提高了，作为一名初学者，我要学的东西还很多。。。</p><p>这次的实验是推箱子，自己YY了一个自动生成推箱子地图的算法，两重BFS，这大概也是我第一次把ACM的算法放到了实际应用中吧。下面上代码。。。。</p>

class Box
{
public :
Box();
void RandomMaze(int n);
public :
int x,y;
};

class game
{
public:
int WaitKey( double sec );
void SetPos( int x, int y );
};

typedef int Status;
typedef int ElemType;
//using namespace std;

class map
{
public:
Status RandomMaze(int n,int m);
Status PrintMaze(int n) ;
public:
int mazemap[20][20];
};

//using namespace std;

class Vehicle
{
public:
Vehicle();
void show();
public:
int x,y;
};

#include "Windows.h"
#include "game.h"
#include "ctime"
#include "conio.h"
using namespace std;

int game::WaitKey( double sec )
{
clock_t tickStart = clock();
clock_t tickEnd = tickStart + (clock_t)(sec * CLOCKS_PER_SEC);
while(!kbhit())
{
// time out
if( clock() >= tickEnd)
return 0;
Sleep(sec / 100.0); // wait
}
return getch();
}

void game::SetPos( int x, int y )
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
COORD cursorPos = {x, y};
SetConsoleCursorPosition(hConsole, cursorPos);
}

#include "box.h"
#include "iostream"
#include "map.h"
#include "vehicle.h"
#include "ctime"
#include "Windows.h"
typedef int Status;
typedef int ElemType;

#define OK        1
#define ERROR     0
#define TRUE      1
#define FALSE     0
#define OVERFLOW -2

Status map::RandomMaze(int n,int m)
{
int i,j,k;
srand(time(NULL));
for(i=0;i<n;i++)
mazemap[0][i]=mazemap[n-1][i]=1;
for(j=0;j<n;j++)
mazemap[j][0]=mazemap[j][n-1]=1;
for(i=1;i<n-1;i++)
for(j=1;j<n-1;j++)
{
k=rand()%6;    //随机生成整张的地图
if(k==0)
mazemap[i][j]=1;
else
mazemap[i][j]=0;
}
/*
for(i=1;i<=m;i++)
{
int rand_x=rand()%19;
int rand_y=rand()%19;
if(rand_x>=1&&rand_y>=1)
{
mazemap[rand_x][rand_y]=-1;    //随机生成箱子的位置
}
else
i--;
}*/
/*
for(i=1;i<=m;i++)
{
int rand_x=rand()%19;
int rand_y=rand()%19;
if(rand_x>=1&&rand_y>=1)
{
mazemap[rand_x][rand_y]=-3;   //随机生成箱子的目标位置
}
else
i--;
}*/
mazemap[1][0]=mazemap[1][1]=0;//标记入口出口
return OK;
}

Status map::PrintMaze(int n)                //打印最后的足迹
{
//printf("路径如下：\n");
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(mazemap[i][j]==0)
printf("  ");       //代表可以走的位置
if(mazemap[i][j]==1)
printf("■");    // 代表墙壁
if(mazemap[i][j]==-1||mazemap[i][j]==-4)
printf("□");    // 代表箱子
if(mazemap[i][j]==-2)
printf("○");    //代表推箱子的人
if(mazemap[i][j]==-3)
printf("◎");     //代表箱子的目标位置
if(mazemap[i][j]==5)
printf("☆");
}
printf("\n");
}
printf("\n");
return OK;
}



#include "box.h"
#include "map.h"
#include "vehicle.h"
#include "cstring"
#include "iostream"
using namespace std;

Vehicle :: Vehicle ():x(0),y(0){};
void  Vehicle :: LoadMap(const char *a)
{
if(strcmp(a,"left")==0)
{
y--;
}
if(strcmp(a,"right")==0)
{
y++;
}
if(strcmp(a,"up")==0)
{
x--;
}
if(strcmp(a,"down")==0)
{
x++;
}
};
void Vehicle::show()
{
cout<<"<"<<x<<","<<y<<">"<<endl;
};

#pragma once
#include "cstdio"
#include "cstring"
#include "algorithm"
#include "conio.h"
#include "ctime"
#include "windows.h"
#include "iostream"
#include "stdlib.h"
#include "queue"
#include "vector"
#include "map.h"
#include "vehicle.h"
#include "box.h"
#include "game.h"
using namespace std;

#define INF 1<<27
#define OK        1
#define ERROR     0
#define TRUE      1
#define FALSE     0
#define OVERFLOW -2
#define INIT_STACK_SIZE 100
#define INCREASESIZE    10

const int MAX_X = INF;
const int MAX_Y = INF;
const int MAX_N = 1000;

typedef int Status;
typedef int ElemType;
typedef pair <int,int>P;

//bool used[MAX_X][MAX_Y];

map A;
Vehicle V;
Box B[];
game C;

int dir[4][3]={{0,1},{0,-1},{1,0},{-1,0}};
bool  used[1000][1000];
/*
bool dfs_judge(int final_x,int final_y)    //上次用的dfs时间复杂度太高了。。。。所以换成了bfs
{
if(final_x==1&&final_y==0)
return true;
for(int i=0;i<=3;i++)
{
int xx=final_x+dir[i][0],yy=final_y+dir[i][1];
if(A.mazemap[xx][yy]!=1&&!used[xx][yy])
{
used[xx][yy]=1;
if(dfs_judge(xx,yy))
return true;
used[xx][yy]=0;
}
}
return false;
}*/

bool bfs_judge_bypeople(int final_x,int final_y)      //第一重bfs
{
queue<P>que;
memset (used,0,sizeof(used));
used[final_x][final_y]=true;
que.push(P(final_x,final_y));
//int cnt=0;
while(!que.empty())
{
P p=que.front();
que.pop();
if(p.first==1&&p.second==0)
return true;
for(int i=0;i<=3;i++)
{
int nx=p.first+dir[i][0],ny=p.second+dir[i][1];
if(A.mazemap[nx][ny]!=1&&!used[nx][ny])
{
que.push(P(nx,ny));
used[nx][ny]=true;
}
}
}
return false;
}

struct node
{
int first,second,direction;      //用于储存坐标值和上一次的方向
node(){}
node(int a,int b,int c) { first=a;second=b;direction=c;}
};

bool bfs_judge_bycase(int m)    //第二重bfs
{
for(int i=1;i<=m;i++)
{
int rand_x=rand()%19,rand_y=rand()%19,rand_c=rand()%19,rand_d=rand()%19;
if(rand_x==rand_c&&rand_y==rand_d)
{
i--;
continue;
}
if(rand_x>1&&rand_y>1&&bfs_judge_bypeople(rand_x,rand_y)&&rand_c>1&&rand_d>1&&A.mazemap[rand_c][rand_d]==0)
{
A.mazemap[rand_x][rand_y]=-1;    //随机生成箱子的位置
A.mazemap[rand_c][rand_d]=-3;   //随机生成箱子的目标位置
}             //构建一个箱子和目标位置的组合
else
{
i--;
continue;
}
memset(used,0,sizeof(used));
used[rand_c][rand_d]=true;
queue<node>que;
que.push(node(rand_c,rand_d,0));     //逆推。。。。。
bool judge=false;
while(!que.empty())
{
node p = que.front();
que.pop();
if(A.mazemap[p.first][p.second]==-1)
{
//A.PrintMaze(20);
if(!bfs_judge_bypeople(p.first+dir[p.direction][0],p.second+dir[p.direction][1]))
continue;
A.mazemap[p.first][p.second]=-4;
judge=true;
break;
}
for(int j=0;j<=3;j++)
{
int nx=p.first+dir[j][0],ny=p.second+dir[j][1];
if((A.mazemap[nx][ny]==-1||A.mazemap[nx][ny]==0)&&!used[nx][ny]&&A.mazemap[nx+dir[j][0]][ny+dir[j][1]]==0)
{
que.push(node(nx,ny,j));        //同时考虑推箱子时候人的位置
used[nx][ny]=true;
}
}
}
if(judge==false)
{
A.mazemap[rand_x][rand_y]=0;
A.mazemap[rand_c][rand_d]=0;
i--;
continue;
}
}
return true;
}
void delete_by_position(int n)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(A.mazemap[i][j]==-1||A.mazemap[i][j]==-4||A.mazemap[i][j]==-2)
{
C.SetPos((j)*2,i);
printf("  ");
}
}
}
}

void create_by_position(int n)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(A.mazemap[i][j]==-1||A.mazemap[i][j]==-4)
{
C.SetPos((j)*2,i);
printf("□");    // 代表箱子
}
if(A.mazemap[i][j]==-2)
{
C.SetPos((j)*2,i);
printf("○");    // 代表人的位置
}  //代表推箱子的人
if(A.mazemap[i][j]==5)
{
C.SetPos((j)*2,i);
printf("☆");    //代表箱子的目标位置已经成功
}
}
}
}

int main(void)
{
printf("====请问要从上一关开始吗？==\n=需要输入1...不需要输入0======\n");
int judge_bynumber;
int n=20;
scanf("%d",&judge_bynumber);
int m;
int cnt=0;
if(judge_bynumber==1)
{
freopen("hehe.in","r",stdin);
C.SetPos(0,0);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
scanf("%d",&A.mazemap[i][j]);
}
scanf("%d",&m);
scanf("%d%d%d",&V.x,&V.y,&cnt);
fclose(stdin);
}
else
{
printf("=========请输入要的箱子数====\n");
scanf("%d",&m);
printf("=============地图规模为20*20======\n");
//scanf("%d",&n);
printf("=======请耐心等待地图生成======\n");
printf("=======地图生成如果太久请重试======\n");
do
{
//memset(used,0,sizeof(used));
A.RandomMaze(n,m);   //生成迷宫地图
//B.RandomMaze(n);
//A.PrintMaze(n);
}while(!bfs_judge_bypeople(n-2,n-1));  //广度优先搜素以保证迷宫不被堵住 （上次的深搜太费时了。。。）
//A.PrintMaze(n);
//A.PrintMaze(n);
bfs_judge_bycase(m);   //采用了两重bfs。。。。保证迷宫一定可解。。。QWQ。。QWQ。。QWQ。。QWQ。。QWQ。。QWQ。。QWQ。。QWQ。。QWQ。。QWQ
//A.PrintMaze(n);
A.mazemap[1][0]=-2;
V.x=1;
V.y=0;
cnt=0;
}
C.SetPos(0,0);
A.PrintMaze(n);                           //打印迷宫地图
printf("\n==================迷宫.......==================");
printf("\n说明:■不能走的区域\t◇走不通的区域");
printf("\n    “空格”代表未到过的区域");
printf("\n     ○代表您的所在位置");
printf("\n     □代表箱子的位置  ");
printf("\n     ◎代表箱子的目标位置");
printf("\n     ☆代表已经成功的目标位置");
printf("\n      按s键存档。。。。");
printf("把所有的箱子推到位就算您的胜利n(*≧▽≦*)n");
printf("\n============================================\n");
while(1)
{
if(cnt==m)
{
C.SetPos(0,n+1);
printf("========您太厉害了n(*≧▽≦*)n=======\n");
break;
}
int k=C.WaitKey(10.0);
if(k==224||k==0)
continue;
if(k==115)
{
freopen("hehe.in","w",stdout);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
printf("%d ",A.mazemap[i][j]);
}
printf("\n");
}
printf("%d %d %d %d",m,V.x,V.y,cnt);
fclose(stdout);

C.SetPos(0,n+1);
//printf("========存档成功！(*≧▽≦*)=======\n");

break;
}
if(k!=75&&k!=77&k!=72&&k!=80)
continue;
//printf("%d",k);
delete_by_position(n);
if(k==75&&A.mazemap[V.x][V.y-1]!=1)     //left
{
if(A.mazemap[V.x][V.y-1]==-1||A.mazemap[V.x][V.y-1]==-4)
{
if(A.mazemap[V.x][V.y-2]==0)
{
A.mazemap[V.x][V.y]=0;
A.mazemap[V.x][V.y-1]=-2;
A.mazemap[V.x][V.y-2]=-4;
create_by_position(n);
C.SetPos(0,n+1);   //默默的重置了坐标。。。。只是为了输出。。。。
continue;
}
if(A.mazemap[V.x][V.y-2]==-3)
{
A.mazemap[V.x][V.y]=0;
A.mazemap[V.x][V.y-1]=-2;
A.mazemap[V.x][V.y-2]=5;
cnt++;
create_by_position(n);
C.SetPos(0,n+1);
continue;

}
else
{
create_by_position(n);
C.SetPos(0,n+1);
continue;
}
}
else if(A.mazemap[V.x][V.y-1]==0)
{
A.mazemap[V.x][V.y]=0;
A.mazemap[V.x][V.y-1]=-2;
create_by_position(n);
C.SetPos(0,n+1);
continue;
}                //其实还有一种人踩到目标位置的情况。。。。懒了。。。。直接简化了。。。。
}
else if(k==77&&A.mazemap[V.x][V.y+1]!=1)    //right
{
if(A.mazemap[V.x][V.y+1]==-1||A.mazemap[V.x][V.y+1]==-4)
{
if(A.mazemap[V.x][V.y+2]==0)
{
A.mazemap[V.x][V.y]=0;
A.mazemap[V.x][V.y+1]=-2;
A.mazemap[V.x][V.y+2]=-4;
create_by_position(n);
C.SetPos(0,n+1);
continue;
}
if(A.mazemap[V.x][V.y+2]==-3)
{
A.mazemap[V.x][V.y]=0;
A.mazemap[V.x][V.y+1]=-2;
A.mazemap[V.x][V.y+2]=5;
cnt++;
create_by_position(n);
C.SetPos(0,n+1);
continue;
}
else
{
create_by_position(n);
C.SetPos(0,n+1);
continue;
}
}
else if(A.mazemap[V.x][V.y+1]==0)
{
A.mazemap[V.x][V.y]=0;
A.mazemap[V.x][V.y+1]=-2;
create_by_position(n);
C.SetPos(0,n+1);
continue;
}
}
else if(k==72&&A.mazemap[V.x-1][V.y]!=1)    //up
{
if(A.mazemap[V.x-1][V.y]==-1||A.mazemap[V.x-1][V.y]==-4)
{
if(A.mazemap[V.x-2][V.y]==0)
{
A.mazemap[V.x][V.y]=0;
A.mazemap[V.x-1][V.y]=-2;
A.mazemap[V.x-2][V.y]=-4;
create_by_position(n);
C.SetPos(0,n+1);                //默默的重置了坐标。。。。只是为了输出。。。。
continue;
}
if(A.mazemap[V.x-2][V.y]==-3)
{
A.mazemap[V.x][V.y]=0;
A.mazemap[V.x-1][V.y]=-2;
A.mazemap[V.x-2][V.y]=5;
cnt++;
create_by_position(n);
C.SetPos(0,n+1);
continue;
}
else
{
create_by_position(n);
C.SetPos(0,n+1);
continue;
}
}
else if(A.mazemap[V.x-1][V.y]==0)
{
A.mazemap[V.x][V.y]=0;
A.mazemap[V.x-1][V.y]=-2;
create_by_position(n);
C.SetPos(0,n+1);
continue;
}
}
else if(k==80&&A.mazemap[V.x+1][V.y]!=1)     //down
{
if(A.mazemap[V.x+1][V.y]==-1||A.mazemap[V.x+1][V.y]==-4)
{
if(A.mazemap[V.x+2][V.y]==0)
{
A.mazemap[V.x][V.y]=0;
A.mazemap[V.x+1][V.y]=-2;
A.mazemap[V.x+2][V.y]=-4;
create_by_position(n);
C.SetPos(0,n+1);
continue;
}
if(A.mazemap[V.x+2][V.y]==-3)
{
A.mazemap[V.x][V.y]=0;
A.mazemap[V.x+1][V.y]=-2;
A.mazemap[V.x+2][V.y]=5;
cnt++;
create_by_position(n);
C.SetPos(0,n+1);
continue;
}
else
{
create_by_position(n);
C.SetPos(0,n+1);
continue;
}
}
else if(A.mazemap[V.x+1][V.y]==0)
{
A.mazemap[V.x][V.y]=0;
A.mazemap[V.x+1][V.y]=-2;
create_by_position(n);
C.SetPos(0,n+1);
continue;
}
}
else
create_by_position(n);
C.SetPos(0,n+1);
//SetPos((V.y)*2,V.x);
//printf("○");
//A.PrintMaze(n);
/*if(V.x==n-2&&V.y==n-1)
{
printf("\n");

//system("pause");
getchar();
getchar();
break;
}*/

}
return 0;
}