#pragma GCC optimize("Ofast")
//#pragma GCC target("avx,avx2,fma")
#include <bits/stdc++.h>
#define all(x) std::begin(x), std::end(x)
#define isz(x) (int)std::size(x)
const auto io_sync_off = [](){
    std::ios_base::sync_with_stdio(0); std::cin.tie(0);
    std::cout << std::fixed << std::setprecision(9);
    return 0;
}();
// Debug defines:
#define watch(x) std::cerr << std::setw(12) << #x << " = " << std::setw(12) << x
#define watchln(x) watch(x) << std::endl
#define watchsp(x) watch(x) << " "
#define cerr cerr && debug && std::cerr
// Defines:
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using vi = std::vector<int>;
using vl = std::vector<ll>;
using vs = std::vector<std::string>;
using vvi = std::vector<vi>;
using vvl = std::vector<vl>;
using vb = std::vector<bool>;
using vvb = std::vector<vb>;
using pii = std::pair<int,int>;
using pil = std::pair<int,ll>;
using pli = std::pair<ll,int>;
using pll = std::pair<ll,ll>;
using vpii = std::vector<pii>;
using vvpii = std::vector<vpii>;
// Comparators:
template<typename A, typename B> bool operator >(const A& a, const B& b) { return b < a; }
template<typename A, typename B> bool operator<=(const A& a, const B& b) { return !(a > b); }
template<typename A, typename B> bool operator>=(const A& a, const B& b) { return !(a < b); }
template<typename A, typename B> bool operator!=(const A& a, const B& b) { return a < b || b < a; }
template<typename A, typename B> bool operator==(const A& a, const B& b) { return !(a != b); }
namespace std {
#if __cplusplus < 201703L
    // Containers:
    template <typename T> constexpr auto size(const T& t) -> decltype(t.size()) { return t.size(); }
#endif
    // 2D arrays:
    template<typename T, int N, int M> auto size(const T (&)[N][M]) { return N * M; }
    template<typename T, int N, int M> auto begin(T (&a)[N][M]) { return &a[0][0]; }
    template<typename T, int N, int M> auto end(T (&a)[N][M]) { return &a[0][0] + N * M; }
    // 3D arrays:
    template<typename T, int N, int M, int K> auto size(const T (&)[N][M][K]) { return N * M * K; }
    template<typename T, int N, int M, int K> auto begin(T (&a)[N][M][K]) { return &a[0][0][0]; }
    template<typename T, int N, int M, int K> auto end(T (&a)[N][M][K]) { return &a[0][0][0] + N * M * K; }
    // Algorithms:
    template<typename C> void reuniq(C& c) { c.erase(unique(all(c)), end(c)); }
    template<typename C, typename X> int lowpos(const C& c, X x) {
        return int(lower_bound(all(c), x) - begin(c));
    }
    template<typename C, typename X> int uppos(const C& c, X x) {
        return int(upper_bound(all(c), x) - begin(c));
    }
    template<typename X, typename Y> X& remin(X& x, const Y& y) { return x = (y < x) ? y : x; }
    template<typename X, typename Y> X& remax(X& x, const Y& y) { return x = (x < y) ? y : x; }
}
// Rand:
namespace Rand {
    const auto seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
    std::mt19937 gen(seed ^ ull(std::make_unique<char>().get()));
}
// Input:
template<typename T> std::istream& operator>>(std::istream& is, std::vector<T>& vec) {
    for (auto &it : vec) is >> it;
    return is;
}
// Output:
template<typename A, typename B> std::ostream& operator<<(std::ostream& os, const std::pair<A,B>& pt) {
    return os << "{" << pt.first << ", " << pt.second << "}";
}
template<typename Iterator>
std::ostream& print_range(std::ostream& os, Iterator begin, Iterator end) {
    os << "{";
    for (auto it = begin; it != end; it++) {
        if (it != begin) { os << ", "; }
        os << *it;
    }
    return os << "}";
}
template<typename T> std::ostream& operator<<(std::ostream& os, const std::vector<T>& vec) {
    return print_range(os, vec.begin(), vec.end());
}
template<typename T> std::ostream& operator<<(std::ostream& os, const std::set<T>& set) {
    return print_range(os, set.begin(), set.end());
}
// Operators << and >> for containers:
template<typename T> std::queue<T>& operator<<(std::queue<T>& q, const T& x) { return q.push(x), q; }
template<typename T> std::queue<T>& operator--(std::queue<T>& q, int) { return q.pop(), q; }
template<typename T> std::queue<T>& operator>>(std::queue<T>& q, T& x) {  return x = q.front(), q--; }

template<typename T> std::vector<T>& operator<<(std::vector<T>& v, const T& x) { return v.push_back(x), v; }
template<typename T> std::vector<T>& operator--(std::vector<T>& v, int) { return v.pop_back(), v; }
template<typename T> std::vector<T>& operator>>(std::vector<T>& v, T& x) { return x = v.back(), v--; }

template<typename T> std::vector<T>& operator<<(std::vector<T>& a, const std::vector<T>& b) {
    return a.insert(a.end(), all(b)), a;
}

template<typename T>
std::list<T>& operator<<(std::list<T>& a, const std::list<T>& b) {
    return a.insert(a.end(), b.begin(), b.end()), a;
}

template<typename T>
std::list<T>& operator>>(const std::list<T>& a, std::list<T>& b) {
    return b.insert(b.begin(), a.begin(), a.end()), b;
}

// Variables:
const int debug = 0;
// -----------------------------------------------------------------------------
int main() {
    int n,m;
    while (std::cin >> n >> m) {
        const int INF = (int)1e9+7;
        vvi dist(1+n+1,vi(1+m+1,INF));
        std::deque<int> q;
        int sr,fr,sc,fc;
        std::cin >> sr >> sc >> fr >> fc;
        dist[sr][sc] = 0;
        q.push_back(sr * 1024 + sc);
        vvb empty(1+n+1,vb(1+m+1,0));
        for (int i = 1; i <= n; i++) {
            std::string input; std::cin >> input;
            for (int j = 1; j <= m; j++) {
                empty[i][j] = input[j-1] == '.';
            }
        }
        vvb visited(1+n+1,vb(1+m+1,false));
        while (isz(q)) {
            auto mask = q.front(); q.pop_front();
            int row = mask / 1024;
            int col = mask % 1024;
            if (visited[row][col]) continue;
            visited[row][col] = 1;
            watchln(row);
            watchln(col);
            watchln(dist[row][col]);
            for (int dr = -1; dr <= 1; dr++) {
                for (int dc = -1; dc <= 1; dc++) {
                    if (dr * dr + dc * dc != 1) continue;
                    int nr = row + dr;
                    int nc = col + dc;
                    if (!empty[nr][nc] || visited[nr][nc]) continue;
                    std::remin(dist[nr][nc], dist[row][col]);
                    q.push_front(nr * 1024 + nc);
                }
            }
            for (int dr = -2; dr <= 2; dr++) {
                for (int dc = -2; dc <= 2; dc++) {
                    int nr = row + dr;
                    int nc = col + dc;
                    if (nr < 0 || nr > n || nc < 0 || nc > m) continue;
                    if (!empty[nr][nc] || visited[nr][nc] || dist[nr][nc] <= dist[row][col] + 1) continue;
                    std::remin(dist[nr][nc],dist[row][col] + 1);
                    q.push_back(nr * 1024 + nc);
                }
            }
        }
        if (dist[fr][fc] == INF) std::cout << "-1\n";
        else std::cout << dist[fr][fc] << "\n";
    }
    
    return 0;
}

Measured memory_bytes: 8008