#include<bits/stdc++.h>
using namespace std;
#define rep(i,n) for(ll i=0;i<n;i++)
#define repl(i,l,r) for(ll i=(l);i<(r);i++)
#define per(i,n) for(ll i=n-1;i>=0;i--)
#define perl(i,r,l) for(ll i=r-1;i>=l;i--)
#define fi first
#define se second
#define pb push_back
#define ins insert
#define all(x) (x).begin(),(x).end()
using ll=long long;
using vl=vector<ll>;
using vvl=vector<vector<ll>>;
const ll MOD=1000000007;
const ll MOD9=998244353;
const int inf=1e9+10;
const ll INF=4e18;
const ll dy[8]={1,0,-1,0,1,1,-1,-1};
const ll dx[8]={0,-1,0,1,1,-1,1,-1};
using Graph = vector<vector<ll>>;
double nCk(int n, int k) {
double res=1.0;
for(int i=0; i<n; i++){
res*=0.5;}
for(int i=0; i<k; i++){
res*=(double)(n-i);
res/=(double)(k-i);
}
return res;}
struct edge{ll to, cost;};
typedef pair<ll,ll> P;
struct graph{
  ll V;
  vector<vector<edge> > G;
  vector<ll> d;
 
  graph(ll n){
    init(n);
  }
 
  void init(ll n){
    V = n;
    G.resize(V);
    d.resize(V);
    rep(i,V){
      d[i] = INF;
    }
  }
 
  void add_edge(ll s, ll t, ll cost){
    edge e;
    e.to = t, e.cost = cost;
    G[s].push_back(e);
  }
 
  void dijkstra(ll s){
    rep(i,V){
      d[i] = INF;
    }
    d[s] = 0;
    priority_queue<P,vector<P>, greater<P> > que;
    que.push(P(0,s));
    while(!que.empty()){
      P p = que.top(); que.pop();
      ll v = p.second;
      if(d[v]<p.first) continue;
      for(auto e : G[v]){
        if(d[e.to]>d[v]+e.cost){
          d[e.to] = d[v]+e.cost;
          que.push(P(d[e.to],e.to));
        }
      }
    }
  }
};
class UnionFind
{
public:
  ll par[100005];
  ll depth[100005];
  ll nGroup[100005];
 
  UnionFind(ll n) {
    init(n);
  }
 
  void init(ll n) {
    for(ll i=0; i<n; i++) {
      par[i] = i;
      depth[i] = 0;
      nGroup[i] = 1;
    }
  }
 
  ll root(ll x) {
    if(par[x] == x) {
      return x;
    } else {
      return par[x] = root(par[x]);
    }
  }
 
  bool same(ll x, ll y) {
    return root(x) == root(y);
  }
 
  void unite(ll x, ll y) {
    x = root(x);
    y = root(y);
    if(x == y) return;
 
    if(depth[x] < depth[y]) {
      par[x] = y;
      nGroup[y] += nGroup[x];
      nGroup[x] = 0;
    } else {
      par[y] = x;
      nGroup[x] += nGroup[y];
      nGroup[y] = 0;
      if(depth[x] == depth[y])
        depth[x]++;
    }
  }
};
const ll MAX = 510000;
ll fac[MAX], finv[MAX], inv[MAX];
 
// テーブルを作る前処理
void COMinit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for (int i = 2; i < MAX; i++){
        fac[i] = fac[i - 1] * i % MOD;
        inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD;
        finv[i] = finv[i - 1] * inv[i] % MOD;
    }
}
 
// 二項係数計算
ll COM(ll n, ll k){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
} 
 
vector<ll> depth;
vector<ll> subtree_size;
void dfs(const Graph &G, ll v, ll p, ll d) {
    depth[v] = d;
    for (auto nv : G[v]) {
        if (nv == p) continue; // nv が親 p だったらダメ
        dfs(G, nv, v, d+1);
    }
 
    // 帰りがけ時に、部分木サイズを求める
    subtree_size[v] = INF; // 自分自身
    vl q;
    for (auto c : G[v]) {
        if (c == p) continue;
        q.pb(subtree_size[c]);// 子のサイズを加える
    }
  ll qq = q.size();
  //cout << v << " " << qq << endl;
  if(qq==0) subtree_size[v]=0;
  else{
  sort(all(q));
    //rep(i,qq)cout << q[i];
    //cout << endl;
  ll caa = 0;
  rep(i,qq){
    caa = max(qq+q[i]-i,caa);}
    subtree_size[v]=caa;
  }
}
ll dp[100005][2];
int main() {
ll H, W;
    cin >> H >> W;
    ll sy,sx,gy,gx,d;
    cin>>sx>>sy>>gx>>gy;
    sx--;sy--;gx--;gy--;
    /* 盤面 */
    vector<string> field(H);
    for (ll h = 0; h < H; ++h) cin >> field[h];

    vector<vector<ll> > dist(H, vector<ll>(W, INF)); 
  	//vector<vector<ll> > dist1(H, vector<ll>(W, -1)); 
    dist[sx][sy] = 0; // スタートを 0 に
    //dist1[sx][sy] = 0;
    // 探索中に各マスはどのマスから来たのかを表す配列 (最短経路長を知るだけなら、これは不要)
    //vector<vector<int> > prev_x(H, vector<int>(W, -1));
    //vector<vector<int> > prev_y(H, vector<int>(W, -1));

    // 「一度見た頂点」のうち「まだ訪れていない頂点」を表すキュー
    deque<pair<ll, ll> > que; 
    que.push_front(make_pair(sx, sy)); // スタートを push


    ////////////////////////////////////////
    /* 幅優先探索を実施 */
    ////////////////////////////////////////    

    /* キューが空になるまで */
    while (!que.empty()) {
        pair<ll, ll> current_pos = que.front(); // キューの先頭を見る (C++ ではこれをしても pop しない)
        ll x = current_pos.first;
        ll y = current_pos.second;
        que.pop_front(); // キューから pop を忘れずに

        // 隣接頂点を探索
        for (ll direction = 0; direction < 4; ++direction) {
            ll next_x = x + dx[direction];
            ll next_y = y + dy[direction];
            if (next_x < 0 || next_x >= H || next_y < 0 || next_y >= W) continue; // 場外アウトならダメ
            if (field[next_x][next_y] == '#') continue; // 壁はダメ
            d = dist[x][y];
            // まだ見ていない頂点なら push
            if(dist[next_x][next_y]>d){
              dist[next_x][next_y] = d;
              que.push_front(make_pair(next_x, next_y));}
                //prev_x[next_x][next_y] = x;  // どの頂点から情報が伝播して来たか、縦方向の座標をメモ
                //prev_y[next_x][next_y] = y;  // どの頂点から情報が伝播して来たか、横方向の座標をメモ
         
        }
        for (ll direction = 4; direction < 8; ++direction) {
            ll next_x = x + dx[direction];
            ll next_y = y + dy[direction];
            if (next_x < 0 || next_x >= H || next_y < 0 || next_y >= W) continue; // 場外アウトならダメ
            if (field[next_x][next_y] == '#') continue; // 壁はダメ
            d = dist[x][y] + 1;
            // まだ見ていない頂点なら push
            if(dist[next_x][next_y]>d){
              que.push_back(make_pair(next_x, next_y));
                dist[next_x][next_y] = dist[x][y]+1;}
        }
      for (ll direction = 0; direction < 4; ++direction) {
            ll next_x = x + 2*dx[direction];
            ll next_y = y + 2*dy[direction];
            if (next_x < 0 || next_x >= H || next_y < 0 || next_y >= W) continue; // 場外アウトならダメ
            if (field[next_x][next_y] == '#') continue; // 壁はダメ

            d = dist[x][y] + 1;
            if(dist[next_x][next_y]>d){
              que.push_back(make_pair(next_x, next_y));
                dist[next_x][next_y] = dist[x][y]+1;}
        }
      for (ll direction = 4; direction < 8; ++direction) {
            ll next_x = x + 2*dx[direction];
            ll next_y = y + 2*dy[direction];
            if (next_x < 0 || next_x >= H || next_y < 0 || next_y >= W) continue; // 場外アウトならダメ
            if (field[next_x][next_y] == '#') continue; // 壁はダメ

            d = dist[x][y] + 1;
            if(dist[next_x][next_y]>d){
              que.push_back(make_pair(next_x, next_y));
                dist[next_x][next_y] = dist[x][y]+1;}
        }
      for (ll direction = 4; direction < 8; ++direction) {
            ll next_x = x + 2*dx[direction];
            ll next_y = y + dy[direction];
            if (next_x < 0 || next_x >= H || next_y < 0 || next_y >= W) continue; // 場外アウトならダメ
            if (field[next_x][next_y] == '#') continue; // 壁はダメ

            
            d = dist[x][y] + 1;
            if(dist[next_x][next_y]>d){
              que.push_back(make_pair(next_x, next_y));
                dist[next_x][next_y] = dist[x][y]+1;}
        }
      for (ll direction = 4; direction < 8; ++direction) {
            ll next_x = x + dx[direction];
            ll next_y = y + 2*dy[direction];
            if (next_x < 0 || next_x >= H || next_y < 0 || next_y >= W) continue; // 場外アウトならダメ
            if (field[next_x][next_y] == '#') continue; // 壁はダメ

            
            d = dist[x][y] + 1;
            if(dist[next_x][next_y]>d){
              que.push_back(make_pair(next_x, next_y));
                dist[next_x][next_y] = dist[x][y]+1;}
        }
    }
  if(dist[gx][gy]==INF) dist[gx][gy]=-1;
        cout << dist[gx][gy] << endl;

}


Measured memory_bytes: 13400