#include<bits/stdc++.h>
using namespace std;

#define rep(i,n) for(int i = 0; i < n; i++)
#define Rep(i,n) for(int i = 1; i <= n; i++)
#define sz(x) int(x.size())
#define all(v) v.begin(), v.end()
#define rall(v) v.rbegin(), v.rend()
#define YesorNo(a) printf(a ? "Yes\n" : "No\n")
#define endl '\n'
#define fi first
#define se second
using ll = long long;
using P = pair<int,int>;
using Pl = pair<ll,ll>;
template<class T> using V = vector<T>;
const int dx[] = {0,1,0,-1,1,1,-1,-1};
const int dy[] = {1,0,-1,0,1,-1,-1,1};
const int inf = (1<<30)-1;
const ll infll = (1LL<<62)-1;
ll ceil(const ll &a, const ll &b){return ((a)+(b)-1)/b;}
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return true; } return false; }
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return true; } return false; }


void Dijkstra(int s, const vector<vector<P>> &g, vector<int> &dis) {
  priority_queue<P, vector<P>, greater<P>> que; // pair = (cost, v);
  dis[s] = 0;
  que.emplace(0,s);
  while(!que.empty()) {
    P p = que.top(); que.pop();
    int now = p.second;
    if(dis[now] < p.first) continue;
    for(P np : g[now]) {
      int next = np.second;
      if(dis[next] > dis[now] + np.first) {
        dis[next] = dis[now] + np.first;
        que.emplace(dis[next], next);
      }
    }
  }
}


struct UnionFind { // UnionFindTree
  vector<int> d;
  UnionFind(int n): d(n,-1) {}
  int find(int x) {
    if(d[x] < 0) return x;
    return d[x] = find(d[x]);
  }
  bool unite(int x, int y) {
    x = find(x);
    y = find(y);
    if(x == y) return false;
    if(-d[x] < -d[y]) swap(x,y);
    d[x] += d[y];
    d[y] = x;
    return true;
  }
  bool same(int x, int y) { return find(x) == find(y); }
  int size(int x) { return -d[find(x)]; }
};



int main(){
    
    int h, w;
    cin >> h >> w;
    int sh, sw, gh, gw;
    cin >> sh >> sw >> gh >> gw;
    sh--; sw--; gh--; gw--;
    V<string> s(h);
    rep(i,h) cin >> s[i];

    auto makeId = [&](int y, int x) { return y*w+x; };

    UnionFind uf(h*w);
    rep(i,h)rep(j,w) {
        if(s[i][j] == '#') continue;
        rep(d,4) {
            int ny = i + dy[d];
            int nx = j + dx[d];
            if(ny < 0 || ny >= h || nx < 0 || nx >= w) continue;
            if(s[ny][nx] == '#') continue;
            uf.unite(makeId(i,j), makeId(ny,nx));
        }
    }

    map<int, int> mp;
    int cnt = 0;
    rep(i,h)rep(j,w) {
        if(s[i][j] == '#') continue;
        int id = makeId(i,j);
        if(mp.find(uf.find(id)) == mp.end()) {
            mp[uf.find(id)] = cnt++;
        }
    }

    V<V<P>> g(cnt);
    V<set<int>> seen(cnt);
    rep(i,h)rep(j,w) {
        if(s[i][j] == '#') continue;
        for(int x = -2; x <= 2; ++x)for(int y = -2; y <= 2; ++y) {
            int nx = x + j;
            int ny = y + i;
            if(ny < 0 || ny >= h || nx < 0 || nx >= w) continue;
            if(s[ny][nx] == '#') continue;
            if(uf.find(makeId(i,j)) == uf.find(makeId(ny,nx))) continue;
            if(seen[mp[uf.find(makeId(i,j))]].find(mp[uf.find(makeId(ny,nx))]) != seen[mp[uf.find(makeId(i,j))]].end()) continue;
            seen[mp[uf.find(makeId(i,j))]].insert(mp[uf.find(makeId(ny,nx))]);
            g[mp[uf.find(makeId(i,j))]].emplace_back(1, mp[uf.find(makeId(ny,nx))]);
        }
    }

    // rep(i,cnt) {
    //     rep(j,sz(g[i])) {
    //         printf(" [%d : %d] ", g[i][j].fi, g[i][j].se);
    //     }
    //     cout << endl;
    // }

    // rep(i,h)rep(j,w) {
    //     int ans = 0;
    //     if(s[i][j] == '#') ans = -1;
    //     else ans = mp[uf.find(makeId(i,j))];
    //     cout << ans << (j==w-1 ? '\n' : ' ');
    // }

    V<int> dist(cnt,inf);
    int start = mp[uf.find(makeId(sh,sw))];
    Dijkstra(start,g,dist);
    int ans = dist[mp[uf.find(makeId(gh,gw))]];
    if(ans == inf) ans = -1;
    cout << ans << endl;
}

Measured memory_bytes: 50068