import sys
from io import StringIO
import unittest
import os
from collections import deque

# 再帰処理上限(dfs作成時に設定するのが面倒なので限度近い値を組み込む)
sys.setrecursionlimit(999999999)


# TODO 迷路クラスを作成してみた。これは、共通化しておく必要がある。
# 迷路(2次元)を扱うクラス
# ※3次元の迷路を扱いたい場合、このクラスのインスタンスを複数生成すれば良いはず。
class youk_maze:
    __maze = []
    __wall_str = ""
    __road_str = ""
    __road_s = []  # 座標の一覧(道)
    __wall_s = []  # 座標の一覧(壁)
    __arrived_s = []  # 到達情報(初期値-1；未到達)
    __not_arrived_val = -1  # 到達情報_未到達の初期値

    def __init__(self, maze: [], can_move_out: bool = False, wall_str: str = "#", road_str: str = "."):
        """
        コンストラクタ
        :maze 迷路の情報を保持する2次元配列
        :can_move_out 迷路の外側に出れるか(True:出れる、False:出れない)
        """

        if len(maze) == 0:
            raise ValueError("迷路の情報が設定されていない = len()が0")

        # -----------------
        # 道と壁を表す文字の設定
        # -----------------
        self.__wall_str = wall_str
        self.__road_str = road_str

        # -----------------
        # 迷路の作成(迷路を道or陰で囲む)
        # 目的1:　Atcoderでは座標が「1」始まりで与えられるため、迷路も開始添え字を1にして処理を明瞭にする。
        # 目的2: 迷路の外に出れるパターンの場合、迷路を道で囲む。
        # -----------------
        frame = road_str if can_move_out else wall_str
        # 1行目
        self.__maze = [[frame] + [frame for _ in range(len(list(maze[0])))] + [frame]]
        # 2~最終行手前
        for line in maze:
            self.__maze.append([frame] + line + [frame])
        # 最終行
        self.__maze.append([frame] + [frame for _ in range(len(maze[0]))] + [frame])

        # -----------------
        # 道と壁の一覧をリストにまとめておく
        # -----------------
        self.__road_s = []
        self.__wall_s = []
        for i in range(len(self.__maze)):
            for j in range(len(self.__maze[0])):
                # 自分が壁なら対象外
                if self.__maze[i][j] == self.__wall_str:
                    self.__wall_s.append([i, j])
                elif self.__maze[i][j] == self.__road_str:
                    self.__road_s.append([i, j])

        # -----------------
        # 経路情報を作成する
        # -----------------
        self.reset_arrived()

    def get_road_list(self):
        """
        座標の一覧を取得(道)
        """
        return self.__road_s

    def get_wall_list(self):
        """
        座標の一覧を取得(壁)
        """
        return self.__wall_s

    def get_maze(self):
        """
        迷路情報を返す
        """
        return self.__maze

    def get_arrived_val(self, cell: []):
        return self.__arrived_s[cell[0]][cell[1]]

    def is_arrived(self, cell: []) -> bool:
        """
        指定された座標が到達済みかを返す。(-1：未到達)
        """
        if self.__arrived_s[cell[0]][cell[1]] == self.__not_arrived_val:
            return False
        else:
            return True

    def can_moved(self, cell: [], do_arrive_check: bool = True) -> bool:
        """
        指定された経路に移動できるかを返す。(True:移動可能、False:移動不可)
        """
        # 範囲外には移動できない
        if not 0 <= cell[0] < len(self.__maze) or not 0 <= cell[1] < len(self.__maze[0]):
            return False

        # 壁なら何もしない
        if self.__maze[cell[0]][cell[1]] == self.__wall_str:
            return False

        if not do_arrive_check:
            return True

        # 処理済みなら何もしない(移動したければ編集するといい)
        if self.__arrived_s[cell[0]][cell[1]] != self.__not_arrived_val:
            return False

        return True

    def set_arrived_val(self, cell: [], val):
        """
        指定された経路に到達情報を設定する。
        """
        self.__arrived_s[cell[0]][cell[1]] = val

    def reset_arrived(self):
        """
        経路の到達情報を初期化する。(おそらく、コンストラクタ以外で使うことは無い・・)
        """
        self.__arrived_s = [[self.__not_arrived_val for i in range(len(self.__maze[0]))] for j in
                            range(len(self.__maze))]

    def get1dpoint(self, cell) -> int:
        """
        座標情報を1次元に変換したものを返す。対象を1次元で管理する処理との連携に使用する。(例：UnionFind)
        """
        # 縦座標×縦幅 + 横座標 等式で、座標を一次元配列の添え字に変換する。
        return cell[0] * len(self.__maze[0]) + cell[1]

    def getcellcount(self) -> int:
        """
        座標数を返す(囲み枠を考慮した座標数を返す)
        """
        # 縦座標×縦幅 + 横座標 等式で、座標を一次元配列の添え字に変換する。
        return len(self.__maze) * len(self.__maze[0])

    def debugmazemap(self, custom_list: [] = []) -> str:
        """
        ※デバック用変数※
        迷路の情報と到達リストをテキスト形式で返す(タブ区切り)
        custom_list:
         任意の一次元配列。渡した場合、座標ごとに情報を紐づけしたものを返す。
         ※到達リスト以外のリストを作って何かを管理している場合、渡すと良い。
        """
        ans = ""
        # 迷路の情報
        for i in range(len(self.__maze)):
            ans += "\t".join(self.__maze[i]) + "\n"

        ans += "\n"
        # 到達リスト
        for i in range(len(self.__maze)):
            ans += "\t".join(map(str, self.__arrived_s[i])) + "\n"
        return ans

        # 引数なしなら上記を返して終了。
        if len(custom_list) == 0:
            return

        # 引数として一次元配列を受け取った場合、迷路の各座標と受け取った一次元配列の情報を紐づけして返す。
        ans += "\n"
        for i in range(len(self.__maze)):
            line = ""
            for j in range(len(self.__maze[0])):
                point = self.get1dpoint([i, j])
                line += str(custom_list[point]) + "\t"
            ans += line + "\n"
        return ans


# 実装を行う関数
def resolve(test_def_name=""):
    h, w = map(int, input().split())

    start = list(map(int, input().split()))
    gorl = list(map(int, input().split()))

    maze = youk_maze([list(input()) for i in range(h)])

    # スタート地点の候補を(=道の座標全て)を取得
    start_list = maze.get_road_list()
    que = deque()
    que.extend(start_list)

    # BFS開始
    # 距離でなく、グループ分けを行う
    group_num = 0
    while len(que) is not 0:
        now = que.popleft()

        # 自分が未処理なら、グループ番号を採番し自信をグループに所属させる。
        if not maze.is_arrived(now):
            group_num += 1
            maze.set_arrived_val(now, group_num)

        # 各方向に移動(徒歩)
        for move_h, move_w in [(1, 0), (0, 1), (0, -1), (-1, 0)]:
            target = [now[0] + move_h, now[1] + move_w]
            if not maze.can_moved(target):
                continue

            # 移動可能な場合、自分と同じエリアと判定
            maze.set_arrived_val(target, group_num)
            # キューを追加
            que.appendleft(target)

    move_target_list = [set() for a in range(group_num + 1)]
    # 再度BFS開始
    que.extend(start_list)
    while len(que) is not 0:
        now = que.popleft()

        # 各方向にワープを試してみる
        for i, j in [(-2, -2), (-2, -1), (-2, 0), (-2, 1), (-2, 2), (-1, -2), (-1, -1), (-1, 1), (-1, 2), (0, -2),
                     (0, 2), (1, -2), (1, -1), (1, 1), (1, 2), (2, -2), (2, -1), (2, 0), (2, 1), (2, 2)]:
            # 処理対象の座標
            target = [now[0] + i, now[1] + j]
            if not maze.can_moved(target, do_arrive_check=False):
                continue

            # ワープ前後の座標のエリアが異なる場合のみ、リストに追加。
            if maze.get_arrived_val(now) != maze.get_arrived_val(target):
                move_target_list[maze.get_arrived_val(now)].add(maze.get_arrived_val(target))

    # スタート地点のエリアからBFSを実施。
    start_erea = maze.get_arrived_val(start)

    # 初期値：自分のエリアにはワープ回数0回で移動できる
    area_list = [-1 for a in range(group_num + 1)]
    area_list[start_erea] = 0

    que.appendleft(start_erea)
    while len(que) is not 0:
        now = que.popleft()

        # 移動できる対象単位でループ(例；エリア1から、2,3に移動できる、等)
        for move_target in move_target_list[now]:

            # 距離が設定済みなら何もしない
            if not area_list[move_target] == -1:
                continue

            # キューに追加
            que.append(move_target)

            # 距離を設定
            area_list[move_target] = area_list[now] + 1

    gorl_area = maze.get_arrived_val(gorl)
    print(area_list[gorl_area])

    # テストクラス


class TestClass(unittest.TestCase):
    def assertIO(self, assert_input, output):
        stdout, sat_in = sys.stdout, sys.stdin
        sys.stdout, sys.stdin = StringIO(), StringIO(assert_input)
        resolve(sys._getframe().f_back.f_code.co_name)
        sys.stdout.seek(0)
        out = sys.stdout.read()[:-1]
        sys.stdout, sys.stdin = stdout, sat_in
        self.assertEqual(out, output)

    def test_input_1(self):
        test_input = """4 4
1 1
4 4
..#.
..#.
.#..
.#.."""
        output = """1"""
        self.assertIO(test_input, output)

    def test_input_2(self):
        test_input = """4 4
1 4
4 1
.##.
####
####
.##."""
        output = """-1"""
        self.assertIO(test_input, output)

    def test_input_3(self):
        test_input = """4 4
2 2
3 3
....
....
....
...."""
        output = """0"""
        self.assertIO(test_input, output)

    def test_input_4(self):
        test_input = """4 5
1 2
2 5
#.###
####.
#..##
#..##"""
        output = """2"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_original(self):
        test_input = """4 4
2 2
3 3
....
..#.
.#..
...."""
        output = """0"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_origina2(self):
        test_input = """4 4
2 2
3 3
....
..##
.#..
...."""
        output = """0"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_origina3(self):
        test_input = """4 4
2 2
3 3
....
..##
##..
...."""
        output = """1"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_origina4(self):
        test_input = """4 4
1 1
3 3
.#..
..##
##..
...."""
        output = """1"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_origina5(self):
        test_input = """4 4
1 1
4 4
.#..
#.##
##..
...."""
        output = """1"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_origina6(self):
        test_input = """4 4
1 1
4 4
.#..
#.##
####
...."""
        output = """2"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_origina7(self):
        test_input = """1 4
1 1
1 4
...."""
        output = """0"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_origina8(self):
        test_input = """1 4
1 1
1 4
.#.."""
        output = """1"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_origina9(self):
        test_input = """1 4
1 4
1 1
..#."""
        output = """1"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_origina10(self):
        test_input = """4 1
4 1
1 1
.
.
#
.
"""
        output = """1"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_origina11(self):
        test_input = """4 1
1 1
4 1
.
.
#
.
"""
        output = """1"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_original12(self):
        test_input = """6 6
1 1
6 6
......
......
......
......
......
......"""
        output = """0"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_original13(self):
        test_input = """6 6
1 1
6 6
......
######
......
......
......
......"""
        output = """1"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_original14(self):
        test_input = """6 6
1 1
6 6
......
######
######
......
......
......"""
        output = """-1"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_original15(self):
        test_input = """6 6
1 1
6 6
......
######
.####.
.#....
#.....
......"""
        output = """1"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_original16(self):
        test_input = """6 6
1 1
6 1
......
######
.####.
.#.#.#
#..#..
....##"""
        output = """2"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_original17(self):
        test_input = """6 6
3 3
6 1
......
######
.#.##.
.#.#.#
####..
....##"""
        output = """1"""
        self.assertIO(test_input, output)

    # 自作テストパターン
    def test_original17(self):
        test_input = """6 6
1 1
4 4
.#.#.#
.#.#.#
.#.#.#
.#...#
.#.#.#
.#.#.#"""
        output = """1"""
        self.assertIO(test_input, output)


# 実装orテストの呼び出し
if __name__ == "__main__":
    if os.environ.get("USERNAME") is None:
        # AtCoder提出時の場合
        resolve()

    else:
        # 自PCの場合
        unittest.main()


Measured memory_bytes: 298184