#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

template<class T> inline void chmin(T &a, const T &b) { if(a > b) a = b; }

struct state {
	int x, y, d, dist;
	state(int x_, int y_, int d_, int dist_):x(x_), y(y_), d(d_), dist(dist_) {}
	state(const state &s):x(s.x), y(s.y), d(s.d), dist(s.dist) {}
	bool operator>(const state &s) const {
		return dist > s.dist;
	}
};

#define X first
#define Y second

constexpr int INF = (1 << 28);
constexpr int MAX_SIZE = 50;
constexpr int dx[4] = {1, -1, 0, 0};
constexpr int dy[4] = {0, 0, 1, -1};
constexpr int ddx[4][2] = {{2, 2}, {-1, -1}, {0, 1}, {0, 1}};
constexpr int ddy[4][2] = {{0, 1}, {0, 1}, {2, 2}, {-1, -1}};

int h, w;
string field[MAX_SIZE + 2];
int dist[MAX_SIZE + 2][MAX_SIZE + 2][4];

void overwrite(int x, int y, char c) {
	for(int i = 0; i <= 1; ++i) {
		for(int j = 0; j <= 1; ++j) {
			field[y + i][x + j] = c;
		}
	}
}

vector<vector<int>> bfs(const pair<int, int> &start) {
	vector<vector<int>> cost(h + 2, vector<int>(w + 2, INF));
	queue<pair<int, int>> que;
	que.push(start);
	cost[start.Y][start.X] = 0;

	while(!que.empty()) {
		const int x = que.front().X;
		const int y = que.front().Y;
		que.pop();

		for(int d = 0; d < 4; ++d) {
			const int nx = x + dx[d], ny = y + dy[d];
			if(field[ny][nx] == '*') continue;
			if(cost[ny][nx] > cost[y][x] + 1) {
				que.push({nx, ny});
				cost[ny][nx] = cost[y][x] + 1;
			}
		}
	}
	return cost;
}

int dijkstra(const vector<state> &start) {
	fill(dist[0][0], dist[0][0] + (MAX_SIZE + 2) * (MAX_SIZE + 2) * 4, INF);
	priority_queue<state, vector<state>, greater<state>> que;
	for(const auto &s : start) {
		que.push(s);
		dist[s.x][s.y][s.d] = s.dist;
	}

	while(!que.empty()) {
		const state s = que.top();
		que.pop();

		if(s.dist > dist[s.x][s.y][s.d]) continue;
		if(s.x == 1 && s.y == 1) return s.dist;

		overwrite(s.x, s.y, '*');
		const auto c1 = bfs({s.x+ddx[s.d][0], s.y+ddy[s.d][0]});
		const auto c2 = bfs({s.x+ddx[s.d][1], s.y+ddy[s.d][1]});
		overwrite(s.x, s.y, 'o');
		for(int d = 0; d < 4; ++d) {
			const int nx = s.x + dx[d], ny = s.y + dy[d];
			const int nx1 = s.x + ddx[d][0], nx2 = s.x + ddx[d][1];
			const int ny1 = s.y + ddy[d][0], ny2 = s.y + ddy[d][1];

			if(field[ny1][nx1] == '*' || field[ny2][nx2] == '*') continue;
			int n_dist = s.dist + 1;
			if(s.d != d) n_dist += min(c1[ny1][nx1] + c2[ny2][nx2], c1[ny2][nx2] + c2[ny1][nx1]);
			if(dist[nx][ny][(d ^ 1)] > n_dist) {
				dist[nx][ny][(d ^ 1)] = n_dist;
				que.push({nx, ny, (d ^ 1), n_dist});
			}
		}
	}

	return -1;
}

int main() {
	cin.tie(nullptr);
	ios::sync_with_stdio(false);

	while(cin >> h >> w && h) {
		field[0] = field[h + 1] = string(w + 2, '*');
		for(int i = 1; i <= h; ++i) {
			cin >> field[i];
			field[i] = '*' + field[i] + '*';
		}

		int sx = INF, sy = INF;
		vector<pair<int, int>> ps;

		for(int y = 1; y <= h; ++y) {
			for(int x = 1; x <= w; ++x) {
				if(field[y][x] == '.') {
					ps.emplace_back(x, y);
					field[y][x] = 'o';
				}
				else if(field[y][x] == 'X') {
					chmin(sx, x);
					chmin(sy, y);
				}
			}
		}

		if(sx == 1 && sy == 1) {
			cout << 0 << endl;
			continue;
		}

		overwrite(sx, sy, '*');
		const auto c1 = bfs(ps[0]);
		const auto c2 = bfs(ps[1]);
		overwrite(sx, sy, 'o');

		vector<state> start;
		for(int d = 0; d < 4; ++d) {
			int init_dist = INF;
			for(int i = 0; i <= 1; ++i) {
				chmin(init_dist, c1[sy+ddy[d][i]][sx+ddx[d][i]] + c2[sy+ddy[d][1-i]][sx+ddx[d][1-i]]);
			}
			if(init_dist == INF) continue;
			start.emplace_back(sx, sy, d, init_dist);
		}

		cout << dijkstra(start) << endl;
	}

	return EXIT_SUCCESS;
}

Measured memory_bytes: 1324