#pragma GCC optimize("Ofast")
#define _USE_MATH_DEFINES
#include "bits/stdc++.h"

using namespace std;

using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
using i8 = int8_t;
using i16 = int16_t;
using i32 = int32_t;
using i64 = int64_t;

constexpr char newl = '\n';
constexpr double eps = 1e-10;

#define FOR(i,a,b) for (int i = (a); i < (b); i++)
#define F0R(i,b) FOR(i,0,b)
#define RFO(i,a,b) for (int i = ((b)-1); i >=(a); i--)
#define RF0(i,b) RFO(i,0,b)
#define fi first
#define se second
#define debug(x) cout << #x << ": " << x << '\n';
#define rng(a) a.begin(),a.end()
#define rrng(a) a.rbegin(),a.rend()

template<typename T1, typename T2> inline void chmin(T1& a, T2 b) { if (a > b) a = b; }
template<typename T1, typename T2> inline void chmax(T1& a, T2 b) { if (a < b) a = b; }
template<class T> void Print(vector<T> v) {
  F0R(i, v.size()) {
    cout << v[i] << ' ';
  }
  cout << newl;
}

#if 1

class UnionFind {
public:
  UnionFind(int size) : size(size) {

    par = vector<int>(size, -1);
  }

  int GetRoot(int v) {
    int root = v;
    while (par[root] >= 0) {
      root = par[root];
    }
    if (root != v) {
      par[v] = root;
    }
    return root;
  }

  bool IsUnion(int a, int b) {
    int ra = GetRoot(a), rb = GetRoot(b);

    return ra == rb && ra >= 0;
  }

  int GetUnionSize(int a) {
    return -par[GetRoot(a)];
  }

  void Unite(int a, int b) {
    int ra = GetRoot(a), rb = GetRoot(b);

    if (ra == rb) return;

    if (GetUnionSize(ra) > GetUnionSize(rb)) {
      par[ra] += par[rb];
      par[rb] = ra;
    }
    else {
      par[rb] += par[ra];
      par[ra] = rb;
    }
  }

protected:

  // 親がいれば、親のindexを入れる
  // 親がいなければ、グループのサイズを負にして入れておく（一人なら-1）
  vector<int> par;

  int size;
};

// INSERT ABOVE HERE
signed main() {
  cin.tie(0);
  ios_base::sync_with_stdio(false);

  int H, W, sr, sc, er, ec;
  cin >> H >> W >> sr >> sc >> er >> ec;
  sr--; sc--; er--; ec--;
  vector<string> ss(H);
  F0R(i, H) {
    cin >> ss[i];
  }

  auto rci = [&W](int r, int c) {
    return r * W + c;
  };

  UnionFind uf(H* W);
  F0R(r, H) {
    F0R(c, W) {
      if (ss[r][c] == '#') continue;
      if (r) {
        if (ss[r - 1][c] == '.') uf.Unite(rci(r,c), rci(r - 1, c));
      }
      if (c) {
        if (ss[r][c - 1] == '.') uf.Unite(rci(r, c), rci(r, c - 1));
      }
    }
  }

  // Union -> depth
  unordered_map<int, int> ud;
  ud[uf.GetRoot(rci(sr, sc))] = 0;

  array<pair<int, int>, 20> as = {
    pair<int,int>{-2, -2}, pair<int,int>{-2, -1}, pair<int,int>{-2, 0}, pair<int,int>{-2, 1}, pair<int,int>{-2, 2},
  pair<int,int>{-1, -2}, pair<int,int>{-1, -1}, pair<int,int>{-1, 1}, pair<int,int>{-1, 2},
  pair<int,int>{0, -2}, pair<int,int>{0, 2},
  pair<int,int>{1, -2}, pair<int,int>{1, -1}, pair<int,int>{1, 1}, pair<int,int>{1, 2},
    pair<int,int>{2, -2}, pair<int,int>{2, -1}, pair<int,int>{2, 0}, pair<int,int>{2, 1}, pair<int,int>{2, 2},
  };

  queue<tuple<int, int, int>> qu1;
  qu1.emplace(sr, sc, 0);
  vector<vector<int>> ts(H, vector<int>(W, -1));
  while (qu1.size()) {
    auto [r,c,depth] = qu1.front();
    qu1.pop();
    if (ss[r][c] == '#') continue;
    int cu = uf.GetRoot(rci(r, c));
    
    queue<tuple<int, int>> qu2;
    qu2.emplace(r, c);
    while (qu2.size()) {
      auto [r, c] = qu2.front();
      qu2.pop();
      if (ts[r][c] >= 0) continue;
      ts[r][c] = depth;
      bool up = false, le = false, ri = false, dw = false;
      if (r > 0) {
        if (ss[r - 1][c] == '#') {
          up = true;
        }
        else {
          qu2.emplace(r - 1, c);
        }
      }
      if (c > 0) {
        if (ss[r][c - 1] == '#') {
          le = true;
        }
        else {
          qu2.emplace(r, c - 1);
        }
      }
      if (r < H - 1) {
        if (ss[r + 1][c] == '#') {
          dw = true;
        }
        else {
          qu2.emplace(r + 1, c);
        }
      }
      if (c < W - 1) {
        if (ss[r][c + 1] == '#') {
          ri = true;
        }
        else {
          qu2.emplace(r, c + 1);
        }
      }
      if (up||le||ri||dw) {
        for (auto& p : as) {
          if (r + p.first >= 0 && r + p.first < H && c + p.second >= 0 && c + p.second < W) {
            if (ss[r + p.first][c + p.second] == '.') {
              int nu = uf.GetRoot(rci(r + p.first, c + p.second));
              if (ud.find(nu) == ud.end()) {
                ud[nu] = depth + 1;
                qu1.emplace(r + p.first, c + p.second, depth + 1);
              }
            }
          }
        }
      }
    }
  }

  int result = ud.find(uf.GetRoot(rci(er, ec))) == ud.end() ? -1 : ud[uf.GetRoot(rci(er, ec))];
  cout << result;
}
#endif


Measured memory_bytes: 19224