#![allow(non_snake_case)]
#![allow(unused_imports)]
#![allow(dead_code)]
 
use proconio::{input, fastout};
use proconio::marker::*;
use whiteread::parse_line;
use std::collections::*;
use num::*;
use num_traits::*;
use superslice::*;
use std::ops::*;
 
use itertools::Itertools;
use itertools_num::ItertoolsNum;

struct Graph {
    graph: Vec<Vec<char>>,
    queue: VecDeque<(usize, usize)>,
    dist: Vec<Vec<isize>>,
}

impl Graph {
    fn new(graph: Vec<Vec<char>>) -> Self {
        let height = graph.len();
        let width = graph[0].len();
        Graph {
            graph: graph,
            queue: VecDeque::new(),
            dist: vec![vec![-1; width]; height]
        }
    }

    fn bfs(&mut self, start: (usize, usize)) {
        let dx = vec![0, 0, 1, -1];
        let dy = vec![1, -1, 0, 0];
        let height = self.graph.len();
        let width = self.graph[0].len();
        let mut cost = 0;
        let mut visited: Vec<(usize, usize)> = Vec::new();

        self.queue.push_back(start);
        visited.push(start);
        self.dist[start.1][start.0] = 0;

        loop {
            // println!("{:?}", self.queue);
            if self.queue.is_empty() {
                break;
            }

            let (c_x, c_y): (usize, usize) = self.queue.pop_front().unwrap();
            visited.push((c_x, c_y));

            for i in 0..4 {
                let next_x = c_x as isize + dx[i];
                let next_y = c_y as isize + dy[i];
                
                if next_x < 0 || next_y < 0 || next_x >= width as isize || next_y >= height as isize { continue }
                let next_x = next_x as usize;
                let next_y = next_y as usize;
                // println!("nx: {} ny: {}", next_x, next_y);
                if self.graph[next_y][next_x] == '#' { continue }

                if self.dist[next_y][next_x] == -1 {
                    self.queue.push_back((next_x, next_y));
                    
                    self.dist[next_y][next_x] = cost;
                }
            }

            if self.queue.is_empty() {
                cost += 1;
                for (x, y) in visited.into_iter() {
                    if self.dist[y][x] != cost - 1 || self.graph[y][x] == '#' { continue; }
                    for ddx in -2..=2 {
                        for ddy in -2..=2 {
                            let next_x = x as isize + ddx;
                            let next_y = y as isize + ddy;
    
                            if next_x < 0 || next_y < 0 || next_x >= width as isize || next_y >= height as isize { continue }
                            let next_x = next_x as usize;
                            let next_y = next_y as usize;
                            // println!("nx: {} ny: {}", next_x, next_y);
                            if self.graph[next_y][next_x] == '#' { continue }
            
                            if self.dist[next_y][next_x] == -1 {
                                self.queue.push_back((next_x, next_y));
                                self.dist[next_y][next_x] = cost;
                            }
                        }
                    }
                }
                visited = Vec::new();
            }
        }
    }

    fn print(&self) {
        for g in self.dist.iter() {
            println!("{:?}", g)
        }
    }
}


#[fastout]
fn solve() {
    const MOD: usize = 1_000_000_007;
    const INF: usize = std::usize::MAX;

    input!{
        h: usize, _w: usize,
        ch: usize, cw: usize, dh: usize, dw: usize,
        s_vec: [Chars; h],
    }

    let mut g = Graph::new(s_vec);
    // dbg!(&g.graph);
    g.bfs((cw-1, ch-1));
    
    // println!("dw: {} dh: {}", dw - 1, dh - 1);
    // g.print();

    println!("{}", g.dist[dh-1][dw-1])
}

fn main() {
    solve();
}


Measured memory_bytes: 15100