Problem:
Score : 400 points

Problem Statement

A maze is composed of a grid of H \times W squares - H vertical, W horizontal.

The square at the i-th row from the top and the j-th column from the left - (i,j) - is a wall if S_{ij} is # and a road if S_{ij} is ..

There is a magician in (C_h,C_w). He can do the following two kinds of moves:

Move A: Walk to a road square that is vertically or horizontally adjacent to the square he is currently in.

Move B: Use magic to warp himself to a road square in the 5\times 5 area centered at the square he is currently in.

In either case, he cannot go out of the maze.

At least how many times does he need to use the magic to reach (D_h, D_w)?

Constraints

1 \leq H,W \leq 10^3

1 \leq C_h,D_h \leq H

1 \leq C_w,D_w \leq W

S_{ij} is # or ..

S_{C_h C_w} and S_{D_h D_w} are ..

(C_h,C_w) \neq (D_h,D_w)

Input

Input is given from Standard Input in the following format:

H W
C_h C_w
D_h D_w
S_{11}\ldots S_{1W}
\vdots
S_{H1}\ldots S_{HW}

Output

Print the minimum number of times the magician needs to use the magic. If he cannot reach (D_h,D_w), print -1 instead.

Sample Input 1

4 4
1 1
4 4
..#.
..#.
.#..
.#..

Sample Output 1

1

For example, by walking to (2,2) and then using the magic to travel to (4,4), just one use of magic is enough.

Note that he cannot walk diagonally.

Sample Input 2

4 4
1 4
4 1
.##.
####
####
.##.

Sample Output 2

-1

He cannot move from there.

Sample Input 3

4 4
2 2
3 3
....
....
....
....

Sample Output 3

0

No use of magic is needed.

Sample Input 4

4 5
1 2
2 5
#.###
####.
#..##
#..##

Sample Output 4

2

Solution in C++ (GCC 9.2.1) (judge verdict: Accepted)

#include <bits/stdc++.h>
using namespace std;

// TYPEDEF
// ----------------------------------------
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> Pair;
typedef vector<ll> vll;
typedef vector<vector<ll>> Graph;
typedef vector<string> vs;
typedef vector<pair<ll, ll>> Pll;
typedef queue<ll> qll;

// REPEAT
// ----------------------------------------
#define REP(i,n) for(ll i=0;i<(ll)(n);i++)
#define REPD(i,n) for(ll i=n-1;i>=0;i--)
#define REPA(i,a) for(ll i=0;i<(ll)(a.size());i++);
#define FOR(i,a,b) for(ll i=a;i<=(ll)(b);i++)
#define FORD(i,a,b) for(ll i=a;i>=(ll)(b);i--)
#define COUT(a) cout << (a) << endl;
#define ENDL(a) cout << endl;
#define COUTA(i,a) for(ll i=0;i<(ll)(a.size());i++) {cout << (a)[i] << " ";} cout << endl;

// UTIL
// ----------------------------------------
#define pb push_back
#define paired make_pair
#define ALL(a) (a).begin(),(a).end()
#define SORT(a) sort((a).begin(),(a).end())
#define RSORT(a) sort((a).rbegin(), (a).rend())

ll tousa_no_wa(ld a, ll n, ld d) {
  return (ld(n) / 2) * (2 * a + (n - 1) * d);
}

// PRINT
// ----------------------------------------
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;
#define Yes cout << "Yes" << endl;
#define No cout << "No" << endl;

// DEBUG
// ----------------------------------------
#ifdef _DEBUG
#define debug(x) cout << "[debug] " << #x << ": " << x << endl
#else
#define debug(x)
#endif

template <typename T>
void debugV(const vector<T> v) {
#ifdef _DEBUG
  rep(i, v.size()) {
    cout << i << ":" << v[i] << " ";
  }
  cout << endl;
#else
  (void)v;
#endif
}

// BIT FLAG
// ----------------------------------------
const unsigned int BIT_FLAG_0 = (1 << 0); // 0000 0000 0000 0001
const unsigned int BIT_FLAG_1 = (1 << 1); // 0000 0000 0000 0010
const unsigned int BIT_FLAG_2 = (1 << 2); // 0000 0000 0000 0100
const unsigned int BIT_FLAG_3 = (1 << 3); // 0000 0000 0000 1000
const unsigned int BIT_FLAG_4 = (1 << 4); // 0000 0000 0001 0000
const unsigned int BIT_FLAG_5 = (1 << 5); // 0000 0000 0010 0000
const unsigned int BIT_FLAG_6 = (1 << 6); // 0000 0000 0100 0000
const unsigned int BIT_FLAG_7 = (1 << 7); // 0000 0000 1000 0000
const unsigned int BIT_FLAG_8 = (1 << 8); // 0000 0001 0000 0000
const unsigned int BIT_FLAG_9 = (1 << 9); // 0000 0010 0000 0000
const unsigned int BIT_FLAG_10 = (1 << 10); // 0000 0100 0000 0000
const unsigned int BIT_FLAG_11 = (1 << 11); // 0000 1000 0000 0000

// CONST
// ----------------------------------------
constexpr ll INF = 0x3f3f3f3f3f3f3f3f;
constexpr double PI=3.14159265358979323846; // or M_PI
constexpr int MOD = 1000000007;


struct UnionFind {
  vll data;
 
  UnionFind(ll sz) {
    data.assign(sz, -1);
  }
 
  bool unite(ll x, ll y) {
    x = find(x);
    y = find(y);
    if (x == y) {
      return (false);
    }
    if (data[x] > data[y]) {
      swap(x, y);
    }
    data[x] += data[y];
    data[y] = x;
    return (true);
  }
 
  ll find(ll k) {
    if(data[k] < 0) {
      return (k);
    }
    return (data[k] = find(data[k]));
  }
 
  ll size(ll k) {
    return (-data[find(k)]);
  }

  ll same(ll x, ll y) {
    return (find(x) == find(y));
  }
};

// modint: mod 計算を int を扱うように扱える構造体
template<int MOD> struct Fp {
    long long val;
    constexpr Fp(long long v = 0) noexcept : val(v % MOD) {
        if (val < 0) v += MOD;
    }
    constexpr int getmod() { return MOD; }
    constexpr Fp operator - () const noexcept {
        return val ? MOD - val : 0;
    }
    constexpr Fp operator + (const Fp& r) const noexcept { return Fp(*this) += r; }
    constexpr Fp operator - (const Fp& r) const noexcept { return Fp(*this) -= r; }
    constexpr Fp operator * (const Fp& r) const noexcept { return Fp(*this) *= r; }
    constexpr Fp operator / (const Fp& r) const noexcept { return Fp(*this) /= r; }
    constexpr Fp& operator += (const Fp& r) noexcept {
        val += r.val;
        if (val >= MOD) val -= MOD;
        return *this;
    }
    constexpr Fp& operator -= (const Fp& r) noexcept {
        val -= r.val;
        if (val < 0) val += MOD;
        return *this;
    }
    constexpr Fp& operator *= (const Fp& r) noexcept {
        val = val * r.val % MOD;
        return *this;
    }
    constexpr Fp& operator /= (const Fp& r) noexcept {
        long long a = r.val, b = MOD, u = 1, v = 0;
        while (b) {
            long long t = a / b;
            a -= t * b; swap(a, b);
            u -= t * v; swap(u, v);
        }
        val = val * u % MOD;
        if (val < 0) val += MOD;
        return *this;
    }
    constexpr bool operator == (const Fp& r) const noexcept {
        return this->val == r.val;
    }
    constexpr bool operator != (const Fp& r) const noexcept {
        return this->val != r.val;
    }
    friend constexpr ostream& operator << (ostream &os, const Fp<MOD>& x) noexcept {
        return os << x.val;
    }
    friend constexpr istream& operator >> (istream &is, Fp<MOD>& x) noexcept {
        return is >> x.val;
    }
    friend constexpr Fp<MOD> modpow(const Fp<MOD> &a, long long n) noexcept {
        if (n == 0) return 1;
        auto t = modpow(a, n / 2);
        t = t * t;
        if (n & 1) t = t * a;
        return t;
    }
};

// 二項係数ライブラリ
template<class T> struct BiCoef {
    vector<T> fact_, inv_, finv_;
    constexpr BiCoef() {}
    constexpr BiCoef(int n) noexcept : fact_(n, 1), inv_(n, 1), finv_(n, 1) {
        init(n);
    }
    constexpr void init(int n) noexcept {
        fact_.assign(n, 1), inv_.assign(n, 1), finv_.assign(n, 1);
        int MOD = fact_[0].getmod();
        for(int i = 2; i < n; i++){
            fact_[i] = fact_[i-1] * i;
            inv_[i] = -inv_[MOD%i] * (MOD/i);
            finv_[i] = finv_[i-1] * inv_[i];
        }
    }
    constexpr T com(int n, int k) const noexcept {
        if (n < k || n < 0 || k < 0) return 0;
        return fact_[n] * finv_[k] * finv_[n-k];
    }
    constexpr T fact(int n) const noexcept {
        if (n < 0) return 0;
        return fact_[n];
    }
    constexpr T inv(int n) const noexcept {
        if (n < 0) return 0;
        return inv_[n];
    }
    constexpr T finv(int n) const noexcept {
        if (n < 0) return 0;
        return finv_[n];
    }
};

// 困ったらここ
// https://ei1333.github.io/luzhiled/


void Main() {
  ll h, w, c_h, c_w, d_h, d_w;
  cin >> h >> w >> c_h >> c_w >> d_h >> d_w;
  vector<vector<char>> s(h, vector<char>(w));
  vector<vector<ll>> check(h, vector<ll>(w, -1));
  REP(i, h) {
    REP(j, w) {
      cin >> s[i][j];
    }
  }

  queue<Pair> q;
  ll group = 0;
  ll group_num = 0;

  REP(i, h) {
    REP(j, w) {
      if (check[i][j] != -1) {
        continue;
      }
      else if (s[i][j] == '#') {
        continue;
      }
      q.emplace(i, j);
      check[i][j] = group;
      group_num = max(group_num, group);
      while(!q.empty()) {
        ll x = q.front().first; //tate
        ll y = q.front().second; //yoko
        q.pop();
        if (s[x][y] == '.') {
          // hidari
          if (y > 0 and check[x][y - 1] == -1 and s[x][y - 1] != '#') {
            q.emplace(x, y - 1);
            check[x][y - 1] = group;
            group_num = max(group_num, group);
          }
          // migi
          if (y < (w - 1) and check[x][y + 1] == -1 and s[x][y + 1] != '#') {
            q.emplace(x, y + 1);
            check[x][y + 1] = group;
            group_num = max(group_num, group);
          }
          // ue
          if (x > 0 and check[x - 1][y] == -1 and s[x - 1][y] != '#') {
            q.emplace(x - 1, y);
            check[x - 1][y] = group;
            group_num = max(group_num, group);
          }
          // shita
          if (x < (h - 1) and check[x + 1][y] == -1 and s[x + 1][y] != '#') {
            q.emplace(x + 1, y);
            check[x + 1][y] = group;
            group_num = max(group_num, group);
          }
        }
      }
      group++;
    }
  }

  Graph g(group_num + 1);
  
  UnionFind uf(group_num + 1);
  REP(i, h) {
    REP(j, w) {
      FOR(diff_i, -2, 2) {
        FOR(diff_j, -2, 2) {
          if ((0 <= i + diff_i) and (i + diff_i < h) and (0 <= j + diff_j) and (j + diff_j < w)) {
            if (check[i][j] != -1 and check[i + diff_i][j + diff_j] != -1) {
              uf.unite(check[i][j], check[i + diff_i][j + diff_j]);
              if (check[i][j] != check[i + diff_i][j + diff_j]) {
                g[check[i][j]].push_back(check[i + diff_i][j + diff_j]);
                g[check[i + diff_i][j + diff_j]].push_back(check[i][j]);
              }
            }
          }
        }
      }
    }
  }

  REP(i, group_num + 1) {
    SORT(g[i]);
    g[i].erase(unique(g[i].begin(), g[i].end()), g[i].end());
    // COUTA(l, g[i]);
  }

  ll start_group = check[c_h - 1][c_w - 1];
  ll goal_group = check[d_h - 1][d_w - 1];

  if (uf.find(start_group) != uf.find(goal_group)) {
    COUT(-1);
  }
  else {
    vll toutatsu(group_num + 1, -1);
    queue<ll> ans;
    ans.push(start_group);
    toutatsu[start_group] = 0;
    while(!ans.empty()) {
      ll target = ans.front();
      ans.pop();
      REP(o, g[target].size()) {
        if (toutatsu[g[target][o]] == -1) {
          toutatsu[g[target][o]] = toutatsu[target] + 1;
          ans.push(g[target][o]);
        }
      }
    }
    COUT(toutatsu[goal_group]);
  }

/*
  REP(i, group + 1) {
    COUT(uf.find(i));
  }
  */
  
}

int main()
{
	cin.tie(0);
	ios_base::sync_with_stdio(false);
	cout << fixed << setprecision(15);
	Main();
}

/*
5
24 11 8 3 16
*/

/*
等差数列の和　floatにしとく

*/