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 Go (1.14.1) (judge verdict: Accepted)

package main

import (
	"bufio"
	"container/heap"
	"container/list"
	"fmt"
	"os"
	"sort"
	"strconv"
	"strings"
)

const (
	initialBufSize = 1e4
	maxBufSize     = 1e6 + 7
)

var buf []byte = make([]byte, maxBufSize)
var sc = bufio.NewScanner(os.Stdin)

func init() {
	sc.Split(bufio.ScanWords)
	sc.Buffer(buf, maxBufSize)
}

type position struct {
	H int
	W int
}

// var d [][]int
// var warp [][]int

func main() {
	d := [][]int{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}
	warp := [][]int{{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}}
	H, W := nextInt(), nextInt()
	C := position{
		nextInt() - 1,
		nextInt() - 1,
	}
	D := position{
		nextInt() - 1,
		nextInt() - 1,
	}
	S := make([][]string, H)
	for i := range S {
		S[i] = strings.Split(nextLine(), "")
	}
	// fmt.Println(C, D)
	// fmt.Println(S)
	dist := make([][]int, H)
	// warped := make([][]bool, H)
	// prev := make([][]position, H)
	for i := range dist {
		dist[i] = make([]int, W)
		// warped[i] = make([]bool, W)
		for j := 0; j < W; j++ {
			dist[i][j] = -1
		}
	}
	dist[C.H][C.W] = 0
	// queue := make([]position, 0)
	// queue = append(queue, C)
	deque := list.New()
	deque.PushBack(C)
	for deque.Len() != 0 {
		current := deque.Front().Value.(position)
		deque.Remove(deque.Front())
		// queue = queue[1:]
		// fmt.Println("cur", current)
		// fq := make([]position, 0)
		for _, v := range d {
			nextP := position{
				current.H + v[0],
				current.W + v[1],
			}
			// nextH := current.W + v[0]
			// nextW := current.W + v[1]
			if nextP.H < 0 || nextP.H >= H || nextP.W < 0 || nextP.W >= W {
				continue
			}
			if S[nextP.H][nextP.W] == "#" {
				continue
			}
			if dist[nextP.H][nextP.W] == -1 || dist[nextP.H][nextP.W] > dist[current.H][current.W] {
				// queue = append([]position{nextP}, queue...)
				// fq = append(fq, nextP)
				// appendだと遅い。dequeっぽい動きをさせる
				deque.PushFront(nextP)
				dist[nextP.H][nextP.W] = dist[current.H][current.W]
				// warped[nextP.H][nextP.W] = false
				// fmt.Println("next", nextP, dist[nextP.H][nextP.W])
			}
			// fmt.Println(nextP)
		}
		// queue = append(queue, fq...)
		for _, v := range warp {
			nextP := position{
				current.H + v[0],
				current.W + v[1],
			}
			if nextP.H < 0 || nextP.H >= H || nextP.W < 0 || nextP.W >= W {
				continue
			}
			if S[nextP.H][nextP.W] == "#" {
				continue
			}
			if dist[nextP.H][nextP.W] == -1 || dist[nextP.H][nextP.W] > dist[current.H][current.W]+1 {
				// queue = append(queue, nextP)
				deque.PushBack(nextP)
				dist[nextP.H][nextP.W] = dist[current.H][current.W] + 1
				// fmt.Println("warp", nextP, dist[nextP.H][nextP.W])
				// warped[nextP.H][nextP.W] = true
			}
		}
		// fmt.Println(dist, queue)
	}
	// fmt.Println(dist)
	fmt.Println(dist[D.H][D.W])
}

func nextLine() string {
	sc.Scan()
	return sc.Text()
}

func nextInt() int {
	sc.Scan()
	i, e := strconv.Atoi(sc.Text())
	if e != nil {
		panic(e)
	}
	return i
}

func abs(a int) int {
	if a > 0 {
		return a
	} else {
		return -a
	}
}

func pow(p, q int) int {
	res := p
	if q == 0 {
		return 1
	}
	for i := 0; i < q-1; i++ {
		res *= p
	}
	return res
}

func ceil(a, b int) int {
	return (a + (b - 1)) / b
}

func MinOf(vars ...int) int {
	min := vars[0]
	for _, i := range vars {
		if min > i {
			min = i
		}
	}
	return min
}

func MaxOf(vars ...int) int {
	max := vars[0]
	for _, i := range vars {
		if max < i {
			max = i
		}
	}
	return max
}

func gcdof2numbers(a int, b int) int {
	if b == 0 {
		return a
	}
	return gcdof2numbers(b, a%b)
}

func lcmof2numbers(a int, b int) int {
	return a / gcdof2numbers(a, b) * b
}

// マイナスの場合は考慮していない
func fuctorial(a int) int {
	if a == 1 || a == 0 {
		return 1
	} else {
		return fuctorial(a-1) * a
	}
}

func NextPermutation(x sort.Interface) bool {
	n := x.Len() - 1
	if n < 1 {
		return false
	}
	j := n - 1
	for ; !x.Less(j, j+1); j-- {
		if j == 0 {
			return false
		}
	}
	l := n
	for !x.Less(j, l) {
		l--
	}
	x.Swap(j, l)
	for k, l := j+1, n; k < l; {
		x.Swap(k, l)
		k++
		l--
	}
	return true
}

// 素因数分解したmapを返す
func primeFuctorize(n int) map[int]int {
	pf := map[int]int{}
	for i := 2; i*i <= n; i++ {
		for n%i == 0 {
			pf[i]++
			n /= i
		}
	}
	if n != 1 {
		pf[n]++
	}
	return pf
}

// ここから拝借
// https://shoman.hatenablog.com/entry/2020/02/25/185456
// Stackは[]intのエイリアス
type Stack []int

// Push adds an element
func (s *Stack) Push(v int) {
	*s = append(*s, v)
}

// Pop removes the top element and return it
func (s *Stack) Pop() (int, error) {
	if s.Empty() {
		return 0, fmt.Errorf("stack is empty")
	}

	v := (*s)[len(*s)-1]
	*s = (*s)[:len(*s)-1]
	return v, nil
}

// Peek returns the top value
func (s *Stack) Peek() (int, error) {
	if s.Empty() {
		return 0, fmt.Errorf("stack is empty")
	}

	return (*s)[len(*s)-1], nil
}

// Size returns the length of stack
func (s *Stack) Size() int {
	return len(*s)
}

// Empty returns true when stack is empty
func (s *Stack) Empty() bool {
	return s.Size() == 0
}

// NewStack generates stack
func NewStack() *Stack {
	s := new(Stack)
	return s
}

// golangの公式サンプルより
// https://xn--go-hh0g6u.com/pkg/container/heap/#example__intHeap
// IntHeap は，整数の最小ヒープです。
type IH []int

func (h IH) Len() int           { return len(h) }
func (h IH) Less(i, j int) bool { return h[i] < h[j] }
func (h IH) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }

func (h *IH) Push(x interface{}) {
	// Push と Pop はポインタレシーバを使っています。
	// なぜなら，スライスの中身だけでなく，スライスの長さも変更するからです。
	*h = append(*h, x.(int))
}

func (h *IH) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

// golangの公式サンプルより
// https://xn--go-hh0g6u.com/pkg/container/heap/#example__priorityQueue

// Item は，優先キューで管理する項目です。
type Item struct {
	value    string // 値。任意です。
	priority int    // キューにおける優先度
	// index は heap.Interface メソッドで更新されます。
	index int // ヒープにおけるインデックス
}

// PriorityQueue は heap.Interface を実装し，Item のリストを保持します。
type PriorityQueue []*Item

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	// Pop が最小ではなく最大の優先度を持つ項目を返して欲しいので，ここでは > を使っています。
	return pq[i].priority > pq[j].priority
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
	pq[i].index = i
	pq[j].index = j
}

func (pq *PriorityQueue) Push(x interface{}) {
	n := len(*pq)
	item := x.(*Item)
	item.index = n
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	old[n-1] = nil  // メモリリークを避ける
	item.index = -1 // 安全のため
	*pq = old[0 : n-1]
	return item
}

// update はキューの Item の優先度と値を更新します。
func (pq *PriorityQueue) update(item *Item, value string, priority int) {
	item.value = value
	item.priority = priority
	heap.Fix(pq, item.index)
}