#include<bits/stdc++.h>
#include <vector>
#include <algorithm>
using namespace std;
using UL = unsigned int;
using ULL = unsigned long long;
using LL = long long;

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



template <class dt>
struct edge {
	uint32_t to;
	dt cost;
	edge() {}
	edge(uint32_t to_, dt cost_)
		:to(to_), cost(cost_) {}
};


template <class dt>
class Solve_Path{
    public:
        //edges[from][to]
        vector<vector<dt>> edges;
        //edges[from][to][id] 多重辺
        vector<vector<vector<dt>>> edges_mul;
        // edges[from][num] = {to, cost}
        vector<vector<pair<int, dt>>> edges_light;
        dt inf;
        int n;
        Solve_Path(int _n, dt _inf){
            // 無限大のコストを割り当てる(実質通れない）
            n = _n;
            inf = _inf;
        }
        void enable_edges(){
            edges = vector<vector<dt>>(n, vector<dt>(n, inf));
        }
        void enable_edgesmul(){
            edges_mul = vector<vector<vector<dt>>>(n, vector<vector<dt>>(n, vector<dt>()));
        }
        void enable_edges_light(){
            edges_light = vector<vector<pair<int, dt>>>(n, vector<pair<int, dt>>());
        }
        void conv_multo2d(){
          enable_edges();
          int n = edges_mul.size();
          rep(i, n){
            rep(j, n){
                for (int id = 0; id < edges_mul[i][j].size(); id++){
                    edges[i][j] = min(edges[i][j], edges_mul[i][j][id]);
                }
            }
          } 
          vector<vector<vector<dt>>> edges_mul;
          vector<vector<vector<dt>>>().swap(edges_mul);    
        }
        void add_path(int from, int to, dt cost){
            edges[from][to] = cost;
            return;
        }
        void add_path(int from, int to){
            edges[from][to] = 1;
            return;
        }        
        void add_path_mul(int from, int to, dt cost){
            edges_mul[from][to].push_back(cost);
        }
        void add_path_mul_nonDir(int from, int to, dt cost){
            edges_mul[from][to].push_back(cost);
            edges_mul[to][from].push_back(cost);
            return;
        }
        void add_path_light(int from, int to, dt cost){
            edges_light[from].push_back({to, cost});
        }       
        
        vector<int> get_NumberOfEdges_nonvec(const vector<vector<vector<dt>>>& edge_list_mul3){
            vector<int> num_edge = vector<int>(n, 0);
            rep(i, n){
                rep(j, i){
                    for (int id = 0; id < edge_list_mul3[i][j].size(); id++){
                        num_edge[j]++;
                        num_edge[i]++;
                    }
                }
            }      
            return num_edge;
        }
        dt get_TotalWeight_nonvec(const vector<vector<vector<dt>>>& edge_list_mul3){
            dt total = 0;
            rep(i, n){
                rep(j, i){
                    for (int id = 0; id < edge_list_mul3[i][j].size(); id++){
                        total += edge_list_mul3[i][j][id];
                    }
                }
            }      
            return total;
        }     
        // 最短経路ペアを探索する。ﾜｰｼｬﾙﾌﾛｲﾄﾞ法O(n^3)
        vector<vector<dt>> solve_WarshallFloyd(const vector<vector<dt>>& edge_list){
            int n = edge_list.size();
            vector<vector<dt>> dp = edge_list;
            rep(i, n){
                rep(j, n){
                    dp[i][j] = edge_list[i][j];
                }
            }            
            rep(k, n){
                rep(i, n){
                    rep(j, n){
                        dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);
                    }
                }
            }
            return dp;
        }
        vector<vector<dt>> solve_WarshallFloyd(const vector<vector<vector<dt>>>& edge_list_mul3){
            int n = edge_list_mul3.size();
            vector<vector<dt>> dp =  vector<vector<dt>>(n, vector<dt>(n, inf));
            rep(i, n){
                rep(j, n){
                    for (int id = 0; id < edge_list_mul3[i][j].size(); id++){
                        dp[i][j] = min(dp[i][j], edge_list_mul3[i][j][id]);
                    }
                }
            }        
            dp = solve_WarshallFloyd(dp);
            return dp;
        }
        vector<vector<dt>> solve_WarshallFloyd(){
            return solve_WarshallFloyd(edges_mul);
        }
        // 最小重み最大マッチングを解く。
        // 全ての頂点をペアにして返す。
        vector<dt> solve_matching_minweight(vector<vector<dt>> d, int ignore_bit){
            int n = d.size();
            // ex. 1<<(n=3)で[(1000)2]、必要なのは(111)2までなので1<<nで十分
            int state_all = 1<<n;
            vector<dt> dp = vector<dt>(state_all, inf);
            // ignorebit以外が偶数じゃなければ計算できない。
            int count = 0;
            rep(i,n) if(ignore_bit&(1<<i)) count++;
            if((n-count)%2>0) return dp;

            // ビットが立ってるところはコスト0でスルー
            dp[ignore_bit] = 0;
            // nビット目までのビットDP、iビット目は要素iのマッチング済みを表す
            for(int state=0;state<1<<n;state++)
            {
                for(int from=0;from<n;from++)
                {
                    // from がマッチング済みの場合スルー
                    if(state&(1<<from))continue;
                    for(int to=from+1;to<n;to++)
                    {
                        // to がマッチング済みの場合スルー
                        if(state&(1<<to))continue;
                        // 重みを足してマッチング後の状態を作り、最小なら更新
                        dp[state|(1<<from)|(1<<to)]=min(dp[state|(1<<from)|(1<<to)],dp[state]+d[from][to]);
                    }
                }
            }
            return dp;
        }
      // ダイクストラ法でノードsからの最短経路を求める。
      vector<dt> solve_Djakstra(const vector<vector<dt>>& edge_list, const int& s){
        int n = edge_list.size();   
        priority_queue<pair<dt, int>, vector<pair<dt, int>>, greater<pair<dt, int>>> candidate_que;   
        vector<dt> distance_dp(n, inf);
        pair<dt, int> tmp_node;
        int now_index;
        // 最初にsを投入。
        candidate_que.push({0, s});
        distance_dp[s] = 0;
        // queの中の最小距離のノードに順に着目して最短経路を更新していく。
        while(!candidate_que.empty()){
          tmp_node = candidate_que.top();candidate_que.pop();
          now_index = tmp_node.second;
          rep(i, edge_list[now_index].size()){
            if(edge_list[now_index][i] == inf) continue;
            if(distance_dp[i] > distance_dp[now_index] + edge_list[now_index][i]){
              candidate_que.push({edge_list[now_index][i], i});
              distance_dp[i] = distance_dp[now_index] + edge_list[now_index][i];
            }
          }
        }
        return distance_dp;
      }
      vector<dt> solve_Djakstra_light(const int& s){  
        priority_queue<pair<dt, int>, vector<pair<dt, int>>, greater<pair<dt, int>>> candidate_que;   
        vector<dt> distance_dp(n, inf);
        pair<dt, int> tmp_node;
        int now_index;
        // 最初にsを投入。
        candidate_que.push({0, s});
        distance_dp[s] = 0;
        // queの中の最小距離のノードに順に着目して最短経路を更新していく。
        while(!candidate_que.empty()){
          tmp_node = candidate_que.top();candidate_que.pop();
          now_index = tmp_node.second;
          rep(i, edges_light[now_index].size()){
            if(distance_dp[edges_light[now_index][i].first] > distance_dp[now_index] + edges_light[now_index][i].second){
              candidate_que.push({edges_light[now_index][i].second, edges_light[now_index][i].first});
              distance_dp[edges_light[now_index][i].first] = distance_dp[now_index] + edges_light[now_index][i].second;
            }
          }
        }
        return distance_dp;
      }
      vector<dt> solve_Djakstra(const vector<vector<vector<dt>>>& edge_list_mul3, const int& s){
        int n = edge_list_mul3.size();
        vector<vector<dt>> dp =  vector<vector<dt>>(n, vector<dt>(n, inf));
        rep(i, n){
            rep(j, n){
                for (int id = 0; id < edge_list_mul3[i][j].size(); id++){
                    dp[i][j] = min(dp[i][j], edge_list_mul3[i][j][id]);
                }
            }
        }        
        return solve_Djakstra(dp, s);      
      }
      vector<dt> solve_Djakstra(const int& s){
        return solve_Djakstra(edges_mul, s);
      }

};



int main() {
  using dt = LL;
  LL H, W; scanf("%lld %lld", &H, &W);
  LL Ch, Cw; scanf("%lld %lld", &Ch, &Cw);
  LL Dh, Dw; scanf("%lld %lld", &Dh, &Dw);  
  Ch--; Cw--; Dh--; Dw--;
  vector<vector<dt>> S(H,vector<dt>(W,0));
  // ダイクストラ法でいけそう

  char ch;
  rep(h,H)rep(w,W){
    cin >> ch;
    if(ch=='#') S[h][w] = 0;
    else if(ch=='.') S[h][w] = 1;
  }

  Solve_Path<dt> SP = Solve_Path<dt>(H*W, INT_MAX);
  // パスの形式の指定、E>1e5の時はO(E)のlightを使う。
  SP.enable_edges_light();
  dt cost = 0;
  // マスh,wはindex = h*W+wで表す。
  rep(h,H)rep(w,W){
    // 5x5マスの任意の道にコスト1でワープ可能
    for(dt i = -2; i<=2; i++)for(dt j = -2; j<=2; j++){
      if(h+i<0 || h+i>=H || w+j<0 || w+j>=W) continue;
      if(S[h+i][w+j] == 1){
        cost = 1;      
        SP.add_path_light(h*W+w,(h+i)*W+(w+j),cost);
      }
    }
    // 隣接する道にコスト0で移動可能
    for(dt i = -1; i<=1; i++)for(dt j = -1; j<=1; j++){
      if(h+i<0 || h+i>=H || w+j<0 || w+j>=W || i*j!=0) continue;
      if(S[h+i][w+j] == 1){
        cost = 0;      
        SP.add_path_light(h*W+w,(h+i)*W+(w+j),cost);
      }
    }    
  } 
  vector<dt> WFpath = SP.solve_Djakstra_light(Ch*W+Cw);
  dt ans = WFpath[Dh*W+Dw];
  if (ans == INT_MAX) cout << -1 << endl;
  else cout << WFpath[Dh*W+Dw] << endl;
  
  return 0;
}


Measured memory_bytes: 384344