//#pragma GCC target("avx2")
#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")

#include <bits/stdc++.h>

using namespace std;

#ifdef LOCAL
#include <prettyprint.hpp>
#define debug(...)  cerr << "[" << #__VA_ARGS__ << "]: ", d_err(__VA_ARGS__);
#else
#define debug(...) 83;
#endif

void d_err() {
    cerr << endl;
}

template <typename H, typename... T>
void d_err(H h, T... t) {
    cerr << h << " ";
    d_err(t...);
}

template <typename T>
void print(T x) {
    cout << x << "\n";
}

#define ALL(x) (x).begin(), (x).end()
#define FOR(i, m, n) for (int i = (m); i < (n); ++i)
#define REVFOR(i, m, n) for (int i = (n - 1); i >= (m); --i)
#define REP(i, n) FOR(i, 0, n)
#define REVREP(i, n) REVFOR(i, 0, n)
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define eb emplace_back
#define bcnt __builtin_popcountll

typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef pair<ll,ll> Pll;
typedef pair<int,int> Pin;

ll INF = 1e16;
int inf = 1e9;
ll MOD = 1e9+7;

struct UnionFind {
    vector<int> par;

    UnionFind(int n): par(n, -1) {}
    void init(int n) { par.assign(n, -1); }

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

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

    bool merge(int x, int y) {
        x = root(x); y = root(y);

        if (x == y) return false;

        // merge by size
        // force size of x to be bigger than that of y
        if (par[x] > par[y]) swap(x, y);
        par[x] += par[y];
        par[y] = x;

        return true;
    }

    ll size(int x) {
        return -par[root(x)];
    }
};

struct Dijkstra {
    struct Edge {
        ll to;
        ll c;
    };

    int V;
    vector<vector<Edge>> e;
    vector<ll> d;

    Dijkstra(int V): V(V) {
        e.resize(V);
        d.resize(V);
    }

    void add_edge(int from, int to, ll cost) {
        e[from].pb({to, cost});
    }

    ll query(ll dest) {
        return d[dest];
    }

    void operator()(ll s) {
        priority_queue<Pll, vector<Pll>, greater<>> q;

        REP(i, V) d[i] = INF;
        d[s] = 0;
        q.push({0, s});

        while(!q.empty()) {
            Pll n = q.top(); q.pop();
            ll v = n.se;
            if (d[v] < n.fi) continue;

            REP(i, e[v].size()) {
                Edge cur = e[v][i];
                ll cost = d[v] + cur.c;
                if (d[cur.to] > cost) {
                    d[cur.to] = cost;
                    q.push({cost, cur.to});
                }
            }
        }
    }
};

int main(){
    cin.tie(0);
    ios_base::sync_with_stdio(false);
    cout << fixed << setprecision(20);
    
    int h, w;
    cin >> h >> w;

    int ch, cw, dh, dw;
    cin >> ch >> cw;
    cin >> dh >> dw;
    ch--; cw--;
    dh--; dw--;

    vector<string> S(h);
    REP(i, h) cin >> S[i];

    UnionFind uf(h * w);

    auto invalid = [&] (int x, int y) -> bool {
        if (x < 0 || x >= w || y < 0 || y >= h) return true;
        if (S[y][x] == '#') return true;
        return false;
    };

    vector<int> dx = {0, 1, 0, -1}, dy = {1, 0, -1, 0};
    vector<vector<bool>> used(h, vector<bool>(w, false));
    REP(i, h) REP(j, w) {
        if (S[i][j] == '.') {
            queue<pair<int, int>> q;
            q.emplace(i, j);
            used[i][j] = true;

            while(!q.empty()) {
                auto p = q.front(); q.pop();

                REP(k, 4) {
                    int ny = p.fi + dy[k], nx = p.se + dx[k];
                    if (invalid(nx, ny) || used[ny][nx]) continue;
                    q.emplace(ny, nx);
                    used[ny][nx] = true;
                    uf.merge(i * w + j, ny * w + nx);
                }
            }
        }
    }

    set<int> idx;
    REP(i, h) REP(j, w) {
        if (invalid(j, i)) continue;
        idx.insert(uf.root(i * w + j));
    }

    map<int, int> m;
    int cnt = 0;
    for(auto &e: idx) m[e] = cnt++;

    Dijkstra graph(cnt + 1);

    REP(i, h) REP(j, w) {
        if (invalid(j, i)) continue;
        FOR(ddx, -2, 3) FOR(ddy, -2, 3) {
            int y2 = i + ddy, x2 = j + ddx;
            if (invalid(x2, y2)) continue;
            int n1 = uf.root(i * w + j), n2 = uf.root(y2 * w + x2);
            if (!uf.issame(n1, n2)) {
                graph.add_edge(m[n1], m[n2], 1);
                graph.add_edge(m[n2], m[n1], 1);
            }
        }
    }

    graph(m[uf.root(ch * w + cw)]);

    ll ans = graph.query(m[uf.root(dh * w + dw)]);
    if (ans == INF) ans = -1;
    print(ans);
}


Measured memory_bytes: 101820