#include <bits/stdc++.h>
using namespace std;
using ll = int64_t;
using ull = uint64_t;
const ll INF = 9e18;

void print() { cout << endl; }
template <typename Head, typename... Tail>
void print(Head head, Tail... tail) {
    int size = sizeof...(Tail);
    cout << head;
    if (size > 0) {
        cout << " ";
    }
    print(tail...);
}

void print0() {}
template <typename Head, typename... Tail>
void print0(Head head, Tail... tail) {
    cout << head;
    print0(tail...);
}

struct point {
    ll h;
    ll w;
};
bool operator<(const point& l, const point& r) {
    if (l.w == r.w) {
        return l.h < r.h;
    }
    return l.w < r.w;
}
bool operator==(const point& l, const point& r) {
    return (l.w == r.w && l.h == r.h);
}
bool operator>(const point& l, const point& r) {
    return !(l == r) && !(l < r);
}
bool operator!=(const point& l, const point& r) {
    return !(l == r);
}
bool operator>=(const point& l, const point& r) {
    return (l == r) || (l > r);
}
bool operator<=(const point& l, const point& r) {
    return (l == r) || (l < r);
}

struct edge {
    ll u;
    ll v;
    ll cost;
};
bool operator<=(const edge& lhs, const edge& rhs) {
    return lhs.cost <= rhs.cost;
}
bool operator<(const edge& lhs, const edge& rhs) {
    return lhs.cost < rhs.cost;
}
bool operator>=(const edge& lhs, const edge& rhs) {
    return lhs.cost >= rhs.cost;
}
bool operator>(const edge& lhs, const edge& rhs) {
    return lhs.cost > rhs.cost;
}
bool operator==(const edge& lhs, const edge& rhs) {
    return lhs.cost == rhs.cost;
}
bool operator!=(const edge& lhs, const edge& rhs) {
    return lhs.cost != rhs.cost;
}

// ダイクストラ
void dijkstra(ll n, ll start, vector<vector<edge>>& edgemap, vector<ll>& min_cost) {
    vector<bool> done(n + 1);
    for (ll j = 0; j <= n; j++) {
        min_cost[j] = -1;
        done[j] = false;
    }
    priority_queue<edge, vector<edge>, greater<edge>> pq;

    pq.push(edge{u : -1, v : start, cost : 0});
    while (!pq.empty()) {
        edge e = pq.top();
        pq.pop();
        if (done[e.v]) {
            continue;
        }
        done[e.v] = true;
        min_cost[e.v] = e.cost;
        for (auto next_e : edgemap[e.v]) {
            if (!done[next_e.v]) {
                edge total_next_e = next_e;
                total_next_e.cost = min_cost[next_e.u] + next_e.cost;
                pq.push(total_next_e);
            }
        }
    }
}

int main() {
    ll H, W;
    cin >> H >> W;
    point start, goal;
    cin >> start.h >> start.w;
    cin >> goal.h >> goal.w;
    start.h--;
    start.w--;
    goal.h--;
    goal.w--;
    set<point> roads;  // 道の一覧
    vector<vector<ll>> maz(H, vector<ll>(W));
    for (ll h = 0; h < H; h++) {
        for (ll w = 0; w < W; w++) {
            char c;
            cin >> c;
            while (c != '.' && c != '#') {
                cin >> c;
            }
            if (c == '.') {
                maz[h][w] = 1;
                roads.insert(point{h, w});
            } else {
                maz[h][w] = 0;
            }
        }
    }

    // dfs. 道にIDを割り振る
    ll union_id = 0;
    vector<vector<ll>> union_map(H, vector<ll>(W, -1));
    while (!roads.empty()) {
        stack<point> search;
        search.push(*roads.begin());
        while (!search.empty()) {
            point p = search.top();
            search.pop();
            roads.erase(p);
            union_map[p.h][p.w] = union_id;

            point top = {p.h - 1, p.w};
            if (roads.count(top) > 0) {
                search.push(top);
            }
            point right = {p.h, p.w + 1};
            if (roads.count(right) > 0) {
                search.push(right);
            }
            point bottom = {p.h + 1, p.w};
            if (roads.count(bottom) > 0) {
                search.push(bottom);
            }
            point left = {p.h, p.w - 1};
            if (roads.count(left) > 0) {
                search.push(left);
            }
        }
        union_id++;
    }

    // 異なるIDのunion間の隣接
    vector<vector<edge>> edge_map(union_id + 1);
    set<pair<ll, ll>> edgdone;
    for (ll h = 0; h < H; h++) {
        for (ll w = 0; w < W; w++) {
            // 25倍。ちょっと重い。 (10^6*25)
            ll u = union_map[h][w];
            if (u < 0) {
                continue;
            }
            for (ll y = h - 2; y <= h + 2; y++) {
                for (ll x = w - 2; x <= w + 2; x++) {
                    if (y >= 0 && y < H && x >= 0 && x < W && union_map[y][x] >= 0 && union_map[y][x] != u) {
                        ll v = union_map[y][x];
                        edge eu = edge{u : u, v : v, cost : 1};
                        edge ev = edge{u : v, v : u, cost : 1};
                        if (edgdone.count(make_pair(u, v)) <= 0) {
                            edge_map[u].push_back(eu);
                            edge_map[v].push_back(ev);
                            edgdone.insert(make_pair(u, v));
                            edgdone.insert(make_pair(v, u));
                        }
                    }
                }
            }
        }
    }
    // print("-----");
    // for (ll h = 0; h < H; h++) {
    //     for (ll w = 0; w < W; w++) {
    //         print0(union_map[h][w], " ");
    //     }
    //     print();
    // }
    // ダイクストラ
    vector<ll> min_cost(union_id + 1, INF);
    dijkstra(union_id, union_map[start.h][start.w], edge_map, min_cost);
    ll result = min_cost[union_map[goal.h][goal.w]];
    if (result == INF) {
        print(-1);
    } else {
        print(result);
    }
}


Measured memory_bytes: 60720