Problem:
Score : 400 points

Problem Statement

A maze is composed of a grid of H \times W squares - H vertical, W horizontal.

The square at the i-th row from the top and the j-th column from the left - (i,j) - is a wall if S_{ij} is # and a road if S_{ij} is ..

There is a magician in (C_h,C_w). He can do the following two kinds of moves:

Move A: Walk to a road square that is vertically or horizontally adjacent to the square he is currently in.

Move B: Use magic to warp himself to a road square in the 5\times 5 area centered at the square he is currently in.

In either case, he cannot go out of the maze.

At least how many times does he need to use the magic to reach (D_h, D_w)?

Constraints

1 \leq H,W \leq 10^3

1 \leq C_h,D_h \leq H

1 \leq C_w,D_w \leq W

S_{ij} is # or ..

S_{C_h C_w} and S_{D_h D_w} are ..

(C_h,C_w) \neq (D_h,D_w)

Input

Input is given from Standard Input in the following format:

H W
C_h C_w
D_h D_w
S_{11}\ldots S_{1W}
\vdots
S_{H1}\ldots S_{HW}

Output

Print the minimum number of times the magician needs to use the magic. If he cannot reach (D_h,D_w), print -1 instead.

Sample Input 1

4 4
1 1
4 4
..#.
..#.
.#..
.#..

Sample Output 1

1

For example, by walking to (2,2) and then using the magic to travel to (4,4), just one use of magic is enough.

Note that he cannot walk diagonally.

Sample Input 2

4 4
1 4
4 1
.##.
####
####
.##.

Sample Output 2

-1

He cannot move from there.

Sample Input 3

4 4
2 2
3 3
....
....
....
....

Sample Output 3

0

No use of magic is needed.

Sample Input 4

4 5
1 2
2 5
#.###
####.
#..##
#..##

Sample Output 4

2

Solution in Rust (1.42.0) (judge verdict: Time Limit Exceeded)

#![allow(unused_imports)]

// language: Rust(1.42.0)
// check available crates on AtCoder at "https://atcoder.jp/contests/language-test-202001"
// My Library Repositry is at "https://github.com/Loptall/sfcpl"

/*
    水コーダーになれてうれしいです
*/

// from std...
use std::cmp::{
    max, min, Ordering,
    Ordering::{Equal, Greater, Less},
    Reverse,
};
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
use std::convert::TryInto;
use std::fmt;
use std::mem::swap;
use std::num::{NonZeroU32, ParseIntError};
use std::ops::{
    Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
    Index, IndexMut, Mul, MulAssign, Neg, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub,
    SubAssign,
};
use std::process::exit;
use std::{f32, f64, i128, i16, i32, i64, i8, isize, u128, u16, u32, u64, u8, usize};

// Dep' crates are...
use itertools::*;
use itertools_num::*;
use lazy_static::lazy_static;
use maplit::{btreemap, btreeset, hashmap, hashset};
use num_bigint::{BigInt, BigUint};
use num_complex::Complex;
use num_integer::{binomial, gcd, lcm, multinomial, Integer};
use num_rational::Rational;
use num_traits::{
    clamp, one, pow, zero, Num, NumAssignOps, NumOps, One, Pow, Signed, Unsigned, Zero,
};
use permutohedron::Heap;
use proconio::{
    derive_readable, fastout, input, is_stdin_empty,
    marker::{Bytes, Chars, Isize1, Usize1},
};
use rand::random;

pub trait Visualize {
    fn visualize(&self, split: &str);
    fn continuous(&self) {
        self.visualize("");
    }
    fn spaces(&self) {
        self.visualize(" ");
    }
    fn lines(&self) {
        self.visualize("\n");
    }
}
macro_rules! impl_vis_for_sized {
    ($($t:ty),+) => {
        $(
            impl Visualize for $t {
                fn visualize(&self, _split: &str) {
                    print!("{}", self);
                }
            }
        )+
    };
}
impl_vis_for_sized! {
    usize, u8, u16, u32, u64, u128,
    isize, i8, i16, i32, i64, i128,
    f64, f32,
    String, &str, char
}
impl<T: fmt::Display> Visualize for [T] {
    fn visualize(&self, split: &str) {
        print!("{}", self.iter().join(split));
    }
}
#[macro_export]
macro_rules! vis {
    // end
    () => {
        println!();
    };

    // last element + trailing pattern
    ($last:expr ;) => {
        $last.lines();
        vis!()
    };
    ($last:expr =>) => {
        $last.continuous();
        vis!();
    };
    ($last:expr $(,)?) => {
        $last.spaces();
        vis!();
    };

    // get first element and pass rest
    ($first:expr; $($rest:tt)*) => {
        $first.lines();
        println!();
        vis!($($rest)*);
    };
    ($first:expr => $($rest:tt)*) => {
        $first.continuous();
        vis!($($rest)*);
    };
    ($first:expr, $($rest:tt)*) => {
        $first.spaces();
        print!(" ");
        vis!($($rest)*);
    };
}
pub const MOD10E9_7: usize = 1000000007; // 10 ^ 9 + 7
pub const MOD99_: usize = 998244353;
pub const MAX: usize = std::usize::MAX; // = 2 ^ 64 - 1 = 18446744073709551615 ≈ 1.8 * 10 ^ 19
pub const INF: usize = 2000000000000000000; // MAX / 9 < 2 * 10e18 < MAX / 10
pub const FNI: i64 = -2000000000000000000; // == -(INF as i64)
pub const PI: f64 = f64::consts::PI; // 3.141592653589793 -- 10 ^ -15
pub const ASCII_A_LARGE: u8 = 65;
pub const ASCII_A_SMALL: u8 = 97;
pub const ASCII_0: u8 = 48;
pub const ADJ4: &[(isize, isize); 4] = &[(1, 0), (0, 1), (-1, 0), (0, -1)];
pub const ADJ8: &[(isize, isize); 8] = &[
    (1, 0),
    (1, 1),
    (0, 1),
    (-1, 1),
    (-1, 0),
    (-1, -1),
    (0, -1),
    (1, -1),
];

type Idx2D = (usize, usize);

const N4: [(isize, isize); 4] = [(1, 0), (0, 1), (-1, 0), (0, -1)];
const N8: [(isize, isize); 8] = [
    (1, 0),
    (1, 1),
    (0, 1),
    (-1, 1),
    (-1, 0),
    (-1, -1),
    (0, -1),
    (1, -1),
];

#[derive(Debug, Clone)]
pub struct Grid<'a> {
    h: usize,
    w: usize,
    board: &'a Vec<Vec<char>>,
    wall: HashSet<char>,
}

impl<'a> Grid<'a> {
    pub fn new(board: &'a Vec<Vec<char>>, wall: Vec<char>) -> Self {
        Self {
            h: board.len(),
            w: board[0].len(),
            board,
            wall: wall.into_iter().collect(),
        }
    }

    pub fn height(&self) -> usize {
        self.h
    }

    pub fn width(&self) -> usize {
        self.w
    }

    pub fn index(&self, idx: Idx2D) -> char {
        self.board[idx.0][idx.1]
    }

    pub fn is_passable(&self, idx: Idx2D) -> bool {
        !self.wall.contains(&self.index(idx))
    }

    pub fn neighbor4(&self, idx: Idx2D) -> impl Iterator<Item = Idx2D> {
        let mut res = Vec::new();
        for &(x, y) in N4.iter() {
            let idx = ((idx.0 as isize) + x, (idx.1 as isize) + y);
            if idx.0 < 0
                || idx.0 >= self.height() as isize
                || idx.1 < 0
                || idx.1 >= self.width() as isize
            {
                continue;
            }
            res.push((idx.0 as usize, idx.1 as usize));
        }
        res.into_iter()
    }

    pub fn neighbor8(&self, idx: Idx2D) -> impl Iterator<Item = Idx2D> {
        let mut res = Vec::new();
        for &(x, y) in N8.iter() {
            let idx = ((idx.0 as isize) + x, (idx.1 as isize) + y);
            if idx.0 < 0
                || idx.0 >= self.height() as isize
                || idx.1 < 0
                || idx.1 >= self.width() as isize
            {
                continue;
            }
            let idx = (idx.0 as usize, idx.1 as usize);
            if self.is_passable(idx) {
                res.push(idx);
            }
        }
        res.into_iter()
    }

    pub fn find(&self, c: char) -> Option<Idx2D> {
        for i in 0..self.height() {
            for j in 0..self.width() {
                if self.index((i, j)) == c {
                    return Some((i, j));
                }
            }
        }
        None
    }

    pub fn rfind(&self, c: char) -> Option<Idx2D> {
        for i in (0..self.height()).rev() {
            for j in (0..self.width()).rev() {
                if self.index((i, j)) == c {
                    return Some((i, j));
                }
            }
        }
        None
    }
}

pub struct Dfs<'a> {
    visited: Vec<Vec<bool>>,
    s: Vec<(Idx2D, Option<Idx2D>)>,
    g: &'a Grid<'a>,
}

impl<'a> Iterator for Dfs<'a> {
    type Item = (Idx2D, Idx2D);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((u, prev)) = self.s.pop() {
            if !self.g.is_passable(u) {
                return self.next();
            }

            for v in self.g.neighbor4(u) {
                if !self.visited[v.0][v.1] {
                    self.visited[v.0][v.1] = true;
                    self.s.push((v, Some(u)));
                }
            }

            if let Some(prev) = prev {
                Some((prev, u))
            } else {
                self.next()
            }
        } else {
            None
        }
    }
}

pub fn dfs<'a>(g: &'a Grid, start: Idx2D) -> Dfs<'a> {
    let mut visited = vec![vec![false; g.width()]; g.height()];
    visited[start.0][start.1] = true;
    let mut s = Vec::new();
    s.push((start, None));
    Dfs { visited, s, g }
}

pub trait Graph<'a> {
    type NodeId: Copy;
    type Iter: Iterator<Item = Self::NodeId>;
    fn len(&self) -> usize;
    fn is_empty(&self) -> bool;
    fn index(&self, i: Self::NodeId) -> usize;
    fn neighbors(&'a self, i: Self::NodeId) -> Self::Iter;
}
/// 重みなしグラフ
pub type UnweightedGraph = Vec<Vec<usize>>;
impl<'a> Graph<'a> for UnweightedGraph {
    type NodeId = usize;
    type Iter = std::iter::Cloned<std::slice::Iter<'a, Self::NodeId>>;
    fn len(&self) -> usize {
        self.len()
    }
    fn is_empty(&self) -> bool {
        self.len() == 0
    }
    fn index(&self, a: Self::NodeId) -> usize {
        a
    }
    fn neighbors(&'a self, a: Self::NodeId) -> Self::Iter {
        self[a].iter().cloned()
    }
}
/// 重みありグラフ
pub type WeightedNodeGraph<W> = Vec<Vec<(usize, W)>>;
impl<'a, W> Graph<'a> for WeightedNodeGraph<W>
where
    W: std::marker::Copy + Clone + 'a,
{
    type NodeId = (usize, W);
    type Iter = std::iter::Cloned<std::slice::Iter<'a, Self::NodeId>>;
    fn len(&self) -> usize {
        self.len()
    }
    fn is_empty(&self) -> bool {
        self.len() == 0
    }
    fn index(&self, a: Self::NodeId) -> usize {
        a.0
    }
    fn neighbors(&'a self, a: Self::NodeId) -> Self::Iter {
        self[a.0].iter().cloned()
    }
}
/// 重みなし有向グラフ
pub fn make_directed_graph(n: usize, edges: &[(usize, usize)]) -> UnweightedGraph {
    let mut g = vec![vec![]; n];
    for &(u, v) in edges.iter() {
        g[u].push(v);
    }
    g
}
/// 重みなし無向グラフ
pub fn make_undirected_graph(n: usize, edges: &[(usize, usize)]) -> UnweightedGraph {
    let mut g = vec![vec![]; n];
    for &(u, v) in edges.iter() {
        g[u].push(v);
        g[v].push(u);
    }
    g
}
/// 重み付き有向グラフ
pub fn make_weighted_directed_graph<W: Clone>(
    n: usize,
    edges: &[(usize, usize, W)],
) -> WeightedNodeGraph<W> {
    let mut g = vec![vec![]; n];
    for &(u, v, ref w) in edges.iter() {
        g[u].push((v, w.clone()));
    }
    g
}
/// 重み付き無向グラフ
pub fn make_weighted_undirected_graph<W: Clone>(
    n: usize,
    edges: &[(usize, usize, W)],
) -> WeightedNodeGraph<W> {
    let mut g = vec![vec![]; n];
    for &(u, v, ref w) in edges.iter() {
        g[u].push((v, w.clone()));
        g[v].push((u, w.clone()));
    }
    g
}

/// 重みなしグラフにおいて、幅優先探索を用いて任意の頂点から、各頂点への最短距離を求める
/// dist[i] = (startからiまでの最短距離)
pub fn dist_table<'a, G>(g: &'a G, start: G::NodeId) -> Vec<usize>
where
    G: Graph<'a, NodeId = usize>,
{
    let mut dist = vec![std::usize::MAX; g.len()];
    dist[start] = 0;
    for (f, t) in bfs(g, start) {
        dist[t] = dist[f] + 1;
    }
    dist
}
/// 重みなしグラフでの2頂点の最短距離を幅優先探索で求める
/// goalまでの経路が見つかった時点で探索を打ち切るので、
/// グラフのサイズの大きさに直接の影響を受けないことが期待される
pub fn shortest_path<'a, G: Graph<'a, NodeId = usize>>(
    g: &'a G,
    start: usize,
    goal: usize,
) -> usize {
    let mut dist = vec![std::usize::MAX; g.len()];
    dist[start] = 0;
    for (f, t) in bfs(g, start) {
        if t == goal {
            return dist[f] + 1;
        }
        dist[t] = dist[f] + 1;
    }
    std::usize::MAX
}
pub struct Bfs<'a, G: Graph<'a>> {
    visited: Vec<bool>,
    q: VecDeque<(G::NodeId, Option<G::NodeId>)>,
    g: &'a G,
}
impl<'a, G: Graph<'a>> Iterator for Bfs<'a, G> {
    type Item = (G::NodeId, G::NodeId);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((u, prev)) = self.q.pop_front() {
            for v in self.g.neighbors(u) {
                if !self.visited[self.g.index(v)] {
                    self.visited[self.g.index(v)] = true;
                    self.q.push_back((v, Some(u)));
                }
            }
            if let Some(prev) = prev {
                Some((prev, u))
            } else {
                self.next()
            }
        } else {
            None
        }
    }
}
/// `start`の頂点からの幅優先探索時の、
/// 頂点から頂点の接続をイテレートするIteratorを作る
/// ```rust
/// use sfcpl::graph::{util::make_undirected_graph, bfs::bfs};
/// let e = &[(0, 2), (0, 1), (1, 2), (2, 3), (3, 4), (3, 5), (1, 5)];
/// let g = make_undirected_graph(6, e);
/// for (f, t) in bfs(&g, 0) {
///     println!("{} -> {}", f, t);
/// }
/// ```
/// これは
/// `0 -> 2`
/// `0 -> 1`
/// `2 -> 3`
/// `1 -> 5`
/// `3 -> 4`
/// を表示する
pub fn bfs<'a, G>(g: &'a G, start: G::NodeId) -> Bfs<'a, G>
where
    G: Graph<'a, NodeId = usize>,
{
    let n = g.len();
    let mut visited = vec![false; n];
    let mut q = VecDeque::new();
    visited[start] = true;
    q.push_back((start, None));
    Bfs { visited, q, g }
}

// code...
// #[fastout]
fn main() {
    input! {
        h: usize, w: usize,
        start: (Usize1, Usize1),
        goal: (Usize1, Usize1),
        board: [Chars; h]
    }

    let g = Grid::new(&board, vec!['#']);
    let mut used = vec![vec![false; w]; h];

    let mut colored = vec![vec![INF; w]; h];

    let mut c = 0;
    for i in 0..h {
        for j in 0..w {
            if g.is_passable((i, j)) && !used[i][j] {
                used[i][j] = true;
                colored[i][j] = c;
                let mut con = vec![(i, j)];
                for (_, b) in dfs(&g, (i, j)) {
                    used[b.0][b.1] = true;
                    colored[b.0][b.1] = c;
                    con.push(b);
                }
                c += 1;
            }
        }
    }

    let mut g = vec![Vec::new(); c];

    for i in 0..h {
        for j in 0..w {
            if colored[i][j] < INF {
                for a in i.saturating_sub(2)..=min(i + 2, h - 1) {
                    for b in j.saturating_sub(2)..=min(j + 2, w - 1) {
                        if colored[i][j] == colored[a][b] || colored[a][b] == INF {
                            continue;
                        }

                        g[colored[i][j]].push(colored[a][b]);
                        g[colored[a][b]].push(colored[i][j]);
                    }
                }
            }
        }
    }

    let mut ans = shortest_path(&g, colored[start.0][start.1], colored[goal.0][goal.1]);
    if colored[start.0][start.1] == colored[goal.0][goal.1] {
        ans = 0;
    }

    if ans > INF {
        vis!(-1);
        return;
    }
    vis!(ans);
}