#include <bits/stdc++.h>

#ifdef DEBUG
#include <Mylib/Debug/debug.cpp>
#else
#define dump(...)
#endif


template <typename T>
struct Graph{
  using weight_value_type = T;
  
  struct Edge{
    int from, to;
    T cost;
  };
  
  std::vector<std::vector<Edge>> data;

  auto& operator[](size_t i) {return data[i];}
  const auto& operator[](size_t i) const {return data[i];}
  
  auto begin() const {return data.begin();}
  auto end() const {return data.end();}

  Graph(){}
  Graph(int N): data(N){}

  bool empty() const {return data.empty();}
  int size() const {return data.size();}

  void add_edge(int i, int j, T w){
    data[i].push_back({i, j, w});
  }
  
  void add_undirected(int i, int j, T w){
    add_edge(i, j, w);
    add_edge(j, i, w);
  }
};


template <typename T>
struct GridGraph : public Graph<T>{
  int H, W;
  GridGraph(int H, int W): Graph<T>(H * W), H(H), W(W){}

  int index(int i, int j) const {
    return i * W + j;
  }
};


/**
 * @title Dijkstra algorithm
 * @docs dijkstra.md
 */
template <typename G>
class Dijkstra{
public:
  using T = typename G::weight_value_type;
  std::vector<std::optional<T>> dist;

private:
  void run(const G &graph, std::vector<int> src){
    const int n = graph.size();
    dist.assign(n, std::nullopt);
    
    std::vector<bool> check(n, false);
    std::priority_queue<std::pair<T,int>, std::vector<std::pair<T,int>>, std::greater<std::pair<T,int>>> pq;

    for(auto s : src){
      dist[s] = 0;
      pq.emplace(0, s);
    }

    while(not pq.empty()){
      const auto [d, i] = pq.top(); pq.pop();

      if(check[i]) continue;
      check[i] = true;

      for(auto &e : graph[i]){
        if(not dist[e.to]){
          dist[e.to] = d + e.cost;
          pq.emplace(*dist[e.to], e.to);
        }else{
          if(*dist[e.to] > d + e.cost){
            dist[e.to] = d + e.cost;
            if(not check[e.to]) pq.emplace(*dist[e.to], e.to);
          }
        }
      }
    }
  }

public:
  Dijkstra(const G &graph, int src){run(graph, {src});}
  Dijkstra(const G &graph, const std::vector<int> &src){run(graph, src);}
};




namespace solver{
  template <typename Container, typename T = typename Container::value_type>
  T safe_get_2d(const std::vector<Container> &a, int i, int j, T d){
    if(i < 0 or i >= (int)a.size()) return d;
    if(j < 0 or j >= (int)a[i].size()) return d;
    return a[i][j];
  }

  int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};

  
  void solve(){
    std::cin.tie(0);
    std::ios::sync_with_stdio(false);

    int H, W; std::cin >> H >> W;
    int Ch, Cw; std::cin >> Ch >> Cw;
    int Dh, Dw; std::cin >> Dh >> Dw;

    --Ch, --Cw;
    --Dh, --Dw;

    std::vector<std::string> S(H);
    for(int i = 0; i < H; ++i) std::cin >> S[i];

    
    GridGraph<int> g(H, W);

    for(int i = 0; i < H; ++i){
      for(int j = 0; j < W; ++j){
        for(auto [dx, dy] : dir){
          if(S[i][j] == '.' and safe_get_2d(S, i + dx, j + dy, '#') == '.'){
            g.add_edge(g.index(i, j), g.index(i + dx, j + dy), 0);
          }
        }

        for(int dx = -2; dx <= 2; ++dx){
          for(int dy = -2; dy <= 2; ++dy){
            if(S[i][j] == '.' and safe_get_2d(S, i + dx, j + dy, '#') == '.'){
              g.add_edge(g.index(i, j), g.index(i + dx, j + dy), 1);
            }
          }
        }
      }
    }

    auto res = Dijkstra(g, g.index(Ch, Cw)).dist[g.index(Dh, Dw)];
    
    std::cout << res.value_or(-1) << "\n";
  }
}

int main(){
  solver::solve();
  return 0;
}


Measured memory_bytes: 165248