#include <cstdio>
#include <algorithm>
#include <queue>
#include <map>
#include <memory>

#define rep(i, n) for(int i = 0; i < n; ++i)

using namespace std;

typedef vector<vector<int>> R;
typedef shared_ptr<R> Q;
typedef pair<pair<int, int>, Q> P;

int table[6][4] = {
	{1, 3, 4, 2},
	{0, 2, 5, 3},
	{0 ,4, 5, 1},
	{0, 1, 5, 4},
	{0, 3, 5, 2},
	{1, 2, 4, 3}
};

int move(int index, int dx, int dy){
	int a = index / 4;
	int b = index % 4;
	int s, t;
	if(dx == -1){
		s = table[a][b];
		t = 5 - a;
	}
	else if(dx == 1){
		s = table[a][(b + 2) % 4];
		t = a;
	}
	else if(dy == -1){
		s = table[a][(b + 1) % 4];
		t = table[a][b];
	}
	else{
		s = table[a][(b + 3) % 4];
		t = table[a][b];
	}
	return s * 4 + find(table[s], table[s] + 4, t) - table[s];
}

int n ,m;
char g[20][20];
int sx[3];
int sy[3];
int st[3];
int d[3][20][20][24];
map<vector<vector<int>>, int> f;

int approximate(vector<vector<int>>& t){
	int p[6][3] = {
		{0, 1, 2},
		{0, 2, 1},
		{1, 0, 2},
		{1, 2, 0},
		{2, 0, 1},
		{2, 1, 0}
	};

	int u = -1;
	rep(i, 6){
		int v = d[p[i][0]][t[0][0]][t[0][1]][t[0][2]] + d[p[i][1]][t[1][0]][t[1][1]][t[1][2]] + d[p[i][2]][t[2][0]][t[2][1]][t[2][2]];
		if(u == -1 || u > v){
			u = v;
		}
	}
	return u;
}

bool is_reached(vector<vector<int>>& t){
	int p[6][3] = {
		{0, 1, 2},
		{0, 2, 1},
		{1, 0, 2},
		{1, 2, 0},
		{2, 0, 1},
		{2, 1, 0}
	};

	rep(a, 6){
		bool b = true;
		rep(i, 3){
			if(!(t[i][0] == sx[p[a][i]] && t[i][1] == sy[p[a][i]] && t[i][2] / 4 == st[p[a][i]])){
				b = false;
			}
		}
		if(b){
			return true;
		}
	}
	return false;
}

int main(){
	scanf("%d%d", &n, &m);
	rep(i, n){
		rep(j, m){
			scanf(" %c", &g[i][j]);
		}
	}

	int t = 0;
	rep(i, n){
		rep(j, m){
			if('1' <= g[i][j] && g[i][j] <= '6'){
				sx[t] = i;
				sy[t] = j;
				st[t] = g[i][j] - '1';
				++t;
			}
		}
	}
	rep(a, 3){
		rep(i, n){
			rep(j, m){
				rep(k, 24){
					d[a][i][j][k] = 10000;
				}
			}
		}

		queue<vector<int>> q;
		rep(i, 4){
			d[a][sx[a]][sy[a]][st[a] * 4 + i] = 0;
			q.push({sx[a], sy[a], st[a] * 4 + i});
		}
		while(!q.empty()){
			auto v = q.front();
			q.pop();
			int dx[4] = {-1, 0, 0, 1};
			int dy[4] = {0, -1, 1, 0};
			rep(i, 4){
				int x = v[0] + dx[i];
				int y = v[1] + dy[i];
				int index = move(v[2], dx[i], dy[i]);
				if(0 <= x && x < n && 0 <= y && y < m && g[x][y] != 'x' && d[a][x][y][index] == 10000){
					d[a][x][y][index] = d[a][v[0]][v[1]][v[2]] + 1;
					q.push({x, y, index});
				}
			}
		}
	}

	priority_queue<P, vector<P>, greater<P>> q;
	vector<vector<int>> s;
	rep(i, n){
		rep(j, m){
			if(g[i][j] == 'o'){
				s.push_back({i, j, 0});
			}
		}
	}
	q.push({{approximate(s), approximate(s)}, Q(new R(s))});
	while(!q.empty()){
		/*
		printf("(%d, %d)\n", q.top().first.first, q.top().first.second);
		*/

		auto v = *q.top().second;
		q.pop();
		int dx[4] = {-1, 0, 0, 1};
		int dy[4] = {0, -1, 1, 0};
		rep(a, 3){
			rep(i, 4){
				int x = v[a][0] + dx[i];
				int y = v[a][1] + dy[i];
				int index = move(v[a][2], dx[i], dy[i]);
				auto t = v;
				t[a][0] = x;
				t[a][1] = y;
				t[a][2] = index;
				bool b = true;
				rep(j, 3){
					if(v[j][0] == x && v[j][1] == y){
						b = false;
					}
				}
				if(0 <= x && x < n && 0 <= y && y < m && g[x][y] != 'x' && b && f.find(t) == f.end()){
					f[t] = f[v] + 1;
					if(is_reached(t)){
						printf("%d\n", f[t]);
						return 0;
					}
					q.push({{approximate(t) + f[t], approximate(t)}, Q(new R(t))});
				}
			}
		}
	}
	return 0;
}

Measured memory_bytes: 172316