这个程序是在大三上学期期末之后实现的,当时手机上有一个推箱子游戏,有 几关怎么也过不去,一怒之下写了个程序,加了几个优化之后,效率还凑合。最坏情况下也可以在几秒时间内解出7*7的推箱子,一般关卡基本上1秒之内。这个 程序还有很大的优化空间的,只是写时间长了,就不想去继续优化了。
程序简介
采用广度优先搜索,自己实现了简单的hashMap用以存储状态
程序从 in.txt 读入数据,第一行是一个数,表示数据有几关,下面是若干个字符矩阵,给一组输入样例
5
#########
##*@*####
##*#D**##
#*BO*O*##
#**DD*###
###*#O###
###***###
#########
#########
#########
#**OD*###
#*ODOD**#
#BDODO@*#
#*ODOD*##
#**OD**##
#########
#########
#########
#########
#**#***##
#*DOOD*##
#@DOB*###
#*DOOD*##
#**#***##
#########
#########
#########
#########
##**#####
#*@D#####
##D*#####
##*D*####
#OD**####
#OOBO####
#########
#########
#########
###****##
###DDD*##
#@*DOO*##
#*DOOO###
####**###
#########
#########
#########
#########
###**####
###D*####
#**B*@###
#**B**###
#**B*####
###B*####
###O#####
#########
#########
#****####
#*D*@####
##B**####
#*B*#####
#*B*#####
#*B*#####
#*O*#####
#########
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#define N 20000000
#define H 4000010
#define mod 4000007
using namespace std;
int dx[]= {0,1,0,-1};
int dy[]= {1,0,-1,0};
int da[4][3]=
{
{0,1,1},
{1,1,0},
{0,-1,-1},
{-1,-1,0}
};
int db[4][3]=
{
{1,1,0},
{0,-1,-1},
{-1,-1,0},
{0,1,1}
};
int da1[4][3]=
{
{0,-1,-1},
{1,1,0},
{0,1,1},
{-1,-1,0}
};
int db1[4][3]=
{
{1,1,0},
{0,1,1},
{-1,-1,0},
{0,-1,-1}
};
int border[9][9];
int bn[20];
/*
0 空白 *
1 砖 #
2 屎 O
3 蜗牛 @
4 箱子 D
5 屎加箱子 B
6 屎加蜗牛 Q
*/
int cg(char c)
{
switch(c)
{
case '*':
return 0;
case '#':
return 1;
case 'O':
return 2;
case '@':
return 3;
case 'D':
return 4;
case 'B':
return 5;
case 'Q':
return 6;
}
}
struct board
{
int b[5],s;
board() {}
bool operator==(board t)
{
for(int i=0; i<=4; i++)
if(t.b[i]!=b[i])return false;
return true;
}
bool encode(int bd[7][7])
{
int num,x,y;
bool flag=true;
memset(b,0,sizeof(b));
for(int i=0; i<=6; i++)
for(int j=0; j<=6; j++)
{
if(bd[i][j]==4)flag=false;
num=i*7+j;
x=num/10;
y=num%10;
b[x]|=(bd[i][j]<<(y*3));
if(bd[i][j]==3 || bd[i][j]==6)
{
s=i*7+j;
}
}
return flag;
}
bool decode(int bd[7][7])
{
int x,y;
bool flag=true;
for(int i=0; i<=4; i++)
{
for(int j=0; j<=9; j++)
{
x=(i*10+j)/7;
y=(i*10+j)%7;
bd[x][y]=(b[i]>>(j*3))%8;
if(bd[x][y]==4)flag=false;
}
}
return flag;
}
};
int tim,sum;
struct hashmap
{
board d[N];
int head[H],next[N],cnt;
void init()
{
memset(head,-1,sizeof(head));
cnt=0;
}
int hashcode(board t)
{
int h=0;
for(int i=0; i<=4; i++)
{
h=(h>>2)^(h<<2)^t.b[i];
}
h%=mod;
if(h<0)h+=mod;
return h;
}
int find(board t)
{
int h=hashcode(t);
for(int i=head[h]; i!=-1; i=next[i])
{
if(d[i]==t)return i;
}
return -1;
}
int push(board t)
{
int h=hashcode(t);
//int num=0;
tim++;
for(int i=head[h]; i!=-1; i=next[i])
{
sum++;
if(d[i]==t)return -1;
// num++;
}
// cout<<num<<endl;
sum++;
d[cnt]=t;
next[cnt]=head[h];
head[h]=cnt++;
return cnt-1;
}
} hm;
int que[N],pr[N];
bool check(int x,int y,int d,int bd[7][7])
{
if(x>=7 || x<=-1 || y>=7 || y<=-1)return false;
int tx,ty,a,b;
if(bd[x][y]==4 || bd[x][y]==5)//如果是个箱子
{
tx=x+dx[d];
ty=y+dy[d];
if(tx>=7 || tx<=-1 || ty>=7 || ty<=-1)return false;
if(bd[tx][ty]!=0 && bd[tx][ty]!=2)return false;//再下一个位置一定得是空的
if(border[tx+1][ty+1]==1)return false;
int B=bd[tx][ty]==2,A=1;//四个箱子不能在一起,除非有四个屎
for(int i=0; i<3; i++)
{
a=tx+da[d][i];
b=ty+db[d][i];
if(a>=7 || a<=-1 || b>=7 || b<=-1)A++;
else if(bd[a][b]==4 || bd[a][b]==1)A++;
else if(bd[a][b]==5)A++,B++;
}
if(A==4 && B!=4)return false;
B=bd[tx][ty]==2;
A=1;//四个箱子不能在一起,除非有四个屎
for(int i=0; i<3; i++)
{
a=tx+da1[d][i];
b=ty+db1[d][i];
if(a>=7 || a<=-1 || b>=7 || b<=-1)A++;
else if(bd[a][b]==4 || bd[a][b]==1)A++;
else if(bd[a][b]==5)A++,B++;
}
if(A==4 && B!=4)return false;
}
if(bd[x][y]==1)return false;
return true;
}
void change(int bd[7][7],int b[7][7],int sx,int sy,int x,int y,int d)
{
memcpy(b,bd,sizeof(int)*49);
int tx,ty;
if(bd[x][y]==4 || bd[x][y]==5)//如果是个箱子
{
tx=x+dx[d];
ty=y+dy[d];
if(bd[tx][ty]==0)
b[tx][ty]=4;
else if(bd[tx][ty]==2)
b[tx][ty]=5;
}
if(bd[x][y]==4)
b[x][y]=3;
else if(bd[x][y]==5)
b[x][y]=6;
else if(bd[x][y]==0)
b[x][y]=3;
else if(bd[x][y]==2)
b[x][y]=6;
if(bd[sx][sy]==3)
b[sx][sy]=0;
else if(bd[sx][sy]==6)
b[sx][sy]=2;
}
int search(board t)
{
queue<int>q;
hm.init();
int front=0,rear=0,tmp,bd[7][7],b[7][7],x,y,tx,ty;
board tt;
que[rear++]=hm.push(t);
pr[front]=-1;
while(front<rear)
{
tmp=que[front++];
t=hm.d[tmp];
if(t.decode(bd))return front-1;
x=t.s/7;
y=t.s%7;
//cout<<x<<" "<<y<<endl;
for(int i=0; i<=3; i++)
{
tx=x+dx[i];
ty=y+dy[i];
if(check(tx,ty,i,bd))
{
//if(tmp==2)cout<<'a'<<i<<endl;
change(bd,b,x,y,tx,ty,i);
if(tt.encode(b))
{
hm.push(tt);
pr[rear]=front-1;
que[rear++]=hm.cnt-1;
return rear-1;
}
//if(tmp==0)cout<<'a'<<tt.s/7<<" "<<tt.s%7<<endl;
//
// for(int i=0;i<=6;i++,cout<<endl)
// for(int j=0;j<=6;j++)
// cout<<b[i][j];
if(hm.push(tt)!=-1)
{
pr[rear]=front-1;
que[rear++]=hm.cnt-1;
if(rear==N)cout<<"ddd"<<endl;
if(rear%1000000==0)cout<<rear<<endl;
}
}
}
}
return -1;
}
void output(int f)
{
if(pr[f]==-1)return ;
output(pr[f]);
int a,b,c,d;
a=hm.d[f].s/7;
b=hm.d[f].s%7;
c=hm.d[pr[f]].s/7;
d=hm.d[pr[f]].s%7;
if(a==c)
{
if(b>d)cout<<"R";
else cout<<"L";
}
else
{
if(a>c)cout<<"D";
else cout<<"U";
}
}
void initialize(char bd[9][9])
{
memset(border,0,sizeof(border));
int x,y;
for(int i=1; i<=7; i++)
for(int j=1; j<=7; j++)
if(bd[i][j]=='*' || bd[i][j]=='@')
{
for(int k=0; k<=3; k++)
{
x=i+dx[k];
y=j+dy[k];
if(bd[x][y]=='#')
{
x=i+dx[(k+1)%4];
y=j+dy[(k+1)%4];
if(bd[x][y]=='#')border[i][j]=1;
}
}
}
// for(int i=0; i<=8; i++,cout<<endl)
// for(int j=0; j<=8; j++)
// cout<<border[i][j]<<" ";
}
int main()
{
freopen("in.txt","r",stdin);
int num;
scanf("%d",&num);
while(num--)
{
char str[9][9];
int bd[7][7];
for(int i=0; i<=8; i++)
{
scanf("%s",str[i]);
}
for(int i=1; i<=7; i++)
for(int j=1; j<=7; j++)
{
bd[i-1][j-1]=cg(str[i][j]);
}
initialize(str);
board t;
t.encode(bd);
tim=sum=0;
int tmp=search(t);
//cout<<tmp<<endl;
output(tmp);
cout<<endl<<endl;
cout<<sum*1.0/tim;
}
return 0;
}