//  [rust]

use std::io::*;
use std::str::*;
use std::collections::VecDeque;

fn read<T: FromStr>(s: &mut StdinLock) -> T {
    let s = s.by_ref().bytes().map(|c| c.unwrap() as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect::<String>();
    s.parse::<T>().ok().unwrap()
}

const  STEP0: &[(i32, i32);4] = &[ (-1, 0), (1, 0), (0, -1), (0, 1),];

const  STEP1: &[(i32, i32); 20] =  
				&[ (-2, -2), (-1, -2), (0, -2), (1, -2), (2, -2),
				   (-2, -1), (-1, -1),          (1, -1), (2, -1),
				   (-2,  0),                             (2,  0),
				   (-2,  1), (-1,  1),          (1,  1), (2,  1),
				   (-2,  2), (-1,  2), (0,  2), (1,  2), (2,  2),];

fn main() {

	let s = stdin();
	let mut s  = s.lock();
	let s =  &mut s;

	struct Param {
		h :i32,
		w :i32,
		starty :i32,
		startx :i32,
		endy: i32,
		endx: i32,
		arr: Vec<u8>,
		steps: Vec<i32>,
	}

	let mut work = Param {
		h:  read::<i32>(s),
		w:  read::<i32>(s),
		starty: read::<i32>(s) - 1,
		startx: read::<i32>(s) - 1,
		endy: read::<i32>(s) - 1,
		endx: read::<i32>(s) - 1,
		arr:  Vec::<u8>::new(),
	    steps: Vec::<i32>::new(),
	};

	for _y in 0 .. work.h {
		work.arr.extend(read::<String>(s).bytes());
	}

	fn getindex(x: i32, y: i32, w: i32) -> usize {
 		 (y * w + x) as usize
	}

	fn isempty(ctx: &Param, x :i32 , y: i32) -> bool  {
		if x < 0 || x >= ctx.w || y < 0 || y >= ctx.h {
			return false;
		}
		let idx = getindex(x, y, ctx.w);
		let r = ctx.arr[idx] != b'#' && ctx.steps[idx] < 0;
		 return r;
	}


	fn check0(ctx :&mut Param) -> Vec< (i32, i32) >   {
		let mut queue = VecDeque::<(i32, i32)>::new();
		let mut vec0 = Vec::<(i32, i32)>::new();
		if isempty(ctx, ctx.startx, ctx.starty) {
			ctx.steps[getindex(ctx.startx, ctx.starty, ctx.w)] = 0;
	    	queue.push_back((ctx.startx, ctx.starty));
			vec0.push((ctx.startx, ctx.starty));
		}
		loop {
			match queue.pop_front() {
				None => { break; } ,
				Some(p) => {
					ctx.steps[getindex(p.0, p.1, ctx.w)] = 0;
					for ri in 0 .. STEP0.len() {
						let px = p.0  + STEP0[ri].0;
						let py = p.1  + STEP0[ri].1; 
						if isempty(ctx, px, py) {
							ctx.steps[getindex(px, py,ctx.w)] = 0;
					 		queue.push_back( (px, py) );
							vec0.push( (px, py) );
						}
					}
				},
			}
		}
		vec0
	};

	fn check1<'a>(ctx : &mut Param, vec0: &mut Vec<(i32, i32)> )  -> Vec<(i32, i32)> {
		let mut vec1 = Vec::<(i32, i32)>::new();
		for tp in vec0.into_iter() {
			ctx.steps[getindex(tp.0, tp.1, ctx.w)] = 0;
			for ri in 0 .. STEP1.len() {
				let px = tp.0  + STEP1[ri].0;
				let py = tp.1  + STEP1[ri].1;
				if isempty(ctx, px, py) {
					ctx.steps[getindex(px, py, ctx.w)] = 0;
					vec1.push( (px, py) );
				}
			}
		}
		vec1
	};


	fn check2<'a>(ctx : &mut Param, vec0: &mut Vec<(i32, i32)> )  -> Vec<(i32, i32)> {
		let mut queue = VecDeque::<(i32, i32)>::new();
		let mut vec2 = Vec::<(i32, i32)>::new();
		for tp in vec0.into_iter() {
			ctx.steps[getindex(tp.0, tp.1, ctx.w)] = 0;
			vec2.push(*tp);
	    	queue.push_back(*tp);
			loop {
				match queue.pop_front() {
					None => { break; } ,
					Some(p) => {
						ctx.steps[getindex(p.0, p.1, ctx.w)] = 0;
						for ri in 0 .. STEP0.len() {
							let px = p.0  + STEP0[ri].0;
							let py = p.1  + STEP0[ri].1; 
							if isempty(ctx, px, py) {
								ctx.steps[getindex(px, py,ctx.w)] = 0;
						 		queue.push_back( (px, py) );
								vec2.push( (px, py) );
							}
						}
					},
				}
			}
		}
		vec2
	};


	work.steps.resize((work.h * work.w) as usize, -1);


    let mut v = check0(&mut work);
	
	let mut step = 0;

	loop {
		if v.len() == 0 {
			step = -1;
			break;
		}
	 	if v.contains( &(work.endx, work.endy) ) {
			break;
		}
	    v = check1(&mut work,  &mut v) ;
		v = check2(&mut work, &mut v) ;
		//dump1(&v);
		step += 1;
	}
 	println!("{}", step);

}