#include <bits/stdc++.h>

using namespace std;

template<typename S, typename T>
ostream& operator<<(ostream& out, const pair<S, T> p) {
    out << "(" << p.first << "," << p.second << ")";
    return out;
}

template<typename T>
ostream& operator<<(ostream& out, const vector<T>& v) {
    for (auto a: v)
        out << a << " ";
    return out;
}

template<typename T>
ostream& operator<<(ostream& out, const set<T>& S) {
    for (auto a: S)
        cout << a << " ";
    return out;
}

template<typename T>
ostream& operator<<(ostream& out, const multiset<T>& S) {
    for (auto a: S)
        cout << a << " ";
    return out;
}

template<typename S, typename T>
ostream& operator<<(ostream& out, const map<S, T>& M) {
    for (auto m: M)
        cout << "(" << m.first << "->" << m.second << ") ";
    return out;
}

template<typename S, typename T>
pair<S, T> operator+(pair<S, T> a, pair<S, T> b) {
    return make_pair(a.first + b.first, a.second + b.second);
}

template<typename S, typename T>
pair<S, T> operator-(pair<S, T> a, pair<S, T> b) {
    return make_pair(a.first - b.first, a.second - b.second);
}

template<typename T>
struct GridGraph {
    int n;
    int m;
    vector<vector<T>> W;
    vector<vector<int>> vis;
    vector<vector<int>> dist;
    vector<pair<int,int>> topo_sort;
    vector<pair<int,int>> sa;
    vector<vector<pair<int,int>>> group;
    vector<vector<int>> dp;
    vector<pair<int, int>> movs;
    vector<pair<int, int>> jump;
    vector<pair<int, int>> movs4 = {{0,1},{-1,0},{0,-1},{1,0}};
    vector<pair<int, int>> movs8 = {{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1}};
    vector<pair<int, int>> movs9 = {{-1,2},{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1},{2,1},{1,2}};

    void init(int n, int m) {
        this->n = n;
        this->m = m;
        // FIXME
        movs = movs4;
        jump.clear();
        for (int i = -2; i <= 2; i++) {
            for (int j = -2; j <= 2; j++) {
                jump.emplace_back(i, j);
            }
        }
    }

    void init(vector<vector<T>>& A) {
        int n = A.size();
        int m = A[0].size();
        init(n, m);
        W = A;
    }

    void init(vector<string>& A) {
        int n = A.size();
        int m = A[0].size();
        init(n, m);
        W.resize(n);
        for (int i = 0; i < n; i++) {
            W[i].resize(m);
            for (int j = 0; j < m; j++) {
                W[i][j] = A[i][j];
            }
        }
    }

    bool is_edge_allowed(pair<int,int> s, pair<int,int> t) {
        // FIXME
        // return W[s.first][s.second] + 1 == W[t.first][t.second];
        return true;
    }

    bool is_node_allowed(pair<int,int> s) {
        // FIXME
        T val = W[s.first][s.second];
        return val == '.';
        // return true;
    }

    void dfs(pair<int, int> s) {
        int x = s.first;
        int y = s.second;
        vis[x][y] = 1;
        for (auto mov: movs) {
            auto t = s + mov;
            int nx = t.first;
            int ny = t.second;
            if (nx >= 0 && nx < n && ny >= 0 && ny < m) {
                if (is_node_allowed(t)) {
                    if (is_edge_allowed(s, t)) {
                        if (vis[nx][ny] == 0) {
                            dfs(t);
                        }
                    }
                }
            }
        }
        vis[x][y] = 2;
        sa.push_back(s);
        topo_sort.push_back(s);
    }

    void source_dfs(vector<pair<int,int>>& A) {
        vis.resize(n);
        for (int i = 0; i < n; i++)
            vis[i].assign(m, 0);
        topo_sort.clear();
        group.clear();
        for (auto s: A) {
            int x = s.first;
            int y = s.second;
            if (is_node_allowed(s)) {
                if (vis[x][y] == 0) {
                    sa.clear();
                    dfs(s);
                    reverse(sa.begin(), sa.end());
                    group.push_back(sa);
                }
            }
        }
        reverse(topo_sort.begin(), topo_sort.end());
    }

    void source_dfs(pair<int,int> s) {
        vector<pair<int,int>> A;
        A.push_back(s);
        source_dfs(A);
    }

    void source_dfs() {
        vector<pair<int,int>> A;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                A.emplace_back(i, j);
            }
        }
        source_dfs(A);
    }

    void source_dynamic_porgramming() {
        dp.resize(n);
        for (int i = 0; i < n; i++)
            dp[i].assign(m, 1);
        for (int i = topo_sort.size() - 1; i >= 0; i--) {
            auto s = topo_sort[i];
            int x = s.first;
            int y = s.second;
            for (auto mov: movs) {
                auto t = s + mov;
                int nx = t.first;
                int ny = t.second;
                if (nx >= 0 && nx < n && ny >= 0 && ny < m) {
                    if (is_node_allowed(t)) {
                        if (is_edge_allowed(s, t)) {
                            dp[x][y] = max(dp[x][y], dp[nx][ny] + 1);
                        }
                    }
                }
            }
        }
    }

    void source_bfs(vector<pair<int,int>>& src, pair<int,int> dst = {-1,-1}) {
        vis.resize(n);
        for (int i = 0; i < n; i++)
            vis[i].assign(m, 0);
        dist.resize(n);
        for (int i = 0; i < n; i++)
            dist[i].assign(m, 1e9);
        queue<pair<int,int>> q;
        for (auto s: src) {
            int x = s.first;
            int y = s.second;
            vis[x][y] = 1;
            dist[x][y] = 0;
            q.push(s);
        }
        while (!q.empty()) {
            auto s = q.front();
            q.pop();
            int x = s.first;
            int y = s.second;
            vis[x][y] = 2;
            if (s == dst)
                break;
            for (auto mov: movs) {
                auto t = s + mov;
                int nx = t.first;
                int ny = t.second;
                if (nx >= 0 && nx < n && ny >= 0 && ny < m) {
                    if (is_node_allowed(t)) {
                        if (is_edge_allowed(s, t)) {
                            if (vis[nx][ny] == 0) {
                                vis[nx][ny] = 1;
                                dist[nx][ny] = dist[x][y] + 1;
                                q.push({nx, ny});
                            }
                        }
                    }
                }
            }
        }
    }

    void source_bfs(pair<int,int> src, pair<int,int> dst = {1, -1}) {
        vector<pair<int,int>> A;
        A.push_back(src);
        source_bfs(A, dst);
    }

    void solve(pair<int,int> src, pair<int,int> dst = {1, -1}) {
        vis.resize(n);
        for (int i = 0; i < n; i++)
            vis[i].assign(m, 0);
        dist.resize(n);
        for (int i = 0; i < n; i++)
            dist[i].assign(m, 1e9);
        queue<pair<int,int>> q;
        vector<pair<int,int>> A = {src};
        vector<pair<int,int>> B;
        int cur = 0;
        while (!A.empty()) {
            topo_sort.clear();
            group.clear();
            for (auto s: A) {
                int x = s.first;
                int y = s.second;
                if (is_node_allowed(s)) {
                    if (vis[x][y] == 0) {
                        dfs(s);
                    }
                }
            }
            reverse(topo_sort.begin(), topo_sort.end());
            A = move(topo_sort);
            for (auto [x, y]: A) {
                dist[x][y] = cur;
            }
            cur++;
            B.clear();
            for (auto &s: A) {
                for (auto mov: jump) {
                    auto t = s + mov;
                    auto [x, y] = t;
                    if (x >= 0 && x < n && y >= 0 && y < m) {
                        if (is_node_allowed(t)) {
                            if (is_edge_allowed(s, t)) {
                                if (vis[x][y] == 0) {
                                    // vis[x][y] = 1;
                                    B.push_back({x, y});
                                }
                            }
                        }
                    }

                }
            }
            A = move(B);
        }
    }

    void dump_grid() {
        for (int i = 0; i < n; i++)
            cout << "W[" << i << "]: " << W[i] << endl;
    }
    void dump() {
        for (int i = 0; i < vis.size(); i++)
            cout << "vis[" << i << "]; " << vis[i] << endl;
        for (int i = 0; i < dist.size(); i++)
            cout << "dist[" << i << "]: " << dist[i] << endl;
        for (int i = 0; i < dp.size(); i++)
            cout << "dp[" << i << "]: " << dp[i] << endl;
    }
};

GridGraph<char> graph;

int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr);
    int n, m;
    pair<int,int> s, t;
    cin >> n >> m;
    cin >> s.first >> s.second;
    cin >> t.first >> t.second;
    s.first--, s.second--, t.first--, t.second--;
    vector<string> W(n);
    for (int i = 0; i < n; i++)
        cin >> W[i];
    graph.init(W);
    // graph.dump_grid();
    graph.solve(s, t);
    // graph.dump();
    if (graph.vis[t.first][t.second] == 0)
        cout << -1 << endl;
    else
        cout << graph.dist[t.first][t.second] << endl;
    return 0;
}


Measured memory_bytes: 17364