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

typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-12;
static const double PI = acos(-1.0);

#define FOR(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define ALL(a) (a).begin(), (a).end()
#ifdef LOCAL
#define dbg(x) cerr << __LINE__ << " : " << #x << " = " << (x) << endl
#else
#define dbg(x) true
#endif

const int MAX_N = 1000001;

namespace uf {
int par[MAX_N];
int rank[MAX_N];
int count[MAX_N];
}  // namespace uf

void init(int n) {
  for (int i = 0; i < n; i++) {
    uf::par[i] = i;
    uf::rank[i] = 0;
    uf::count[i] = 1;
  }
}

int find(int x) {
  if (uf::par[x] == x) {
    return x;
  } else {
    return uf::par[x] = find(uf::par[x]);
  }
}

void unite(int x, int y) {
  x = find(x);
  y = find(y);
  if (x == y)
    return;

  if (uf::rank[x] < uf::rank[y]) {
    uf::par[x] = y;
    uf::count[y] += uf::count[x];
  } else {
    uf::par[y] = x;
    if (uf::rank[x] == uf::rank[y])
      uf::rank[x]++;
    uf::count[x] += uf::count[y];
  }
}

int group_size(int x) {
  return uf::count[find(x)];
}

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

const int MAX_V = 1000001;  // TODO
const ll INF = INT_MAX;

struct Edge {
  int to;
  ll cost;
};
typedef pair<ll, int> P;  // firstは最短距離、secondは頂点の番号

int V = 1000001;        // 頂点数 TODO
vector<Edge> G[MAX_V];  // グラフ TODO
ll d[MAX_V];            // 頂点sからの最短距離
int prev_[MAX_V];       // 最短路の直前の頂点

void dijkstra(int s) {
  priority_queue<P, vector<P>, greater<P>> que;
  fill(d, d + V, INF);
  fill(prev_, prev_ + V, -1);
  d[s] = 0;
  que.push(P(0, s));

  while (!que.empty()) {
    P p = que.top();
    que.pop();
    int v = p.second;
    if (d[v] < p.first)
      continue;
    for (int i = 0; i < (int)G[v].size(); i++) {
      Edge e = G[v][i];
      if (d[e.to] > d[v] + e.cost) {
        d[e.to] = d[v] + e.cost;
        prev_[e.to] = v;
        que.push(P(d[e.to], e.to));
      }
    }
  }
}

vector<int> get_path(int t) {
  vector<int> path;

  for (; t != -1; t = prev_[t]) {
    path.push_back(t);
  }
  reverse(path.begin(), path.end());
  return path;
}

int main() {
  ll H, W;
  cin >> H >> W;
  init(W * H);
  ll Ch, Cw;
  cin >> Ch >> Cw;
  Ch--;
  Cw--;
  ll Dh, Dw;
  cin >> Dh >> Dw;
  Dh--;
  Dw--;
  vector<string> s(H);
  REP(i, H) {
    cin >> s[i];
  }
  vector<pair<ll, ll>> dv = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
  REP(y, H) {
    REP(x, W) {
      if (s[y][x] == '.') {
        REP(i, dv.size()) {
          ll dx = dv[i].first;
          ll dy = dv[i].second;
          if (0 <= x + dx && x + dx < W && 0 <= y + dy && y + dy < H) {
            if (s[y + dy][x + dx] == '.') {
              unite(y * W + x, (y + dy) * W + (x + dx));
            }
          }
        }
      }
    }
  }
  REP(y, H) {
    REP(x, W) {
      if (s[y][x] == '.') {
        for (ll dy = -2; dy <= 2; dy++) {
          for (ll dx = -2; dx <= 2; dx++) {
            if (0 <= x + dx && x + dx < W && 0 <= y + dy && y + dy < H) {
              if (s[y + dy][x + dx] == '.') {
                if (!same(y * W + x, (y + dy) * W + (x + dx))) {
                  G[find(y * W + x)].push_back({find((y + dy) * W + (x + dx)), 1});
                  G[find((y + dy) * W + (x + dx))].push_back({find(y * W + x), 1});
                }
              }
            }
          }
        }
      }
    }
  }
  dijkstra(find(Ch * W + Cw));
  if (d[find(Dh * W + Dw)] == INF) {
    cout << -1 << endl;

  } else {
    cout << d[find(Dh * W + Dw)] << endl;
  }
  return 0;
}


Measured memory_bytes: 137412