#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <iterator>
#include <cmath>
#include <set>
#include <deque> 
#include <string>


using namespace std;

struct Point {
	int r, c;
};

Point cPoint;
Point dPoint;

int height, width;

int dr[] = {-1, 0, 0, 1};
int dc[] = { 0,-1, 1, 0};

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

char s[1010][1010];
int b[1010][1010];
int nextBaseNo;

struct Area {
	int id;
	std::set<int> connect;
	bool isVisited;
	int dist;
};

std::vector<Area> areas;

bool inBound(int r, int c) {
	if ((1 <= r) && (r <= height) && (1 <= c) && (c <= width)) {
		return true;
	} else 
		return false;
}

void doFill(int r, int c, int belongsTo) {
	std::queue<Point> q;
	Point curPoint, newPoint;
	curPoint.r = r;
	curPoint.c = c;
	if (inBound(curPoint.r, curPoint.c))
		q.push(curPoint);
	
	while (!q.empty()) {
		curPoint = q.front();
		q.pop();
		b[curPoint.r][curPoint.c] = belongsTo;
		
		for (int d = 0 ; d < 4 ; d++) {
			newPoint.r = curPoint.r + dr[d];
			newPoint.c = curPoint.c + dc[d];
			
			if (inBound(newPoint.r, newPoint.c)) {
				if (b[newPoint.r][newPoint.c] == -2) {
					b[newPoint.r][newPoint.c] = belongsTo;
					q.push(newPoint);
				}
					 
			}
		}
	}
	
	Area newArea;
	newArea.id = belongsTo;
	newArea.connect.clear();
	newArea.dist = -1;
	areas.push_back(newArea);
}

void doExtend(int r, int c) {
	int nr, nc;
	int ba = b[r][c];
	for (int d = 0 ; d < 12 ; d++) {
		nr = r + dm[d][0];
		nc = c + dm[d][1];

		
		if ((b[nr][nc] >= 0) && (b[nr][nc] != ba)) {
			if (inBound(nr, nc)) {
				int bb = b[nr][nc];
				
				areas[ba].connect.insert(bb);
				areas[bb].connect.insert(ba);
				
			}
		}
	}
}

int doBfs(int pStartArea, int pEndArea) {
	if (pStartArea == pEndArea)
		return 0;
	int count;
	std::queue<int> q;
	q.push(pStartArea);
	areas[pStartArea].dist = 0;
	
	int curP, newP;
	while (!q.empty()) {
		curP = q.front();
		q.pop();
		
		int newDist = areas[curP].dist + 1;
		std::set<int>::iterator iConnect;
		for (iConnect = areas[curP].connect.begin() ; 
		    iConnect != areas[curP].connect.end() ;
			iConnect++) {
			newP = *iConnect;
			if ((areas[newP].dist == -1) || (areas[newP].dist > newDist)) {
				areas[newP].dist = newDist;
				q.push(newP);
				
				if (newP == pEndArea) {
					return areas[newP].dist;
				}
			}
			
		}
	}
	
	return -1;
}

int main()
{
	scanf("%d%d\n", &height, &width);
	scanf("%d%d\n", &(cPoint.r), &(cPoint.c));
	scanf("%d%d\n", &(dPoint.r), &(dPoint.c));
	
	nextBaseNo = 0;
	for (int i = 0 ; i < height ; i++) {
		scanf("%s\n", &(s[i]));
		for (int j = 0 ; j < width ; j++) {
			if (s[i][j] == '#') {
				b[i + 1][j + 1] = -1;
				continue;
			} else if (s[i][j] == '.') {
				b[i + 1][j + 1] = -2;
				continue;
			}
		}
	}
	
	nextBaseNo = 0;
	for (int r = 1 ; r <= height ; r++) {
		for (int c = 1 ; c <= width ; c++) {
			if (b[r][c] == -2) {
				doFill(r, c, nextBaseNo);
				nextBaseNo++;
			}
		}
	}
	
	for (int r = 1 ; r <= height ; r++) {
		for (int c = 1 ; c <= width ; c++) {
			if (b[r][c] >= 0) {
				doExtend(r, c);
			}
		}
	}
	
	int startArea = b[cPoint.r][cPoint.c];
	int endArea = b[dPoint.r][dPoint.c];
	
	int count = doBfs(startArea, endArea);
	printf("%d\n", count);
	
	return 0;
}




Measured memory_bytes: 33984