#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <climits>
#include <cmath>
#include <cstdint>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <valarray>
#include <vector>

#if __has_include(<string_view>)
#include <string_view>
#endif
#if __has_include(<optional>)
#include <optional>

#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

template <class T>
constexpr const T& max(const T& a, const std::optional<T>& b)
{
    return b ? max(a, *b) : a;
}

template <class T>
constexpr const T& max(const std::optional<T>& a, const T& b)
{
    return a ? max(*a, b) : b;
}

template <class T>
constexpr const std::optional<T>& max(const std::optional<T>& a, const std::optional<T>& b)
{
    if (a && b)
        return *a > *b ? a : b;
    else if (a)
        return a;
    else
        return b;
}

template <class T>
constexpr const T& min(const T& a, const std::optional<T>& b)
{
    return b ? min(a, *b) : a;
}

template <class T>
constexpr const T& min(const std::optional<T>& a, const T& b)
{
    return a ? min(*a, b) : b;
}

template <class T>
constexpr const std::optional<T>& min(const std::optional<T>& a, const std::optional<T>& b)
{
    if (a && b)
        return *a < *b ? a : b;
    else if (a)
        return a;
    else
        return b;
}

#endif
#if __has_include(<any>)
#include <any>
#endif

template <class T, class U>
istream& operator>>(istream& is, pair<T, U>& pair)
{
    is >> pair.first >> pair.second;
    return is;
}

template <class T>
istream& operator>>(istream& is, vector<T>& collection)
{
    for (auto& item : collection)
        is >> item;
    return is;
}

template <class T>
istream& operator>>(istream& is, valarray<T>& collection)
{
    for (auto& item : collection)
        is >> item;
    return is;
}

template <class T>
T peak_and_pop(std::queue<T>& q)
{
    assert(!q.empty());
    T t = move(q.front());
    q.pop();
    return t;
}

template <class T>
T peak_and_pop(std::priority_queue<T>& q)
{
    assert(!q.empty());
    T t = move(q.top());
    q.pop();
    return t;
}

template <class T>
T peak_and_pop(std::stack<T>& q)
{
    assert(!q.empty());
    T t = move(q.top());
    q.pop();
    return t;
}

struct point_t {
    point_t():x(0),y(0){}
    point_t(int x, int y):x(x),y(y){}
    int x,y;
};

void solution()
{
    int h,w;
    point_t cp,dp;
    cin >> h >> w >> cp.y >> cp.x >> dp.y >> dp.x;
    cp.x -= 1;
    cp.y -= 1;
    dp.x -= 1;
    dp.y -= 1;
    vector<vector<char>> maze(h, vector<char>(w));
    for(auto& row : maze){
        for(auto& c : row){
            cin >> c;
        }
    }
    vector<uint32_t> distance(h*w, numeric_limits<uint32_t>::max());
    auto index_of = [&](int x, int y) -> uint32_t { return y*w + x; };
    auto distance_of = [&](int x, int y) -> uint32_t& { return distance[index_of(x, y)]; };

    distance_of(cp.x, cp.y) = 0;

    auto get_cell = [&](int x, int y){
        return (0 <= x && x < w && 0 <= y && y < h) ? maze[y][x] : '#';
    };

    auto get_cell_of = [&](int index){
        return get_cell(index % w, index / w);
    };

    deque<int> cell_to_visit;
    cell_to_visit.push_front(index_of(cp.x, cp.y));

    auto try_update = [&](int x, int y, uint32_t d){
        const char cell = get_cell(x, y);
        if(cell == '.'){
            uint32_t& dnext = distance_of(x, y);
            if(dnext > d){
                dnext = d;
                return true;
            }
        }
        return false;
    };

    while(!cell_to_visit.empty()) {
        const int index = cell_to_visit.front();
        cell_to_visit.pop_front();
        const int x = index % w;
        const int y = index / w;
        const uint32_t d = distance_of(x, y);
        constexpr int dx[] = {1, 0, -1, 0};
        constexpr int dy[] = {0, 1, 0, -1};
        for(int i = 0; i < 4; ++i){
            if(try_update(x + dx[i], y + dy[i], d)){
                cell_to_visit.push_front(index_of(x + dx[i], y + dy[i]));
            }
        }
        for(int dx = -2; dx <= 2; ++dx){
            for(int dy = -2; dy <= 2; ++dy){
                if(try_update(x + dx, y + dy, d + 1)){
                    cell_to_visit.push_back(index_of(x + dx, y + dy));
                }
            }
        }
    }
/*
    for(int y = 0; y < h; ++y){
        for(int x = 0; x < w; ++x){
            cerr << (int32_t)distance_of(x, y) << ',';
        }
        cerr << '\n';
    }
*/
    cout << (int32_t)distance_of(dp.x, dp.y) << '\n';
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(10);
    solution();
    return 0;
}


Measured memory_bytes: 8164