#include <algorithm>
#include <array>
#include <bits/stdc++.h>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <iostream>
#include <iterator>
#include <limits>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <vector>

// lib/rotate_left.hpp
#ifndef ROTATE_LEFT_HPP
#define ROTATE_LEFT_HPP


/*
usage:

// 5-bit circular shift to the left
tools::rotate_left(x, 5);
*/

// Source: Stack Overflow ( https://stackoverflow.com/questions/776508/best-practices-for-circular-shift-rotate-operations-in-c/776523#776523 )
// Author: John Regehr ( https://blog.regehr.org/ ) and Peter Cordes ( https://stackoverflow.com/users/224132/peter-cordes )
// License: CC BY-SA 3.0
namespace tools {
  template <typename T, typename ::std::enable_if<::std::is_unsigned<T>::value, ::std::nullptr_t>::type = nullptr>
  constexpr T rotate_left(const T& value, const ::std::size_t& count) noexcept {
    return (value << (count & ::std::numeric_limits<T>::max())) | (value >> (-(count & ::std::numeric_limits<T>::max()) & ::std::numeric_limits<T>::max()));
  }

  template <typename T, typename ::std::enable_if<::std::is_signed<T>::value, ::std::nullptr_t>::type = nullptr>
  T rotate_left(const T& value, const ::std::size_t& count) {
    return value >= static_cast<T>(0)
      ? static_cast<T>(::tools::rotate_left(static_cast<typename ::std::make_unsigned<T>::type>(value), count))
      : (throw ::std::invalid_argument("value of ::tools::rotate_left must be non-negative, but was " + ::std::to_string(value) + "."));
  }
}

#endif

// lib/util.hpp
#ifndef UTIL_HPP
#define UTIL_HPP


using i64 = ::std::int_fast64_t;
using u64 = ::std::uint_fast64_t;
using i32 = ::std::int_fast32_t;
using u32 = ::std::uint_fast32_t;

namespace tools {
  template <typename T>
  void read(::std::istream& is, ::std::vector<T>& vector, const typename ::std::vector<T>::size_type size) {
    vector.reserve(size);
    ::std::copy_n(::std::istream_iterator<T>(is), size, ::std::back_inserter(vector));
  }
  template <typename T>
  void read(::std::vector<T>& vector, const typename ::std::vector<T>::size_type size) {
    ::tools::read(::std::cin, vector, size);
  }

  template <typename T, ::std::size_t N>
  void read(::std::istream& is, ::std::array<T, N>& array) {
    ::std::copy_n(std::istream_iterator<T>(is), N, array.begin());
  }
  template <typename T, ::std::size_t N>
  void read(::std::array<T, N>& array) {
    ::tools::read(::std::cin, array);
  }
}

#endif

// lib/vector2.hpp
#ifndef VECTOR2_HPP
#define VECTOR2_HPP


/*
usage:

tools::vector2<int>(6, 5) // => (6, 5)
*/

namespace tools {
  template <typename T>
  class vector2 {
  public:
    T x;
    T y;

    vector2() :
      vector2(T(), T()) {
    }

    vector2(const T& x, const T& y) :
      x(x),
      y(y) {
    }

    double norm() const {
      return ::std::sqrt(this->squaredNorm());
    }

    T squaredNorm() const {
      return this->inner_product(*this);
    }

    template <typename SFINAE_T = T, typename ::std::enable_if<::std::is_same<SFINAE_T, double>::value, ::std::nullptr_t>::type = nullptr>
    double normalize() const {
      return *this / this->norm();
    }

    ::tools::vector2<T> operator+() const {
      return *this;
    }

    ::tools::vector2<T> operator-() const {
      return ::tools::vector2<T>(-this->x, -this->y);
    }

    friend ::tools::vector2<T> operator+(const ::tools::vector2<T>& lhs, const ::tools::vector2<T>& rhs) {
      return ::tools::vector2<T>(lhs.x + rhs.x, lhs.y + rhs.y);
    }

    friend ::tools::vector2<T> operator-(const ::tools::vector2<T>& lhs, const ::tools::vector2<T>& rhs) {
      return ::tools::vector2<T>(lhs.x - rhs.x, lhs.y - rhs.y);
    }

    template <typename OTHER, typename ::std::enable_if<!::std::is_same<OTHER, ::tools::vector2<T>>::value, ::std::nullptr_t>::type = nullptr>
    friend ::tools::vector2<T> operator*(const ::tools::vector2<T>& lhs, const OTHER& rhs) {
      return ::tools::vector2<T>(lhs.x * rhs, lhs.y * rhs);
    }
    template <typename OTHER, typename ::std::enable_if<!::std::is_same<OTHER, ::tools::vector2<T>>::value, ::std::nullptr_t>::type = nullptr>
    friend ::tools::vector2<T> operator*(const OTHER& lhs, const ::tools::vector2<T>& rhs) {
      return ::tools::vector2<T>(lhs * rhs.x, lhs * rhs.y);
    }

    template <typename OTHER, typename ::std::enable_if<!::std::is_same<OTHER, ::tools::vector2<T>>::value, ::std::nullptr_t>::type = nullptr>
    friend ::tools::vector2<T> operator/(const ::tools::vector2<T>& lhs, const OTHER& rhs) {
      return ::tools::vector2<T>(lhs.x / rhs, lhs.y / rhs);
    }

    T inner_product(const ::tools::vector2<T>& other) const {
      return this->x * other.x + this->y * other.y;
    }

    ::tools::vector2<T>& operator+=(const ::tools::vector2<T>& other) {
      return *this = *this + other;
    }

    ::tools::vector2<T>& operator-=(const ::tools::vector2<T>& other) {
      return *this = *this - other;
    }

    template <typename OTHER, typename ::std::enable_if<!::std::is_same<OTHER, ::tools::vector2<T>>::value, ::std::nullptr_t>::type = nullptr>
    ::tools::vector2<T>& operator*=(const OTHER& other) {
      return *this = *this * other;
    }

    template <typename OTHER, typename ::std::enable_if<!::std::is_same<OTHER, ::tools::vector2<T>>::value, ::std::nullptr_t>::type = nullptr>
    ::tools::vector2<T>& operator/=(const OTHER& other) {
      return *this = *this / other;
    }

    friend bool operator==(const ::tools::vector2<T>& lhs, const ::tools::vector2<T>& rhs) {
      return lhs.x == rhs.x && lhs.y == rhs.y;
    }

    friend bool operator!=(const ::tools::vector2<T>& lhs, const ::tools::vector2<T>& rhs) {
      return lhs.x != rhs.x || lhs.y != rhs.y;
    }

    static ::std::array<::tools::vector2<T>, 4> four_directions() {
      return ::std::array<::tools::vector2<T>, 4>({
        ::tools::vector2<T>(static_cast<T>(-1), static_cast<T>(0)),
        ::tools::vector2<T>(static_cast<T>(1), static_cast<T>(0)),
        ::tools::vector2<T>(static_cast<T>(0), static_cast<T>(-1)),
        ::tools::vector2<T>(static_cast<T>(0), static_cast<T>(1))
      });
    }

    static ::std::array<::tools::vector2<T>, 8> eight_directions() {
      return ::std::array<::tools::vector2<T>, 8>({
        ::tools::vector2<T>(static_cast<T>(-1), static_cast<T>(-1)),
        ::tools::vector2<T>(static_cast<T>(-1), static_cast<T>(0)),
        ::tools::vector2<T>(static_cast<T>(-1), static_cast<T>(1)),
        ::tools::vector2<T>(static_cast<T>(0), static_cast<T>(-1)),
        ::tools::vector2<T>(static_cast<T>(0), static_cast<T>(1)),
        ::tools::vector2<T>(static_cast<T>(0), static_cast<T>(-1)),
        ::tools::vector2<T>(static_cast<T>(1), static_cast<T>(-1)),
        ::tools::vector2<T>(static_cast<T>(1), static_cast<T>(0)),
        ::tools::vector2<T>(static_cast<T>(1), static_cast<T>(1))
      });
    }
  };
}

namespace std {
  template <typename T>
  ::std::string to_string(const ::tools::vector2<T>& f) {
    return '(' + ::std::to_string(f.x) + ", " + ::std::to_string(f.y) + ')';
  }

  template <typename T>
  struct hash<::tools::vector2<T>> {
    using result_type = ::std::size_t;
    using argument_type = ::tools::vector2<T>;
    ::std::size_t operator()(const ::tools::vector2<T>& key) const {
      static const ::std::hash<T> hash;
      static const ::std::size_t shift = ::std::numeric_limits<::std::size_t>::digits / 2;
      const ::std::size_t hash_x = hash(key.x);
      const ::std::size_t hash_y = hash(key.y);
      return hash_x ^ ::tools::rotate_left(hash_y, shift);
    }
  };

  template <typename T>
  ::std::ostream& operator<<(::std::ostream& os, const ::tools::vector2<T>& self) {
    return os << ::std::to_string(self);
  }

  template <typename T>
  ::std::istream& operator>>(::std::istream& is, ::tools::vector2<T>& self) {
    return is >> self.x >> self.y;
  }
}

#endif

// main.cpp

int main() {
  i64 H, W;
  std::cin >> H >> W;
  tools::vector2<i64> C;
  {
    i64 C_h, C_w;
    std::cin >> C_h >> C_w;
    C.x = C_w - 1;
    C.y = C_h - 1;
  }
  tools::vector2<i64> D;
  {
    i64 D_h, D_w;
    std::cin >> D_h >> D_w;
    D.x = D_w - 1;
    D.y = D_h - 1;
  }
  std::vector<std::string> S;
  tools::read(S, H);

  std::vector<std::vector<i64>> components(H, std::vector<i64>(W, -1));
  i64 component_count;
  {
    std::unordered_set<tools::vector2<i64>> unvisited;
    for (i64 y = 0; y < H; ++y) {
      for (i64 x = 0; x < W; ++x) {
        if (S[y][x] == '.') {
          unvisited.emplace(x, y);
        }
      }
    }
    i64 component_id = 0;
    while (!unvisited.empty()) {
      std::queue<tools::vector2<i64>> queue;
      components[unvisited.begin()->y][unvisited.begin()->x] = component_id;
      queue.push(*unvisited.begin());
      while (!queue.empty()) {
        const tools::vector2<i64> curr = queue.front();
        queue.pop();
        unvisited.erase(curr);
        for (const tools::vector2<i64>& direction : tools::vector2<i64>::four_directions()) {
          const tools::vector2<i64> next = curr + direction;
          if (0 <= next.y && next.y < H && 0 <= next.x && next.x < W && components[next.y][next.x] == -1 && S[next.y][next.x] == '.') {
            components[next.y][next.x] = component_id;
            queue.push(next);
          }
        }
      }
      ++component_id;
    }
    component_count = component_id;
  }

  std::vector<std::unordered_set<i64>> graph(component_count);
  for (i64 y = 0; y < H; ++y) {
    for (i64 x = 0; x < W; ++x) {
      for (i64 dy = -2; dy <= 2; ++dy) {
        for (i64 dx = -2; dx <= 2; ++dx) {
          if (0 <= y + dy && y + dy < H && 0 <= x + dx && x + dx < W && components[y][x] != -1 && components[y + dy][x + dx] != -1 && components[y + dy][x + dx] != components[y][x]) {
            graph[components[y][x]].insert(components[y + dy][x + dx]);
          }
        }
      }
    }
  }

  std::vector<i64> distances(component_count, std::numeric_limits<i64>::max());
  {
    distances[components[C.y][C.x]] = 0;
    std::queue<i64> queue({components[C.y][C.x]});
    while (!queue.empty()) {
      const i64 curr = queue.front();
      queue.pop();
      for (const i64& next : graph[curr]) {
        if (distances[next] == std::numeric_limits<i64>::max()) {
          distances[next] = distances[curr] + 1;
          queue.push(next);
        }
      }
    }
  }

  std::cout << (distances[components[D.y][D.x]] == std::numeric_limits<i64>::max() ? -1 : distances[components[D.y][D.x]]) << std::endl;
  return 0;
}

Measured memory_bytes: 39708