#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cassert>

using namespace std;

#define FOR(i,k,n) for(int i=(k); i<(int)(n); ++i)
#define REP(i,n) FOR(i,0,n)
#define FORIT(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)

template<class T> void debug(T begin, T end){ for(T i = begin; i != end; ++i) cerr<<*i<<" "; cerr<<endl; }
inline bool valid(int x, int y, int W, int H){ return (x >= 0 && y >= 0 && x < W && y < H); }

typedef long long ll;
const int INF = 100000000;
const double EPS = 1e-8;
const int MOD = 1000000007;
int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};
int bx[4][2] = { {2, 2}, {0, 1}, {-1, -1}, {0, 1}};
int by[4][2] = { {0, 1}, {2, 2}, {0, 1}, {-1, -1}};
int from[4][2] = { {0, 1}, {1, 0}, {0, 1}, {1, 0} };
int to[4][2] = { {0, 1}, {1, 0}, {1, 0}, {0, 1} };
int H, W;
int bfs(const vector<string>& grid, int sx, int sy, int gx, int gy){
  queue<int> qx, qy;
  int d[50][50]; memset(d, -1, sizeof(d));
  qx.push(sx); qy.push(sy);
  d[sy][sx] = 0;
  //printf("start %d %d\n", sx, sy);
  //REP(y, H){ cout<<grid[y]<<endl; }
  while(!qx.empty()){
    int x = qx.front(); qx.pop();
    int y = qy.front(); qy.pop();
    if(x == gx && y == gy) return d[y][x];
    REP(r, 4){
      int nx = x + dx[r];
      int ny = y + dy[r];
      if(valid(nx, ny, W, H) && grid[ny][nx] != '*' && d[ny][nx] == -1){
        d[ny][nx] = d[y][x] + 1;
        qx.push(nx); qy.push(ny);
      }
    }
  }
  return INF;
}
struct S{
  int x, y, r, d;
  S(int x, int y, int r, int d) : x(x), y(y), r(r), d(d) {}
  bool operator < (const S& s) const {
    return d > s.d;
  }
  void print(){
    printf("x = %d y = %d r = %d d = %d\n", x, y, r, d);
  }
};

int main(){
  while(cin>>H>>W && H){
    vector<string> grid(H);
    vector<string> grid_sub(H, string('.', W));
    REP(i, H) cin>>grid[i];
    int sx = W, sy = H;
    REP(y, H) REP(x, W)if(grid[y][x] == 'X'){
      sx = min(x, sx); sy = min(sy, y); 
    }
    if(sx == 0 && sy == 0){
      cout<<0<<endl;
      continue;
    }
    priority_queue<S> que;
    REP(r, 4){
      int nx = sx + dx[r];
      int ny = sy + dy[r];
      bool ok = true;
      if(!valid(nx, ny, W, H) || !valid(nx + 1, ny + 1, W, H)) continue;
      REP(dx, 2)REP(dy, 2) if(grid[ny + dy][nx + dx] == '*') ok = false;
      if(!ok) continue;
      //printf(">nx = %d ny = %d r = %d\n", nx, ny, r);
      /* 空白が目的地 */
      vector<int> tx, ty;
      REP(y, H)REP(x, W) if(grid[y][x] == '.'){
        //printf("tx = %d ty = %d\n", x, y);
        tx.push_back(x); ty.push_back(y);
      }
      /* 大ピースが進む場所が出発地 */
      vector<int> fx, fy;
      REP(i, 2){ fx.push_back(sx + bx[r][i]); fy.push_back(sy + by[r][i]); }
      //REP(i, 2) printf("fx = %d fy = %d\n", fx[i], fy[i]);
      int cost = INF;
      REP(k, 4){
        //printf("> k = %d\n", k);
        REP(y, H)REP(x, W){
          if(grid[y][x] == '*') grid_sub[y][x] = '*';
          else if(sx <= x && x <= sx + 1 && sy <= y && y <= sy + 1) grid_sub[y][x] = '*';
          else if(grid[y][x] == 'o') grid_sub[y][x] = '.';
          else grid_sub[y][x] = '.';
        }
        int f1 = from[k][0], t1 = to[k][0];
        int f2 = from[k][1], t2 = to[k][1];
        int c1 = bfs(grid_sub, fx[f1], fy[f1], tx[t1], ty[t1]);
        int c2 = bfs(grid_sub, fx[f2], fy[f2], tx[t2], ty[t2]);
        //printf("(%d, %d) -> (%d, %d) : %d\n", fx[f1], fy[f1], tx[t1], ty[t1], c1);
        //printf("(%d, %d) -> (%d, %d) : %d\n", fx[f2], fy[f2], tx[t2], ty[t2], c2);
        cost = min(cost, c1 + c2 + 1);
      }
      if(cost == INF) continue;
      que.push(S(nx, ny, (r + 2) % 4, cost));
    }
    bool used[50][50][4] = {};
    bool output = false;
    while(!que.empty()){
      S s = que.top(); que.pop();
      if(s.x == 0 && s.y == 0){
        printf("%d\n", s.d);
        output = true;
        break;
      }
      if(used[s.y][s.x][s.r]) continue;
      used[s.y][s.x][s.r] = true;
      //s.print();
      REP(r, 4){
        int nx = s.x + dx[r];
        int ny = s.y + dy[r];
        bool ok = true;
        if(!valid(nx, ny, W, H) || !valid(nx + 1, ny + 1, W, H)) continue;
        REP(dx, 2)REP(dy, 2) if(grid[ny + dy][nx + dx] == '*') ok = false;
        if(!ok) continue;
        //printf(">nx = %d ny = %d r = %d\n", nx, ny, r);
        /* 空白が目的地 */
        vector<int> tx, ty;
        REP(i, 2){ tx.push_back(s.x + bx[s.r][i]); ty.push_back(s.y + by[s.r][i]); }
        /* 大ピースが進む場所が出発地 */
        vector<int> fx, fy;
        REP(i, 2){ fx.push_back(s.x + bx[r][i]); fy.push_back(s.y + by[r][i]); }
        //REP(i, 2) printf("fx = %d fy = %d\n", fx[i], fy[i]);
        int cost = INF;
        REP(k, 4){
          //printf("> k = %d\n", k);
          REP(y, H)REP(x, W){
            if(grid[y][x] == '*') grid_sub[y][x] = '*';
            else if(s.x <= x && x <= s.x + 1 && s.y <= y && y <= s.y + 1) grid_sub[y][x] = '*';
            else if(grid[y][x] == 'o') grid_sub[y][x] = '.';
            else grid_sub[y][x] = '.';
          }
          int f1 = from[k][0], t1 = to[k][0];
          int f2 = from[k][1], t2 = to[k][1];
          int c1 = bfs(grid_sub, fx[f1], fy[f1], tx[t1], ty[t1]);
          int c2 = bfs(grid_sub, fx[f2], fy[f2], tx[t2], ty[t2]);
          //printf("(%d, %d) -> (%d, %d) : %d\n", fx[f1], fy[f1], tx[t1], ty[t1], c1);
          //printf("(%d, %d) -> (%d, %d) : %d\n", fx[f2], fy[f2], tx[t2], ty[t2], c2);
          cost = min(cost, c1 + c2 + 1);
        }
        if(cost == INF) continue;
        if(!used[ny][nx][(r + 2) % 4]){
          que.push(S(nx, ny, (r + 2) % 4, s.d + cost));
        }
      }
    }
    if(!output) cout<<-1<<endl;
  }
  return 0;
}

Measured memory_bytes: 1316