#include <string>
#include <iostream>
#include <stack>
#include <queue> // priority_queue も入ってる
#include <set>   // 要素数は size() で取得 multisetもある
#include <map>
#include <array> // sizeはコンパイル時定数で固定
#include <vector>
#include <numeric>   // accumulate, gcd
#include <algorithm> // count_ifに必要
#include <iomanip>   // cout << setprecision(15) << x で小数の出力精度を指定
#include <tuple>
#include <utility> //pair
#include <cmath>
#include <random>

using namespace std;
// 問題が起こるまでintは使用禁止2020-04-13
using ll = long long;

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

template <class InputIterator, class T>
bool contains_itr(InputIterator iterator, const T &value)
{
    if (find(iterator.begin(), iterator.end(), value) == iterator.end())
        return false;
    else
        return true;
}

template <class T>
bool contains_set(set<T> st, const T &value)
{
    if (st.find(value) == st.end())
    {
        return false;
    }
    else
    {
        return true;
    }
}

template <class InputIterator>
auto sum(InputIterator iterator)
{
    return accumulate(iterator.begin(), iterator.end(), 0);
}

// endは排他的(exclusive)なので注意
vector<ll> range(ll begin, ll end)
{
    vector<ll> result;
    for (ll i = begin; i < end; ++i)
    {
        result.push_back(i);
    }
    return result;
}

random_device seed_gen;
mt19937 engine(seed_gen());
// 0, 1, 2 のどれかが得られる一様分布
// uniform_int_distribution<> dist(0, 2);
// cout << dist(engine) << endl;
// みたいに、先に確率分布を宣言して、そこにengineを与えて使う。

// =========ここまでテンプレ============

int main()
{
    ll h, w, ch, cw, dh, dw;
    cin >> h >> w >> ch >> cw >> dh >> dw;
    --ch;
    --cw;
    --dh;
    --dw;
    vector<vector<char>> s(h, vector<char>(w));
    rep(i, h)
    {
        rep(j, w) cin >> s[i][j];
    }
    vector<vector<ll>> shortests(h, vector<ll>(w, LLONG_MAX));
    // (最短ワープ数、座標h,座標w)
    priority_queue<tuple<ll, ll, ll>, vector<tuple<ll, ll, ll>>, greater<tuple<ll, ll, ll>>> que;
    que.push(tuple<ll, ll, ll>{0, ch, cw});
    ll result = -1;
    while (!que.empty())
    {
        tuple<ll, ll, ll> now = que.top();
        que.pop();
        ll nowWarp = get<0>(now);
        ll nowH = get<1>(now);
        ll nowW = get<2>(now);

        if (nowH == dh && nowW == dw)
        {
            result = nowWarp;
            break;
        }

        // 上下左右について、移動可能(存在し、壁じゃない)かつ、ワープ数が更新できるならqueに追加
        if (nowH > 0 && s[nowH - 1][nowW] == '.' && shortests[nowH - 1][nowW] > nowWarp)
        {
            shortests[nowH - 1][nowW] = nowWarp;
            que.push(tuple<ll, ll, ll>{nowWarp, nowH - 1, nowW});
        }
        if (nowH < h - 1 && s[nowH + 1][nowW] == '.' && shortests[nowH + 1][nowW] > nowWarp)
        {
            shortests[nowH + 1][nowW] = nowWarp;
            que.push(tuple<ll, ll, ll>{nowWarp, nowH + 1, nowW});
        }
        if (nowW > 0 && s[nowH][nowW - 1] == '.' && shortests[nowH][nowW - 1] > nowWarp)
        {
            shortests[nowH][nowW - 1] = nowWarp;
            que.push(tuple<ll, ll, ll>{nowWarp, nowH, nowW - 1});
        }
        if (nowW < w - 1 && s[nowH][nowW + 1] == '.' && shortests[nowH][nowW + 1] > nowWarp)
        {
            shortests[nowH][nowW + 1] = nowWarp;
            que.push(tuple<ll, ll, ll>{nowWarp, nowH, nowW + 1});
        }
        for (ll i = nowH - 2; i <= nowH + 2; ++i)
        {
            for (ll j = nowW - 2; j <= nowW + 2; ++j)
            {
                if (i >= 0 && i <= h - 1 && j >= 0 && j <= w - 1 && s[i][j] == '.' && shortests[i][j] > nowWarp + 1)
                {
                    shortests[i][j] = nowWarp + 1;
                    que.push(tuple<ll, ll, ll>{nowWarp + 1, i, j});
                }
            }
        }
    }
    cout << result << endl;
    return 0;
}

Measured memory_bytes: 12212