#include <bits/stdc++.h>

using namespace std;

#define SZ(x) (int)(x.size())
#define REP(i, n) for(int i=0;i<(n);++i)
#define FOR(i, a, b) for(int i=(a);i<(b);++i)
#define RREP(i, n) for(int i=(int)(n);i>=0;--i)
#define RFOR(i, a, b) for(int i=(int)(a);i>=(int)(b);--i)
#define ALL(a) (a).begin(),(a).end()
#define DUMP(x) cerr<<#x<<" = "<<(x)<<endl
#define DEBUG(x) cerr<<#x<<" = "<<(x)<<" (L"<<__LINE__<<")"<< endl;

using ll = long long;
using vi = vector<int>;
using vvi = vector<vi>;
using vll = vector<ll>;
using vvll = vector<vll>;
using P = pair<int, int>;

const double eps = 1e-8;
const ll MOD = 1000000007;
const int INF = INT_MAX / 2;
const ll LINF = LLONG_MAX / 2;

template <typename T1, typename T2>
bool chmax(T1 &a, const T2 &b) {
  if(a < b) {a = b; return true;}
  return false;
}

template <typename T1, typename T2>
bool chmin(T1 &a, const T2 &b) {
  if(a > b) {a = b; return true;}
  return false;
}

template<typename T1, typename T2>
ostream& operator<<(ostream &os, const pair<T1, T2> p) {
  os << p.first << ":" << p.second;
  return os;
}

template<class T>
ostream &operator<<(ostream &os, const vector<T> &v) {
  REP(i, SZ(v)) {
    if(i) os << " ";
    os << v[i];
  }
  return os;
}

struct UnionFind {
  vi par;
  int n;

  UnionFind(int n): n(n) {
    par.resize(n, -1);
  }

  int root(int x) {
    return par[x] < 0 ? x : par[x] = root(par[x]);
  }

  int same(int x, int y) {
    return root(x) == root(y);
  }

  void unite(int x, int y) {
    x = root(x);
    y = root(y);
    if(x == y) return;

    if(par[x] < par[y]) swap(x, y);

    par[y] += par[x];
    par[x] = y;
  }
};

int h, w;
int idx(int i, int j) {
  return i * w + j;
}

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(10);

  cin >> h >> w;
  P st, gl;
  cin >> st.first >> st.second;
  cin >> gl.first >> gl.second;
  st.first--;
  st.second--;
  gl.first--;
  gl.second--;

  vector<vector<bool>> grid(h, vector<bool>(w));
  REP(i, h) {
    string s;cin >> s;
    REP(j, w) {
      grid[i][j] = s[j] == '.';
    }
  }

  UnionFind uf(h*w);

  REP(i, h) {
    FOR(j, 1, w) {
      if(grid[i][j-1] && grid[i][j]) uf.unite(idx(i, j-1), idx(i, j));
    }
  }
  FOR(i, 1, h) {
    REP(j, w) {
      if(grid[i][j] && grid[i-1][j]) uf.unite(idx(i-1, j), idx(i, j));
    }
  }

  vector<set<int>> g(h*w);
  REP(i, h) {
    REP(j, w) {
      FOR(k, -2, 3) {
        FOR(l, -2, 3) {
          int nr = i + k;
          int nc = j + l;
          if(!(0 <= nr && nr < h && 0 <= nc && nc < w)) continue;
          if(!grid[i][j] || !grid[nr][nc]) continue;

          int idx1 = idx(i, j);
          int idx2 = idx(nr, nc);
          if(uf.same(idx1, idx2)) continue;
          idx1 = uf.root(idx1);
          idx2 = uf.root(idx2);
          g[idx1].insert(idx2);
          g[idx2].insert(idx1);
        }
      }
    }
  }

  int start = uf.root(idx(st.first, st.second));
  int goal = uf.root(idx(gl.first, gl.second));

  vi d(h*w,  INF);
  priority_queue<P, vector<P>, greater<P>> pq;
  d[start] = 0;
  pq.push({0, start});
  while(!pq.empty()) {
    auto tmp = pq.top(); pq.pop();
    int dist = tmp.first;
    int now = tmp.second;
    if(dist > d[now]) continue;
    for(auto &e: g[now]) {
      if(d[e] > dist + 1) {
        d[e] = dist + 1;
        pq.push({dist + 1, e});
      }
    }
  }

  cout << (d[goal] == INF ? -1 : d[goal]) << endl;

}








Measured memory_bytes: 76572