#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1000 + 7;
char input[MAXN][MAXN];
int n, m, height[MAXN][MAXN][4];
queue<int> cityX[4], cityY[4], extraX, extraY;
bool isPassed[MAXN][MAXN], isReachable[MAXN][MAXN][4];
deque<int> neighborQueX, neighborQueY;
void extraBFS(int extX, int extY, int cityCounter) {
  extraX.push(extX);
  extraY.push(extY);
  isPassed[extX][extY] = true;
  while (extraX.size()) {
    extX = extraX.front();
    extY = extraY.front();
    extraX.pop();
    extraY.pop();
    isReachable[extX][extY][cityCounter] = true;
    int extNX, extNY;
    for (int i = 0; i < 2; ++i) {
      for (int j = -1; j < 2; j += 2) {
        if (i) {
          extNX = extX + j;
          extNY = extY;
        } else {
          extNX = extX;
          extNY = extY + j;
        }
        if (input[extNX][extNY] >= '1' and input[extNX][extNY] <= '3' and
            !isPassed[extNX][extNY]) {
          isPassed[extNX][extNY] = true;
          height[extNX][extNY][cityCounter] = height[extX][extY][cityCounter];
          extraX.push(extNX);
          cityX[cityCounter].push(extNX);
          extraY.push(extNY);
          cityY[cityCounter].push(extNY);
        }
      }
    }
  }
}
void BFS(int cityCounter) {
  int X, Y;
  while (cityX[cityCounter].size()) {
    X = cityX[cityCounter].front(), Y = cityY[cityCounter].front();
    cityX[cityCounter].pop();
    cityY[cityCounter].pop();
    isReachable[X][Y][cityCounter] = true;
    neighborQueX.clear();
    neighborQueY.clear();
    int neighborX, neighborY;
    for (int i = 0; i < 2; ++i) {
      for (int j = -1; j < 2; j += 2) {
        if (i) {
          neighborX = X + j;
          neighborY = Y;
        } else {
          neighborX = X;
          neighborY = Y + j;
        }
        if (neighborX >= 0 and n > neighborX and neighborY >= 0 and
            m > neighborY and
            input[neighborX][neighborY] != '0' + cityCounter and
            !isPassed[neighborX][neighborY]) {
          if (input[neighborX][neighborY] >= '1' &&
              input[neighborX][neighborY] <= '3') {
            neighborQueX.push_front(neighborX);
            neighborQueY.push_front(neighborY);
          } else if (input[neighborX][neighborY] == '.') {
            neighborQueX.push_back(neighborX);
            neighborQueY.push_back(neighborY);
          }
        }
      }
    }
    while (neighborQueX.size()) {
      neighborX = neighborQueX.front();
      neighborY = neighborQueY.front();
      neighborQueX.pop_front();
      neighborQueY.pop_front();
      if (isPassed[neighborX][neighborY]) continue;
      if (input[neighborX][neighborY] >= '1' and
          input[neighborX][neighborY] <= '3') {
        height[neighborX][neighborY][cityCounter] = height[X][Y][cityCounter];
        int extX = neighborX, extY = neighborY;
        extraX.push(extX);
        extraY.push(extY);
        isPassed[extX][extY] = true;
        while (extraX.size()) {
          extX = extraX.front();
          extY = extraY.front();
          extraX.pop();
          extraY.pop();
          isReachable[extX][extY][cityCounter] = true;
          int extNX, extNY;
          for (int i = 0; i < 2; ++i) {
            for (int j = -1; j < 2; j += 2) {
              if (i) {
                extNX = extX + j;
                extNY = extY;
              } else {
                extNX = extX;
                extNY = extY + j;
              }
              if (input[extNX][extNY] >= '1' and input[extNX][extNY] <= '3' and
                  !isPassed[extNX][extNY]) {
                isPassed[extNX][extNY] = true;
                height[extNX][extNY][cityCounter] =
                    height[extX][extY][cityCounter];
                extraX.push(extNX);
                cityX[cityCounter].push(extNX);
                extraY.push(extNY);
                cityY[cityCounter].push(extNY);
              }
            }
          }
        }
      }
      cityX[cityCounter].push(neighborX);
      cityY[cityCounter].push(neighborY);
      isPassed[neighborX][neighborY] = true;
      height[neighborX][neighborY][cityCounter] = height[X][Y][cityCounter] + 1;
      if (input[neighborX][neighborY] != '.') {
        height[neighborX][neighborY][cityCounter] = height[X][Y][cityCounter];
      }
    }
  }
  return;
}
int main() {
  cin >> n >> m;
  memset(height, 0, sizeof height);
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < m; ++j) {
      cin >> input[i][j];
      if (input[i][j] != '#' and input[i][j] != '.') {
        cityX[input[i][j] - '0'].push(i);
        cityY[input[i][j] - '0'].push(j);
      }
    }
  }
  BFS(1);
  memset(isPassed, 0, sizeof isPassed);
  BFS(2);
  memset(isPassed, 0, sizeof isPassed);
  BFS(3);
  int answer = MAXN * MAXN, ansX = -1, ansY = -1;
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < m; ++j) {
      int partialAnswer = 0;
      bool possiblity = true;
      for (int k = 1; k < 4; ++k) {
        partialAnswer += height[i][j][k];
        if (!isReachable[i][j][k]) possiblity = false;
      }
      if (input[i][j] == '.') {
        partialAnswer -= 2;
      }
      if (!possiblity) continue;
      if (partialAnswer < answer) {
        answer = partialAnswer;
        ansX = i;
        ansY = j;
      }
    }
  }
  if (ansX < 0 and ansY < 0) {
    cout << -1 << endl;
    return 0;
  }
  if (answer == -3) {
    cout << 0 << endl;
    return 0;
  }
  cout << answer << endl;
  return 0;
}
