#include <bits/stdc++.h>
using namespace std;

#define dump(n) cout<<"# "<<#n<<'='<<(n)<<endl
#define repi(i,a,b) for(int i=int(a);i<int(b);i++)
#define peri(i,a,b) for(int i=int(b);i-->int(a);)
#define rep(i,n) repi(i,0,n)
#define per(i,n) peri(i,0,n)
#define all(c) begin(c),end(c)
#define mp make_pair
#define mt make_tuple

typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<double> vd;
typedef vector<vd> vvd;
typedef vector<string> vs;

const int INF=1e9;
const int MOD=1e9+7;
const double EPS=1e-9;

template<typename T1,typename T2>
ostream& operator<<(ostream& os,const pair<T1,T2>& p){
	return os<<'('<<p.first<<','<<p.second<<')';
}
template<typename T>
ostream& operator<<(ostream& os,const vector<T>& a){
	os<<'[';
	rep(i,a.size()) os<<(i?" ":"")<<a[i];
	return os<<']';
}

typedef vector<vvi> vvvi;
typedef vector<vvvi> vvvvi;

template<typename Functor>
struct functor_traits{
	template<typename C,typename Ret,typename Arg,typename... Args>
	static Arg helper(Ret(C::*)(Arg,Args...));
	template<typename C,typename Ret,typename Arg,typename... Args>
	static Arg helper(Ret(C::*)(Arg,Args...)const);
	typedef decltype(helper(&Functor::operator())) first_argument_type;
};
template<typename Compare,typename T=typename functor_traits<Compare>::first_argument_type>
priority_queue<T,vector<T>,Compare> make_priority_queue(Compare comp){
	return priority_queue<T,vector<T>,Compare>(move(comp));
}

bool in(int h,int w,int i,int j){return 0<=i && i<h && 0<=j && j<w;}
bool in(int h,int w,pii p){return in(h,w,p.first,p.second);}

int calc(vs grid,pii king,pii a,pii b)
{
	int h=grid.size(),w=grid[0].size();
	rep(i,2) rep(j,2) grid[king.first+i][king.second+j]='*';
	vvi dist(h,vi(w,INF));
	queue<tuple<int,int,int>> q;
	q.emplace(a.first,a.second,0);
	while(q.size()){
		int i,j,d; tie(i,j,d)=q.front(); q.pop();
		if(!in(h,w,i,j) || grid[i][j]=='*' || dist[i][j]!=INF) continue;
		dist[i][j]=d;
		if(mp(i,j)==b) return d;
		rep(k,4)
			q.emplace(i+"\xff\x1\0\0"[k],j+"\0\0\xff\x1"[k],d+1);
	}
	return dist[b.first][b.second];
}

int calc(vs grid,pii king,pii p1,pii p2,pii q1,pii q2)
{
	return min(calc(grid,king,p1,q1)+calc(grid,king,p2,q2),
						 calc(grid,king,p1,q2)+calc(grid,king,p2,q1));
	//int h=grid.size(),w=grid[0].size();
	//rep(i,2) rep(j,2) grid[king.first+i][king.second+j]='*';
	//vvvvi dist(h,vvvi(w,vvi(h,vi(w,INF))));
	//queue<tuple<int,int,int,int,int>> q;
	//q.emplace(p1.first,p1.second,p2.first,p2.second,0);
	//while(q.size()){
	//	int i1,j1,i2,j2,d; tie(i1,j1,i2,j2,d)=q.front(); q.pop();
	//	if(!in(h,w,i1,j1) || !in(h,w,i2,j2) || grid[i1][j1]=='*' || grid[i2][j2]=='*'
	//	|| (i1==i2 && j1==j2) || dist[i1][j1][i2][j2]!=INF) continue;
	//	dist[i1][j1][i2][j2]=dist[i2][j2][i1][j1]=d;
	//	rep(k,4){
	//		q.emplace(i1+"\xff\x1\0\0"[k],j1+"\0\0\xff\x1"[k],i2,j2,d+1);
	//		q.emplace(i1,j1,i2+"\xff\x1\0\0"[k],j2+"\0\0\xff\x1"[k],d+1);
	//	}
	//}
	//return dist[q1.first][q1.second][q2.first][q2.second];
}

int main()
{
	for(int h,w;cin>>h>>w && h|w;){
		vs grid(h);
		rep(i,h) cin>>grid[i];
		//dump(mp(h,w));
		//rep(i,h) cout<<grid[i]<<endl;
		
		if(grid[0][0]=='X'){
			cout<<0<<endl;
			continue;
		}
		
		auto pq=make_priority_queue([](tuple<int,int,int,int> a,tuple<int,int,int,int> b){return get<3>(a)>get<3>(b);});
		{
			pii king(-1,-1),open1(-1,-1),open2(-1,-1);
			rep(i,h) rep(j,w){
				if(grid[i][j]=='X'){
					if(king==mp(-1,-1)) king=mp(i,j);
					grid[i][j]='.';
				}
				else if(grid[i][j]=='.')
					(open1==mp(-1,-1)?open1:open2)=mp(i,j);
				else if(grid[i][j]=='o')
					grid[i][j]='.';
			}
			int ki=king.first,kj=king.second;
			if(in(h,w,ki-1,kj) && grid[ki-1][kj]!='*' && grid[ki-1][kj+1]!='*')
				pq.emplace(ki,kj,0,calc(grid,king,open1,open2,mp(ki-1,kj),mp(ki-1,kj+1)));
			if(in(h,w,ki+2,kj) && grid[ki+2][kj]!='*' && grid[ki+2][kj+1]!='*')
				pq.emplace(ki,kj,1,calc(grid,king,open1,open2,mp(ki+2,kj),mp(ki+2,kj+1)));
			if(in(h,w,ki,kj-1) && grid[ki][kj-1]!='*' && grid[ki+1][kj-1]!='*')
				pq.emplace(ki,kj,2,calc(grid,king,open1,open2,mp(ki,kj-1),mp(ki+1,kj-1)));
			if(in(h,w,ki,kj+2) && grid[ki][kj+2]!='*' && grid[ki+1][kj+2]!='*')
				pq.emplace(ki,kj,3,calc(grid,king,open1,open2,mp(ki,kj+2),mp(ki+1,kj+2)));
		}
		
		vvvi dist(h,vvi(w,vi(4,INF)));
		while(pq.size()){
			//if(rand()%1000==0) printf("> %d\n",pq.size());
			int ki,kj,dir,step; tie(ki,kj,dir,step)=pq.top(); pq.pop();
			if(!in(h,w,ki,kj) || dist[ki][kj][dir]!=INF) continue;
			dist[ki][kj][dir]=step;
			if(step>=INF) break;
			
			pii open1,open2;
			if(dir==0) open1=mp(ki-1,kj),open2=mp(ki-1,kj+1);
			if(dir==1) open1=mp(ki+2,kj),open2=mp(ki+2,kj+1);
			if(dir==2) open1=mp(ki,kj-1),open2=mp(ki+1,kj-1);
			if(dir==3) open1=mp(ki,kj+2),open2=mp(ki+1,kj+2);
			
			pq.emplace(ki+"\xff\x1\0\0"[dir],kj+"\0\0\xff\x1"[dir],dir^1,step+1);
			if(in(h,w,ki-1,kj) && grid[ki-1][kj]!='*' && grid[ki-1][kj+1]!='*')
				pq.emplace(ki,kj,0,step+calc(grid,mp(ki,kj),open1,open2,mp(ki-1,kj),mp(ki-1,kj+1)));
			if(in(h,w,ki+2,kj) && grid[ki+2][kj]!='*' && grid[ki+2][kj+1]!='*')
				pq.emplace(ki,kj,1,step+calc(grid,mp(ki,kj),open1,open2,mp(ki+2,kj),mp(ki+2,kj+1)));
			if(in(h,w,ki,kj-1) && grid[ki][kj-1]!='*' && grid[ki+1][kj-1]!='*')
				pq.emplace(ki,kj,2,step+calc(grid,mp(ki,kj),open1,open2,mp(ki,kj-1),mp(ki+1,kj-1)));
			if(in(h,w,ki,kj+2) && grid[ki][kj+2]!='*' && grid[ki+1][kj+2]!='*')
				pq.emplace(ki,kj,3,step+calc(grid,mp(ki,kj),open1,open2,mp(ki,kj+2),mp(ki+1,kj+2)));
		}
		int res=*min_element(all(dist[0][0]));
		cout<<(res<INF?res:-1)<<endl;
	}
}

Measured memory_bytes: 1348