#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
char graph[9][9];
bool vis[9][9][9][9][9][9][9][9];
int m,n;
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
//X人 *箱子 #墙 @hole
struct Node{
int x[4],y[4]; //0-2为箱子,3为人
int step;
}t;
bool judge(int x,int y){
if(x>=0 && x<m && y>=0 && y<n && graph[x][y]!='#')
return true;
return false;
}
int bfs(){
queue<Node> q;
Node cur,next;
vis[t.x[0]][t.y[0]][t.x[1]][t.y[1]][t.x[2]][t.y[2]][t.x[3]][t.y[3]] = true;
q.push(t);
while(!q.empty()){
cur = q.front();
q.pop();
//判断是否到达目标状态
if(graph[cur.x[0]][cur.y[0]]=='@' && graph[cur.x[1]][cur.y[1]]=='@' && graph[cur.x[2]][cur.y[2]]=='@')
return cur.step;
for(int i=0;i<4;i++){
next = cur;
next.x[3] += dx[i];
next.y[3] += dy[i]; //人进行移动
if(judge(next.x[3],next.y[3])){ //人到达的位置是否合法
bool flag = false;
for(int j=0;j<3;j++){ //看人的新位置是否与某个箱子重合
if(next.x[3]==next.x[j] && next.y[3]==next.y[j]){
next.x[j] += dx[i]; //该箱子被推动了
next.y[j] += dy[i];
if(!judge(next.x[j],next.y[j]))
flag = true;
for(int k=0;k<3;k++){ //看其他箱子是否阻挡了该箱子的位置
if(j!=k && next.x[j]==next.x[k] && next.y[j]==next.y[k])
flag = true;
}
}
}
if(flag) continue;
if(vis[next.x[0]][next.y[0]][next.x[1]][next.y[1]][next.x[2]][next.y[2]][next.x[3]][next.y[3]]) continue;
vis[next.x[0]][next.y[0]][next.x[1]][next.y[1]][next.x[2]][next.y[2]][next.x[3]][next.y[3]] = true;
next.step ++;
q.push(next);
}
}
}
return -1;
}
int main(){
while(scanf("%d%d",&m,&n)!=EOF){
int idx = 0;
t.step = 0;
for(int i=0;i<m;i++)
for(int j=0;j<n;j++){
scanf(" %c",&graph[i][j]);
if(graph[i][j]=='*'){
t.x[idx] = i;
t.y[idx++] = j; //箱子的位置
}
else if(graph[i][j]=='X'){
t.x[3] = i;
t.y[3] = j; //人的位置
}
}
memset(vis,false,sizeof(vis));
int res = bfs();
printf("%d\n",res);
}
return 0;
}