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

#pragma region Macros
using ll = long long;
#define int ll
using pii = pair<int, int>;
using tiii = tuple<int, int, int>;
template<class T = ll> using V = vector<T>;
template<class T = ll> using VV = V<V<T>>;
#define IOS\
    ios::sync_with_stdio(false);\
    cin.tie(0);\
    cout.tie(0);
#define FOR(i,l,r) for(ll i=(l);i<(r);++i)
#define REP(i,n) FOR(i,0,n)
#define REPS(i,n) FOR(i,1,n+1)
#define RFOR(i,l,r) for(ll i=(l);i>=(r);--i)
#define RREP(i,n) RFOR(i,n-1,0)
#define RREPS(i,n) RFOR(i,n,1)
#define mp make_pair
#define mt make_tuple
#define pb push_back
#define eb emplace_back
#define all(x) (x).begin(),(x).end()
#define SORT(name) sort(name.begin(), name.end())
#define RSORT(name)\
    SORT(name);\
    reverse(all(name));
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))
inline void Yes(bool b = true) {cout << (b ? "Yes" : "No") << '\n';}
inline void YES(bool b = true) {cout << (b ? "YES" : "NO") << '\n';}
template <class T> inline void print(T x){ cout << x << '\n';}
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; }

const ll LLINF = (1LL<<60);
const int INF = (1LL<<30);
const double DINF = std::numeric_limits<double>::infinity();
#pragma endregion

#if 1
#  define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#  define DBG(fmt, ...)
#endif

class PosId2D {
    public:
        PosId2D() : m_H(0), m_W(0) {}
        PosId2D(ll h, ll w) : m_H(0), m_W(0) { Init(h, w); }
        void Init(ll h, ll w) { m_H = h; m_W = w; }

        // id からそれに対応する (i, j) を返します
        pair<ll, ll> GetPos(ll id) {
            assert(m_H > 0 && m_W > 0);
            return make_pair(id / m_W, id % m_W);
        }
        // i, j からそれに対応する id を返します
        ll GetId(ll i, ll j) {
            return i * m_W + j;
        }
        ll GetId(pair<ll, ll> pos) { return GetId(pos.first, pos.second); }

        // 二次元グリッド上に存在しない特別な id を返します
        // n: 何番目の特別な id か（特別な id が複数作れるように渡す）
        ll GetSpecial(ll n) { return m_H * m_W + n; }

    private:
        ll m_H; // 高さ
        ll m_W; // 幅
};

// 二次元グリッド用のダイクストラ
template <typename T>
class DijkstraGrid {
    private:
        struct Edge {
            int to;   // 有向辺の行先頂点
            T cost;  // 辺の重み
        };
        typedef pair<int, T> P;       // first: 最短距離 second: 頂点 id
    public:
        // コンストラクタ
        // v … 頂点数, inf: …「無限大」とする値
        DijkstraGrid() {}
        DijkstraGrid(int h, int w, T inf) { Init(h, w, inf); }
        void Init(int h, int w, T inf) {
            assert(h > 0 && w > 0);
            m_H = h;
            m_W = w;
            m_V = m_H * m_W;
            m_Inf = inf;
            m_G.assign(m_V, vector<Edge>());
        }
        // 有向辺の追加。負のコストは未対応
        void AddDirEdge(int from_i, int from_j, int to_i, int to_j, T cost) {
            assert(0 <= from_i && from_i < m_H);
            assert(0 <= from_j && from_j < m_W);
            assert(0 <= to_i && to_i < m_H);
            assert(0 <= to_j && to_j < m_W);
            m_G[from_i * m_W + from_j].push_back({to_i * m_W + to_j, cost});
        }
        // 無向辺の追加。負のコストは未対応
        void AddUndirEdge(int from_i, int from_j, int to_i, int to_j, T cost) {
            AddDirEdge(from_i, from_j, to_i, to_j, cost);
            AddDirEdge(to_i, to_j, from_i, from_j, cost);
        }
        // 始点 (i, j) (i が縦) から各マスへの最短経路の導出 O(E log V)
        // Calc を連続で行うことも可能
        void Calc(int i, int j) {
            assert(0 <= i && i < m_H);
            assert(0 <= j && j < m_W);
            int s = i * m_W + j;
            m_Dist.assign(m_V, m_Inf);
            m_PrevP.assign(m_V, -1);
            // 最短距離が短い順で cand を取り出す
            // 頂点 P.second まで P.first のコストで来れたことを情報として入れておく
            priority_queue<P, vector<P>, greater<P> > cand;
            m_Dist[s] = 0;  // 始点のコストは 0
            cand.push(P(0, s));
            while(!cand.empty()) {
                P p = cand.top(); cand.pop();     // cand のトップを取り出す
                T v = p.second;
                // 頂点 v まで最短経路が、 cand から取り出したものより既に小さいなら何もしない
                if(m_Dist[v] < p.first){ continue; }
                // 現在見ている頂点から延びている辺を全て見る
                for(Edge e : m_G[v]) {
                    if(m_Dist[e.to] > m_Dist[v] + e.cost) {
                        // 現在の最短経路より短くなるなら更新
                        m_Dist[e.to] = m_Dist[v] + e.cost;
                        m_PrevP[e.to] = v;
                        cand.push(P(m_Dist[e.to], e.to));
                    }
                }
            }
        }
        // 始点 (i, j) から頂点 t への最短距離を返す O(1)
        // 前処理として Calc(s) が必要
        T GetDist(int i, int j) {
            assert(0 <= i && i < m_H);
            assert(0 <= j && j < m_W);
            return m_Dist[i * m_W + j];
        }
        // 始点から頂点 (i, j) までの経路を vector に入れて返す (始点と終点含む)
        // O(V') … V' は最短経路の頂点数
        // 前処理として Calc() が必要
        vector< pair<int, int> > GetPath(int i, int j) {
            vector< pair<int, int> > path;
            int t = i * m_W + j;
            // t が s になるまで prev_p[t] を辿っていく
            for(; t != -1; t = m_PrevP[t]) { path.push_back(make_pair(t / m_W, t % m_W)); }
            // このままだと t->s の順になっているので逆順にする
            reverse(path.begin(), path.end());
            return path;
        }
    private:
        int m_H;                    // 高さ
        int m_W;                    // 幅
        int m_V;                    // 頂点の数
        T m_Inf;                    // 無限の代わりとして扱う値
        vector< vector<Edge> > m_G; // 頂点 i から延びている辺の vector(隣接リスト)
        vector<T> m_Dist;           // 各頂点への最短コスト。つまり答え
        vector<int> m_PrevP;        // 最短経路の各頂点を保存(経路復元で利用)
};

const int MOD = 1000000007;
const int MAX_N = 100010;

int Ch, Cw, Dh, Dw;
int H, W;
V<string> S;

bool IsAd(int i, int j, int y, int x) {
    if(i - 1 == y && j == x) { return true; }
    if(i + 1 == y && j == x) { return true; }
    if(i == y && j - 1 == x) { return true; }
    if(i == y && j + 1 == x) { return true; }
    return false;
}

signed main() {
    IOS;

    cin >> H >> W;
    cin >> Ch >> Cw;
    cin >> Dh >> Dw;
    Ch--; Cw--; Dh--; Dw--;

    S.resize(H);
    REP(i, H) {
        cin >> S[i];
    }

    DijkstraGrid<int> dk(H, W, LLINF);

    REP(i, H) {
        REP(j, W) {
            if(S[i][j] == '#') { continue; }
            for(int y = i - 2; y <= i + 2; ++y) {
                if(y < 0 || y >= H) { continue; }
                for(int x = j - 2; x <= j + 2; ++x) {
                    if(x < 0 || x >= W) { continue; }
                    if(IsAd(i, j, y, x)) { continue; }
                    if (S[y][x] == '#') {
                        continue;
                    }
                    dk.AddDirEdge(i, j, y, x, 1);
                }
            }
            if(i - 1 >= 0) {
                dk.AddDirEdge(i, j, i - 1, j, 0);
            }
            if(i + 1 < H) {
                dk.AddDirEdge(i, j, i + 1, j, 0);
            }
            if(j - 1 >= 0) {
                dk.AddDirEdge(i, j, i, j - 1, 0);
            }
            if(j + 1 < W) {
                dk.AddDirEdge(i, j, i, j + 1, 0);
            }
        }
    }

    dk.Calc(Ch, Cw);
    int ans = dk.GetDist(Dh, Dw);
    if(ans >= LLINF) {
        print(-1);
        return 0;
    }
    print(ans);

    return 0;
}


Measured memory_bytes: 207180