# D - Wizard in Maze

import sys

from collections import deque

from typing import List, Tuple





class WarpableMaze:

    __slots__ = ["height", "width", "road", "wall", "grid"]



    def __init__(

        self,

        height: int,

        width: int,

        grid: List[str],

        road: str = ".",

        wall: str = "#",

    ) -> None:

        # Values of start and goal must be 0-origin.

        self.height = height + 4

        self.width = width + 4

        self.road = road

        self.wall = wall

        self.grid = self._flatten_grid(grid)



    def _flatten_grid(self, grid: List[str]) -> str:

        flat_grid = self.wall * self.width * 2

        for row in grid:

            flat_grid += self.wall * 2 + row + self.wall * 2

        flat_grid += self.wall * self.width * 2

        return flat_grid



    def _flatten_dxy(self, x: int, y: int) -> int:

        return self.width * x + y



    def _flatten_coordinate(self, h: int, w: int) -> int:

        return self._flatten_dxy(h + 2, w + 2)



    def bfs(self, start_2d: Tuple[int, int], goal_2d: Tuple[int, int]) -> int:

        start = self._flatten_coordinate(*start_2d)

        goal = self._flatten_coordinate(*goal_2d)



        w = self.width

        flatten = lambda *dxy: tuple(self._flatten_dxy(*xy) for xy in dxy)

        move_to_warp = {

            -w: flatten((-2, -2), (-2, -1), (-2, 0), (-2, 1), (-1, -1)),

            w: flatten((1, 1), (2, -1), (2, 0), (2, 1), (2, 2)),

            -1: flatten((-1, -2), (0, -2), (1, -2), (1, -1), (2, -2)),

            1: flatten((-1, 1), (-2, 2), (-1, 2), (0, 2), (1, 2)),

        }



        unsearched = 1 << 30

        dist = [unsearched] * (self.height * self.width)

        dist[start] = 0

        queue = deque([start])

        while queue:

            x = queue.popleft()

            cur_dist = dist[x]

            if x == goal:

                break



            for move, warp in move_to_warp.items():

                nx = x + move

                if self.grid[nx] == self.road:

                    if dist[nx] > cur_dist:

                        dist[nx] = cur_dist

                        queue.appendleft(nx)

                    continue



                for dx in warp:

                    nx = x + dx

                    if self.grid[nx] == self.wall:

                        continue

                    if dist[nx] > cur_dist + 1:

                        dist[nx] = cur_dist + 1

                        queue.append(nx)



        return dist[goal] if dist[goal] != unsearched else -1



    def debug(self):

        print("<DEBUG>", file=sys.stderr)

        for row in zip(*[iter(self.grid)] * self.width):

            print(*row, file=sys.stderr)





def main():

    H, W, CH, CW, DH, DW, *S = open(0).read().split()

    maze = WarpableMaze(int(H), int(W), S)

    start, goal = (int(CH) - 1, int(CW) - 1), (int(DH) - 1, int(DW) - 1)

    print(maze.bfs(start, goal))

    # maze.debug()





if __name__ == "__main__":

    main()

# D - Wizard in Maze

import sys

from collections import deque

from typing import List, Tuple





class WarpableMaze:

    __slots__ = ["height", "width", "road", "wall", "unsearched", "dist"]



    def __init__(

        self,

        height: int,

        width: int,

        grid: List[bytes],

        road: str = ".",

        wall: str = "#",

    ) -> None:

        self.height = height + 4

        self.width = width + 4

        self.road = road

        self.wall = wall

        self.unsearched = 1 << 30

        self.dist = self._convert_grid_to_dist(grid)



    def _flatten_dxy(self, x: int, y: int) -> int:

        return self.width * x + y



    def _flatten_coordinate(self, h: int, w: int) -> int:

        return self._flatten_dxy(h + 2, w + 2)



    def _convert_grid_to_dist(self, grid: List[bytes]) -> List[int]:

        dist = [-1] * self.height * self.width

        i = self.width * 2 + 1

        for row in grid:

            for c in row.decode():

                i += 1

                if c == self.road:

                    dist[i] = self.unsearched

            i += 4

        return dist



    def bfs(self, start_2d: Tuple[int, int], goal_2d: Tuple[int, int]) -> int:

        start = self._flatten_coordinate(*start_2d)

        goal = self._flatten_coordinate(*goal_2d)



        w = self.width

        walk_to_warp = {

            -w: (-2 * w - 2, -2 * w - 1, -2 * w, -2 * w + 1, -w - 1),

            w: (w + 1, 2 * w - 1, 2 * w, 2 * w + 1, 2 * w + 2),

            -1: (-w - 2, -2, w - 2, w - 1, 2 * w - 2),

            1: (-w + 1, -2 * w + 2, -w + 2, 2, w + 2),

        }



        dist = self.dist[:]

        dist[start] = 0

        queue = deque([start])

        while queue:

            x = queue.popleft()

            cur_dist = dist[x]

            if x == goal:

                break



            for walk, warp in walk_to_warp.items():

                nx = x + walk

                if dist[nx] > cur_dist:

                    dist[nx] = cur_dist

                    queue.appendleft(nx)

                    continue

                if dist[nx] >= 0:

                    continue



                for dx in warp:

                    nx = x + dx

                    if dist[nx] > cur_dist + 1:

                        dist[nx] = cur_dist + 1

                        queue.append(nx)



        return dist[goal] if dist[goal] != self.unsearched else -1



    def debug(self):

        print("<DEBUG>", file=sys.stderr)

        for row in zip(*[iter(self.dist)] * self.width):

            print(*row, file=sys.stderr)





def main():

    read = sys.stdin.buffer.read

    readline = sys.stdin.buffer.readline



    H, W = map(int, readline().split())

    CH, CW = map(int, readline().split())

    DH, DW = map(int, readline().split())

    (*S,) = read().split()



    maze = WarpableMaze(H, W, S)

    start, goal = (CH - 1, CW - 1), (DH - 1, DW - 1)

    print(maze.bfs(start, goal))

    # maze.debug()





if __name__ == "__main__":

    main()

# D - Wizard in Maze
import sys
from collections import deque
from typing import List, Tuple


class WarpableMaze:
    __slots__ = ["height", "width", "road", "wall", "grid"]

    def __init__(
        self,
        height: int,
        width: int,
        grid: List[str],
        road: str = ".",
        wall: str = "#",
    ) -> None:
        # Values of start and goal must be 0-origin.
        self.height = height + 4
        self.width = width + 4
        self.road = road
        self.wall = wall
        self.grid = self._flatten_grid(grid)

    def _flatten_grid(self, grid: List[str]) -> str:
        flat_grid = self.wall * self.width * 2
        for row in grid:
            flat_grid += self.wall * 2 + row + self.wall * 2
        flat_grid += self.wall * self.width * 2
        return flat_grid

    def _flatten_dxy(self, x: int, y: int) -> int:
        return self.width * x + y

    def _flatten_coordinate(self, h: int, w: int) -> int:
        return self._flatten_dxy(h + 2, w + 2)

    def bfs(self, start_2d: Tuple[int, int], goal_2d: Tuple[int, int]) -> int:
        start = self._flatten_coordinate(*start_2d)
        goal = self._flatten_coordinate(*goal_2d)
        w = self.width
        flatten = lambda *dxy: tuple(self._flatten_dxy(*xy) for xy in dxy)
        move_to_warp = {
            -w: flatten((-2, -2), (-2, -1), (-2, 0), (-2, 1), (-1, -1)),
            w: flatten((1, 1), (2, -1), (2, 0), (2, 1), (2, 2)),
            -1: flatten((-1, -2), (0, -2), (1, -2), (1, -1), (2, -2)),
            1: flatten((-1, 1), (-2, 2), (-1, 2), (0, 2), (1, 2)),
        }
        unsearched = 1 << 30
        dist = [unsearched] * (self.height * self.width)
        dist[start] = 0
        queue = deque([start])
        while queue:
            x = queue.popleft()
            cur_dist = dist[x]
            if x == goal:
                break
            for move, warp in move_to_warp.items():
                nx = x + move
                if self.grid[nx] == self.road:
                    if dist[nx] > cur_dist:
                        dist[nx] = cur_dist
                        queue.appendleft(nx)
                    continue
                for dx in warp:
                    nx = x + dx
                    if self.grid[nx] == self.wall:
                        continue
                    if dist[nx] > cur_dist + 1:
                        dist[nx] = cur_dist + 1
                        queue.append(nx)
        return dist[goal] if dist[goal] != unsearched else -1

    def debug(self):
        print("<DEBUG>", file=sys.stderr)
        for row in zip(*[iter(self.grid)] * self.width):
            print(*row, file=sys.stderr)


def main():
    H, W, CH, CW, DH, DW, *S = open(0).read().split()
    maze = WarpableMaze(int(H), int(W), S)
    start, goal = (int(CH) - 1, int(CW) - 1), (int(DH) - 1, int(DW) - 1)
    print(maze.bfs(start, goal))
    # maze.debug()


if __name__ == "__main__":
    main()

# D - Wizard in Maze
import sys
from collections import deque
from typing import List, Tuple


class WarpableMaze:
    __slots__ = ["height", "width", "road", "wall", "unsearched", "dist"]

    def __init__(
        self,
        height: int,
        width: int,
        grid: List[bytes],
        road: str = ".",
        wall: str = "#",
    ) -> None:
        self.height = height + 4
        self.width = width + 4
        self.road = road
        self.wall = wall
        self.unsearched = 1 << 30
        self.dist = self._convert_grid_to_dist(grid)

    def _flatten_dxy(self, x: int, y: int) -> int:
        return self.width * x + y

    def _flatten_coordinate(self, h: int, w: int) -> int:
        return self._flatten_dxy(h + 2, w + 2)

    def _convert_grid_to_dist(self, grid: List[bytes]) -> List[int]:
        dist = [-1] * self.height * self.width
        i = self.width * 2 + 1
        for row in grid:
            for c in row.decode():
                i += 1
                if c == self.road:
                    dist[i] = self.unsearched
            i += 4
        return dist

    def bfs(self, start_2d: Tuple[int, int], goal_2d: Tuple[int, int]) -> int:
        start = self._flatten_coordinate(*start_2d)
        goal = self._flatten_coordinate(*goal_2d)
        w = self.width
        walk_to_warp = {
            -w: (-2 * w - 2, -2 * w - 1, -2 * w, -2 * w + 1, -w - 1),
            w: (w + 1, 2 * w - 1, 2 * w, 2 * w + 1, 2 * w + 2),
            -1: (-w - 2, -2, w - 2, w - 1, 2 * w - 2),
            1: (-w + 1, -2 * w + 2, -w + 2, 2, w + 2),
        }
        dist = self.dist[:]
        dist[start] = 0
        queue = deque([start])
        while queue:
            x = queue.popleft()
            cur_dist = dist[x]
            if x == goal:
                break
            for walk, warp in walk_to_warp.items():
                nx = x + walk
                if dist[nx] > cur_dist:
                    dist[nx] = cur_dist
                    queue.appendleft(nx)
                    continue
                if dist[nx] >= 0:
                    continue
                for dx in warp:
                    nx = x + dx
                    if dist[nx] > cur_dist + 1:
                        dist[nx] = cur_dist + 1
                        queue.append(nx)
        return dist[goal] if dist[goal] != self.unsearched else -1

    def debug(self):
        print("<DEBUG>", file=sys.stderr)
        for row in zip(*[iter(self.dist)] * self.width):
            print(*row, file=sys.stderr)


def main():
    read = sys.stdin.buffer.read
    readline = sys.stdin.buffer.readline
    H, W = map(int, readline().split())
    CH, CW = map(int, readline().split())
    DH, DW = map(int, readline().split())
    (*S,) = read().split()
    maze = WarpableMaze(H, W, S)
    start, goal = (CH - 1, CW - 1), (DH - 1, DW - 1)
    print(maze.bfs(start, goal))
    # maze.debug()


if __name__ == "__main__":
    main()

-    __slots__ = ["height", "width", "road", "wall", "grid"] +    __slots__ = ["height", "width", "road", "wall", "unsearched", "dist"] -        grid: List[str], +        grid: List[bytes], -        # Values of start and goal must be 0-origin. -        self.grid = self._flatten_grid(grid) - -    def _flatten_grid(self, grid: List[str]) -> str: -        flat_grid = self.wall * self.width * 2 -        for row in grid: -            flat_grid += self.wall * 2 + row + self.wall * 2 -        flat_grid += self.wall * self.width * 2 -        return flat_grid +        self.unsearched = 1 << 30 +        self.dist = self._convert_grid_to_dist(grid) +    def _convert_grid_to_dist(self, grid: List[bytes]) -> List[int]: +        dist = [-1] * self.height * self.width +        i = self.width * 2 + 1 +        for row in grid: +            for c in row.decode(): +                i += 1 +                if c == self.road: +                    dist[i] = self.unsearched +            i += 4 +        return dist + -        flatten = lambda *dxy: tuple(self._flatten_dxy(*xy) for xy in dxy) -        move_to_warp = { -            -w: flatten((-2, -2), (-2, -1), (-2, 0), (-2, 1), (-1, -1)), -            w: flatten((1, 1), (2, -1), (2, 0), (2, 1), (2, 2)), -            -1: flatten((-1, -2), (0, -2), (1, -2), (1, -1), (2, -2)), -            1: flatten((-1, 1), (-2, 2), (-1, 2), (0, 2), (1, 2)), +        walk_to_warp = { +            -w: (-2 * w - 2, -2 * w - 1, -2 * w, -2 * w + 1, -w - 1), +            w: (w + 1, 2 * w - 1, 2 * w, 2 * w + 1, 2 * w + 2), +            -1: (-w - 2, -2, w - 2, w - 1, 2 * w - 2), +            1: (-w + 1, -2 * w + 2, -w + 2, 2, w + 2), -        unsearched = 1 << 30 -        dist = [unsearched] * (self.height * self.width) +        dist = self.dist[:] -            for move, warp in move_to_warp.items(): -                nx = x + move -                if self.grid[nx] == self.road: -                    if dist[nx] > cur_dist: -                        dist[nx] = cur_dist -                        queue.appendleft(nx) +            for walk, warp in walk_to_warp.items(): +                nx = x + walk +                if dist[nx] > cur_dist: +                    dist[nx] = cur_dist +                    queue.appendleft(nx) +                    continue +                if dist[nx] >= 0: -                    if self.grid[nx] == self.wall: -                        continue -        return dist[goal] if dist[goal] != unsearched else -1 +        return dist[goal] if dist[goal] != self.unsearched else -1 -        for row in zip(*[iter(self.grid)] * self.width): +        for row in zip(*[iter(self.dist)] * self.width): -    H, W, CH, CW, DH, DW, *S = open(0).read().split() -    maze = WarpableMaze(int(H), int(W), S) -    start, goal = (int(CH) - 1, int(CW) - 1), (int(DH) - 1, int(DW) - 1) +    read = sys.stdin.buffer.read +    readline = sys.stdin.buffer.readline +    H, W = map(int, readline().split()) +    CH, CW = map(int, readline().split()) +    DH, DW = map(int, readline().split()) +    (*S,) = read().split() +    maze = WarpableMaze(H, W, S) +    start, goal = (CH - 1, CW - 1), (DH - 1, DW - 1)