//
//  main.cpp
//

#include <algorithm>
#include <array>
#include <assert.h>
#include <complex>
#include <iomanip>
#include <iostream>
#include <limits>
#include <inttypes.h>
#include <map>
#include <math.h>
#include <memory>
#include <memory>
#include <queue>
#include <random>
#include <set>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>

using namespace std;

using ll = int64_t;
using ull = uint64_t;

[[maybe_unused]] constexpr ll LL_MAX = numeric_limits<ll>::max();
[[maybe_unused]] constexpr ll LL_MIN = numeric_limits<ll>::min();
[[maybe_unused]] constexpr ull ULL_MAX = numeric_limits<ull>::max();

#define rep(i, a, b) for (ll i = (a); i < (b); i++)
#define rrep(i, a, b) for (ll i = (a)-1; i >= (b); i--)

template<typename T>
void chmin(T& x, T y) {
	x = min(x, y);
}

template<typename T>
void chmax(T& x, T y) {
	x = max(x, y);
}

ll csum(ll x, ll y) {
	if (x > 0 && y > 0 && x > LL_MAX - y) {
		return LL_MAX;
	}
	if (x < 0 && y < 0 && x < LL_MIN - y) {
		return LL_MIN;
	}
	return x + y;
}

ll readi() {
	ll ret;
	scanf("%" PRId64 "", &ret);
	return ret;
}

vector<ll> readvi(ll n) {
	vector<ll> ret(n);
	rep(i, 0, n) { ret[i] = readi(); }
	return ret;
}

string reads() {
	string s;
	//getline(cin, s);
	cin >> s;
	return s;
}

void writei(ll x) {
	printf("%" PRId64 "\n", x);
}

void writevi(const vector<ll>& xs) {
    rep(i,0,xs.size()) {
        if (i < xs.size() - 1) {
            printf("%" PRId64 " ", xs[i]);
        } else {
            printf("%" PRId64 "\n", xs[i]);
        }
    }
}

template<typename T>
vector<T> make_vec_nd(T init, ll size) {
	return vector<T>(size, init);
}
template<typename T, typename... Args>
auto make_vec_nd(T init, ll size, Args... rest) {
	auto inner = make_vec_nd(init, rest...);
	return vector<decltype(inner)>(size, inner);
}

struct ListCostGraph {
	struct Edge {
		ll from;
		ll to;
		ll cost;
	};
	vector<vector<Edge>> edges;
 
	ListCostGraph(ll size) { edges.resize(size); }
 
	void add_edge(ll from, ll to, ll cost) {
		edges[from].push_back(Edge{from, to, cost});
	}
 
	void add_edge_bidir(size_t a, size_t b, ll cost) {
		add_edge(a, b, cost);
		add_edge(b, a, cost);
	}
 
	vector<ll> dijkstra(ll s) {
		// O(E logV)
		vector<ll> dist(edges.size(), numeric_limits<ll>::max());
		struct P {
			size_t vertex;
			ll distance;
			P(size_t vertex, ll distance)
			: vertex(vertex)
			, distance(distance) {}
		};
		auto compare = [](const P& lhs, const P& rhs) {
			return lhs.distance > rhs.distance;
		};
		priority_queue<P, vector<P>, decltype(compare)> que(compare);
		dist[s] = 0;
		que.push(P(s, 0));
		while (!que.empty()) {
			P p = que.top();
			que.pop();
			size_t v = p.vertex;
			ll d = p.distance;
			if (dist[v] < d) {
				continue;
			}
			for (int i = 0; i < edges[v].size(); i++) {
				const Edge& e = edges[v][i];
				ll new_dist = dist[v] + e.cost;
				if (dist[e.to] <= new_dist) {	 // eを使っても最短経路が改善しないとき
					continue;
				}
				dist[e.to] = new_dist;
				que.push(P(e.to, new_dist));
			}
		}
		return dist;
	}
};

struct P {
	ll x;
	ll y;
};

vector<vector<bool>> is_wall;
vector<vector<ll>> group;
ll W;
ll H;

void dfs(P pos, ll grp_id) {
	if (group[pos.x][pos.y] >= 0) {
		return;
	}
	group[pos.x][pos.y] = grp_id;
	static const vector<P> vecs = {{-1,0},{1,0},{0,-1},{0,1}};
	for (const P& v : vecs) {
		P next = {pos.x + v.x, pos.y + v.y};
		if (!(0 <= next.x && next.x < W && 0 <= next.y && next.y < H)) {
			continue;
		}
		if (is_wall[next.x][next.y]) {
			continue;
		}
		dfs(next, grp_id);
	}
}

int main() {
	H = readi();
	W = readi();
	P start;
	start.y = readi() - 1;
	start.x = readi() - 1;
	P end;
	end.y = readi() - 1;
	end.x = readi() - 1;
	is_wall = make_vec_nd(false, W, H);
	rep(y,0,H) {
		auto line = reads();
		rep(x,0,W) {
			is_wall[x][y] = line[x] == '#';
		}
	}
	group = make_vec_nd((ll)-1, W, H);
	ll grp_id = 0;
	rep(x,0,W) rep(y,0,H) {
		P pos = {x,y};
		if (is_wall[x][y]) {
			continue;
		}
		if (group[x][y] >= 0) {
			continue;
		}
		dfs(pos, grp_id++);
	}
/*
	rep(y,0,H) {
		rep(x,0,W) {
			printf("%d ", group[x][y]);
		}
		printf("\n");
	}
*/
	unordered_set<ull> connected;
	auto encode_pair = [](ll x, ll y){
		if (x > y) {
			swap(x,y);
		}
		ull code = ((ull)x << 32) | (ull)y;
		return code;
	};
	ListCostGraph graph(grp_id);
	rep(x,0,W) rep(y,0,H) {
		if (is_wall[x][y]) {
			continue;
		}
		rep(dx,-2,3) rep(dy,-2,3) {
			P pos = {x + dx, y + dy};
			if (!(0 <= pos.x && pos.x < W && 0 <= pos.y && pos.y < H)) {
				continue;
			}
			if (x == 0 && y == 0) {
				continue;
			}
			if (is_wall[pos.x][pos.y]) {
				continue;
			}
			ll from = group[x][y];
			ll to = group[pos.x][pos.y];
			if (connected.count(encode_pair(from, to))) {
				continue;
			}
			connected.insert(encode_pair(from, to));
			graph.add_edge_bidir(from, to, 1);
		}
	}
	ll start_grp = group[start.x][start.y];
	ll end_grp = group[end.x][end.y];
	ll dist = graph.dijkstra(start_grp)[end_grp];
	if (dist == LL_MAX) {
		writei(-1);
	} else {
		writei(dist);
	}
}


Measured memory_bytes: 49432