#define errOut(s) \
  { std::cerr << __LINE__ << ":" << #s << ":" << (s) << std::endl; }

#include <bits/stdc++.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Weverything"
//#include <boost/multi_array.hpp>
//#include <boost/optional.hpp>
//#include <boost/range/adaptors.hpp>
//#include <boost/range/algorithm.hpp>
//#include <boost/range/irange.hpp>
#pragma clang diagnostic pop

using namespace std;

static int h, w;
static constexpr int wallIdx = 1000000;
static constexpr int hMax = 1000;
static constexpr int wMax = 1000;

struct point_t {
  int x, y;
  int unionFindIdx() const { return y * wMax + x; }
};
static point_t start;
static point_t goal;
struct maze_t {
  bool walls[wMax][hMax];
};
static maze_t maze;

struct union_find_t {
  vector<int> par;  // par[i]:iの親の番号　(例) par[3] = 2 : 3の親が2

  explicit union_find_t(int N) : par(N) {  //最初は全てが根であるとして初期化
    for (int i = 0; i < N; i++) {
      par[i] = i;
    }
  }

  int root(int x) {  // データxが属する木の根を再帰で得る：root(x) = {xの木の根}
    if (par[x] == x) {
      return x;
    }
    return par[x] = root(par[x]);
  }

  void unite(int x, int y) {  // xとyの木を併合
    int rx = root(x);         // xの根をrx
    int ry = root(y);         // yの根をry
    if (rx == ry) {
      return;  // xとyの根が同じ(=同じ木にある)時はそのまま
    }
    par[rx] =
        ry;  // xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける
  }

  bool same(int x, int y) {  // 2つのデータx, yが属する木が同じならtrueを返す
    int rx = root(x);
    int ry = root(y);
    return rx == ry;
  }
};

int64_t solve() {
  union_find_t unionFind(wallIdx + 1);
  for (int y = 0; y < h; y++) {
    for (int x = 0; x < w; x++) {
      point_t const p{x, y};
      auto const idx = p.unionFindIdx();
      if (maze.walls[x][y]) {
        unionFind.unite(wallIdx, idx);
        continue;
      }
      if (x > 0 && !maze.walls[x - 1][y]) {
        unionFind.unite(idx, idx - 1);
      }
      if (y > 0 && !maze.walls[x][y - 1]) {
        point_t const u{x, y - 1};
        unionFind.unite(idx, u.unionFindIdx());
      }
    }
  }
  auto const startIdx = start.unionFindIdx();
  auto const goalIdx = goal.unionFindIdx();
  auto const startRoot = unionFind.root(startIdx);
  auto const goalRoot = unionFind.root(goalIdx);
  if (startRoot == goalRoot) {
    return 0;
  }
  std::unordered_map<int, std::unordered_set<int>> warps;
  std::unordered_set<int> rootSet;
  for (int y = 0; y < h; y++) {
    for (int x = 0; x < w; x++) {
      if (maze.walls[x][y]) {
        continue;
      }
      point_t const p{x, y};
      auto const r = unionFind.root(p.unionFindIdx());
      rootSet.insert(r);
      for (int yy = y; yy < h && yy <= y + 2; yy++) {
        for (int xx = std::max(x - 2, 0); xx < w && xx <= x + 2; xx++) {
          if (xx == x && yy == y) {
            continue;
          }
          if (maze.walls[xx][yy]) {
            continue;
          }
          point_t const pp{xx, yy};
          auto const rr = unionFind.root(pp.unionFindIdx());
          if (rr == r) {
            continue;
          }
          warps[r].insert(rr);
          warps[rr].insert(r);
        }
      }
    }
  }

  //  for (int y = 0; y < h; y++) {
  //    for (int x = 0; x < w; x++) {
  //      point_t const p{x, y};
  //      auto const r = unionFind.root(p.unionFindIdx());
  //      std::cerr << r << " ";
  //    }
  //    std::cerr << std::endl;
  //  }
  //
  std::unordered_map<int, int> rootMap;
  std::vector<int> roots(rootSet.size());
  roots[0] = startRoot;
  rootMap[startRoot] = 0;
  roots[roots.size() - 1] = goalRoot;
  rootMap[goalRoot] = roots.size() - 1;
  int i = 1;
  for (auto r : rootSet) {
    if (r == startRoot || r == goalRoot) {
      continue;
    }
    roots[i] = r;
    rootMap[r] = i;
    i++;
  }
  //  for (auto r : roots) {
  //    errOut(r);
  //  }

  std::vector<int> dist(roots.size(), -1);
  std::queue<int> que;

  dist[0] = 0;
  que.push(0);

  // BFS
  while (!que.empty()) {
    int const rootIdx = que.front();
    //    errOut(rootIdx);
    //    errOut(roots[rootIdx]);

    que.pop();
    for (int r : warps[roots[rootIdx]]) {
      //      errOut(r);
      int const rIdx = rootMap[r];
      if (dist[rIdx] != -1) {
        continue;
      }
      dist[rIdx] = dist[rootIdx] + 1;
      if (rIdx == roots.size() - 1) {
        return dist[rIdx];
      }
      que.push(rIdx);
    }
  }
  return -1;
}

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

  std::cin >> h >> w;
  std::cin >> start.y >> start.x;
  start.x--;
  start.y--;
  std::cin >> goal.y >> goal.x;
  goal.x--;
  goal.y--;
  for (int y = 0; y < h; y++) {
    for (int x = 0; x < w; x++) {
      char ch;
      std::cin >> ch;
      maze.walls[x][y] = ch == '#';
    }
  }

  std::cout << solve() << std::endl;
  return 0;
}


Measured memory_bytes: 54512