#include <bits/stdc++.h>
const int INF = 0x3f3f3f3f;
const int MaxN = 1000 + 10;
const int MaxM = 1000 + 10;
const int dx[] = {1, 0, -1, 0};
const int dy[] = {0, -1, 0, 1};
struct Node {
  int x, y;
};
struct NodeStatus {
  int step[3];
} answer[MaxN][MaxM];
char board[MaxN][MaxM];
int n, m;
void BFS(int country) {
  std::queue<Node> Q;
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < m; ++j) {
      if (board[i][j] == country + '1') {
        answer[i][j].step[country] = 0;
        Q.push((Node){i, j});
      }
    }
  }
  while (!Q.empty()) {
    Node start = Q.front();
    Q.pop();
    for (int i = 0; i < 4; ++i) {
      Node next;
      next.x = start.x + dx[i];
      next.y = start.y + dy[i];
      if (next.x < 0 || next.x >= n || next.y < 0 || next.y >= m ||
          board[next.x][next.y] == '#')
        continue;
      bool isPoint = (board[next.x][next.y] == '.') ? true : false;
      if (isPoint + answer[start.x][start.y].step[country] <
              answer[next.x][next.y].step[country] ||
          answer[next.x][next.y].step[country] == -1) {
        answer[next.x][next.y].step[country] =
            isPoint + answer[start.x][start.y].step[country];
        Q.push(next);
      }
    }
  }
}
int main() {
  std::ios::sync_with_stdio(false);
  std::cin >> n >> m;
  memset(answer, -1, sizeof(answer));
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < m; ++j) {
      std::cin >> board[i][j];
    }
  }
  for (int i = 0; i < 3; ++i) BFS(i);
  int fuck = INF;
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < m; ++j) {
      if (board[i][j] == '#') continue;
      bool isPoint = (board[i][j] == '.') ? true : false;
      if (answer[i][j].step[0] != -1 && answer[i][j].step[1] != -1 &&
          answer[i][j].step[2] != -1) {
        fuck = std::min(fuck, answer[i][j].step[0] + answer[i][j].step[1] +
                                  answer[i][j].step[2] - isPoint * 2);
      }
    }
  }
  (fuck == INF) ? std::cout << -1 : std::cout << fuck;
  return 0;
}
