#define _CRT_SECURE_NO_DEPRECATE
#pragma GCC optimize("O3")
#pragma GCC target("sse4")
#include "bits/stdc++.h"
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
//using namespace __gnu_pbds;
#define int long long int
#define SYNC std::ios_base::sync_with_stdio(0);cin.tie(NULL);cout.tie(NULL);
#define FRE freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
typedef long double ld;
typedef pair<int,int> ii;
typedef pair<int,ii> iii;
typedef vector<int> vi;
typedef vector<ii>   vii;
//typedef tree<int, null_type, less<int>, rb_tree_tag, 
//             tree_order_statistics_node_update> 
//    ost;
#define rep(i,l,r)   for (int i = (l); i < (r); i++)
#define here cout << " Hey!!\n";
#define  pb push_back
#define  F  first
#define  S  second
#define all(v) (v).begin(),(v).end()
#define sz(a) (int)((a).size())
#define sq(x) ((x)*(x))
template <typename T>
void etch(T V) {
	for (auto x : V)	cout << x << ' ' ;
	cout << '\n';
}
vector<string> vec_splitter(string s) {
	s += ',';
	vector<string> res;
	while(!s.empty()) {
		res.push_back(s.substr(0, s.find(',')));
		s = s.substr(s.find(',') + 1);
	}
	return res;
}
void debug_out(
vector<string> __attribute__ ((unused)) args,
__attribute__ ((unused)) int idx, 
__attribute__ ((unused)) int LINE_NUM) { cerr << endl; } 
template <typename Head, typename... Tail>
void debug_out(vector<string> args, int idx, int LINE_NUM, Head H, Tail... T) {
	if(idx > 0) cerr << ", "; else cerr << "Line(" << LINE_NUM << ") ";
	stringstream ss; ss << H;
	cerr << args[idx] << " = " << ss.str();
	debug_out(args, idx + 1, LINE_NUM, T...);
}
#ifndef ONLINE_JUDGE
#define debug(...) debug_out(vec_splitter(#__VA_ARGS__), 0, __LINE__, __VA_ARGS__)
#else
#define debug(...) 42
#endif
const int MOD = 1e9+7;
const int MOD1 = 998244353;
const int N = 2e5+5;
const int INF = 1000111000111000111LL;
const ld EPS = 1e-12;
const ld PI = 3.141592653589793116;
int grid[1005][1005];
int dp[1005][1005];
multiset<pair<int, pair<int, int>>> st;
int h, w; 
int sx, sy, fx, fy;
int dx[] = {0, 1, 0, -1};
int dy[] = {1, 0, -1, 0};
bool is_safe(int i, int j) {
	return (i >=1 && j >= 1 && i <= h && j <= w && (grid[i][j] == 0));
}
int32_t main()
{
	SYNC
	cin >> h >> w;
	cin >> sx >> sy >> fx >> fy;
	rep(i,1,h+1) {
		rep(j,1,w+1) {
			char ch; cin >> ch;
			if (ch == '#')	grid[i][j] = 1;
		}
	}
	// rep(i,1,h+1) {
	// 	rep(j,1,w+1) {
	// 		cout << grid[i][j];
	// 	}cout << '\n';
	// }
	rep(i,0,1005) {
		rep(j,0,1005)	dp[i][j] = INF;
	}
	dp[sx][sy] = 0;
	st.insert({0, {sx, sy}});
	while (sz(st) > 0) {
		pair<int, pair<int, int>> pp = *st.begin();
		st.erase(st.find(pp));
		ii node = pp.S;
		int len = pp.F;
		//debug(node.F, node.S, len);
		if (dp[node.F][node.S] < len) continue;
		rep(k,0,4) {
			int tx = node.F+dx[k], ty = node.S+dy[k];
			if (is_safe(tx,ty) && len < dp[tx][ty]) {
				if (st.find({dp[tx][ty], {tx, ty}}) != st.end()) {
					st.erase(st.find({dp[tx][ty], {tx, ty}}));
				}
				dp[tx][ty] = len;
				st.insert({dp[tx][ty], {tx, ty}});
			}
		}
		for (int x = -2; x <= 2; x++) {
			for (int y = -2; y <= 2; y++) {
				int tx = node.F+x, ty = node.S+y;
				if (is_safe(tx, ty) && len+1 < dp[tx][ty]) {
					if (st.find({dp[tx][ty], {tx, ty}}) != st.end()) {
						st.erase(st.find({dp[tx][ty], {tx, ty}}));
					}
					dp[tx][ty] = len+1;
					st.insert({dp[tx][ty], {tx, ty}});
				}
			}
		}
	}
	if (dp[fx][fy] == INF)	dp[fx][fy] = -1;
	cout << dp[fx][fy];
	return 0;
}

Measured memory_bytes: 19588