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 C# (.NET Core 3.1.201) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using static System.Console;
using static System.Math;
using static MyIO;
using static MyUtil;
using static ShortestPath;

public class D { public static void Main() => (new Solver()).Solve(); }

public class Solver
{
	private long[] dy = new long[] { -1, 0, 1, 0 };
	private long[] dx = new long[] { 0, -1, 0, 1 };

	public void Solve()
	{
		long H = GetLong();
		long W = GetLong();
		var C = (GetLong() - 1, GetLong() - 1);
		var D = (GetLong() - 1, GetLong() - 1);
		var grid = new char[H, W];
		for(long i = 0; i < H; i++)
		{
			var S = GetString().ToArray();
			for(long j = 0; j < W; j++)
				grid[i, j] = S[j];
		}
		long conv(long y, long x) => y * W + x;

		var uf = new UnionFind(H * W);
		for(long i = 0; i < H; i++)
		{
			for(long j = 0; j < W; j++)
			{
				if(grid[i, j] == '#')
					continue;

				long v = conv(i, j);
				for(long k = 0; k < 4; k++)
				{
					var (ni, nj) = (i + dy[k], j + dx[k]);
					if(ni < 0 || ni >= H || nj < 0 || nj >= W || grid[ni, nj] == '#')
						continue;
					
					long u = conv(ni, nj);
					if(!uf.IsSame(v, u))
						uf.Unite(v, u);
				}
			}
		}

		var adj = Range(0, H * W).Select(_ => new List<Edge<long>>()).ToArray();
		for(long i = 0; i < H; i++)
		{
			for(long j = 0; j < W; j++)
			{
				if(grid[i, j] == '#')
					continue;

				long v = conv(i, j);
				long rv = uf.Root(v);
				for(long k = -2; k <= 2; k++)
				{
					for(long l = -2; l <= 2; l++)
					{
						var (ni, nj) = (i + k, j + l);
						if(ni < 0 || ni >= H || nj < 0 || nj >= W || grid[ni, nj] == '#')
							continue;

						long u = conv(ni, nj);
						long ru = uf.Root(u);
						adj[rv].Add(new Edge<long>(rv, ru, 1));
						adj[ru].Add(new Edge<long>(ru, rv, 1));
					}
				}
			}
		}

		long INF = long.MaxValue / 2;
		long s = conv(C.Item1, C.Item2);
		var d = Dijkstra<long>(adj, INF, uf.Root(s), (x, y) => x + y);
		long t = conv(D.Item1, D.Item2);
		WriteLine(d[uf.Root(t)] < INF ? d[uf.Root(t)] : -1);
	}
}

public static class ShortestPath
{
	public struct Edge<T>
	{
		public long From;
		public long To;
		public T Cost;

		public Edge(long from, long to, T cost)
		{
			From = from;
			To = to;
			Cost = cost;
		}
	}
	
	// false: has negative cycle
	public static bool BellmanFord<T>(long N, List<Edge<T>> edges, long s, T inf, Func<T, T, T> add, out T[] d) where T : IComparable<T>
	{
		d = Enumerable.Repeat(inf, (int)N).ToArray();
		d[s] = default(T);
		for(long i = 0; i < N; i++)
		{
			bool update = false;
			foreach(var e in edges)
			{
				var tmp = add(d[e.From], e.Cost);
				if((d[e.From].CompareTo(inf) < 0) && (d[e.To].CompareTo(tmp) > 0))
				{
					d[e.To] = tmp;
					update = true;
					if(i == N - 1)
						return false;
				}
			}
			if(!update)
				break;
		}
		return true;
	}

	public static bool HasNegativeCycle<T>(long N, List<Edge<T>> edges, Func<T, T, T> add) where T : IComparable<T>
	{
		var d = new T[N];		
		for(long i = 0; i < N; i++)
		{
			foreach(var e in edges)
			{
				var tmp = add(d[e.From], e.Cost);
				if(d[e.To].CompareTo(tmp) > 0)
				{
					d[e.To] = tmp;
					if(i == N - 1)
						return true;
				}
			}
		}
		return false;
	}

	public static T[] Dijkstra<T>(T[,] cost, T inf, long s, Func<T, T, T> add) where T : IComparable<T>
	{
		long V = cost.GetLength(0);	
		var used = new bool[V];
		var d = Enumerable.Repeat(inf, (int)V).ToArray();
		d[s] = default(T);

		while(true)
		{
			long v = -1;
			for(long u = 0; u < V; u++)
				if(!used[u] && (v == -1 || d[u].CompareTo(d[v]) < 0))
					v = u;

			if(v == -1)
				break;

			used[v] = true;
			for(long u = 0; u < V; u++)
			{
				var tmp = add(d[v], cost[v, u]);
				if(d[u].CompareTo(tmp) > 0)
					d[u] = tmp;
			}
		}
		return d;
	}

	public static T[] Dijkstra<T>(List<Edge<T>>[] adj, T inf, long s, Func<T, T, T> add) where T : IComparable<T>
	{
		Comparison<Tuple<T, long>> comp = ((x, y) => x.Item1.CompareTo(y.Item1));
		var pq = new PriorityQueue<Tuple<T, long>>(adj.Length, comp);

		var d = Enumerable.Repeat(inf, adj.Length).ToArray();
		d[s] = default(T);
		pq.Push(Tuple.Create(d[s], s));
		while(pq.Count > 0)
		{
			var p = pq.Pop();
			long v = p.Item2;
			if(d[v].CompareTo(p.Item1) < 0)
				continue;

			for(long i = 0; i < adj[v].Count; i++)
			{
				var edge = adj[v][(int)i];
				var tmp = add(d[v], edge.Cost);
				if(d[edge.To].CompareTo(tmp) > 0)
				{
					d[edge.To] = tmp;
					pq.Push(Tuple.Create(d[edge.To], edge.To));
				}
			}
		}
		return d;
	}

	// false: has negative cycle
	public static bool WarshallFloyd<T>(ref T[,] d, Func<T, T, T> add) where T : IComparable<T>
	{
		long V = d.GetLength(0);
		for(long k = 0; k < V; k++)
		{
			for(long i = 0; i < V; i++)
			{
				for(long j = 0; j < V; j++)
				{
					var tmp = add(d[i, k], d[k, j]);
					if(d[i, j].CompareTo(tmp) > 0)
						d[i, j] = tmp;
				}
			}
		}
		for(long i = 0; i < V; i++)
		{
			if(d[i, i].CompareTo(default(T)) < 0)
				return false;
		}
		return true;
	}
}

public class PriorityQueue<T>
{
	public long Count { get; private set; } = 0;
	public long MaxSize { get; private set; } = 0;
	private T[] m_heap;
	private Comparison<T> Comp = null;
	
	public PriorityQueue(long maxSize, Comparison<T> comp)
	{
		if(maxSize <= 0)
			throw new Exception();
		MaxSize = maxSize;
		m_heap = new T[maxSize];

		Comp = comp;
	}
	
	public void Push(T x)
	{
		if(Count == MaxSize)
		{
			T[] new_heap = new T[MaxSize << 1];
			Array.Copy(m_heap, new_heap, MaxSize);
			m_heap = new_heap;
			MaxSize <<= 1;
		}
		
		long i = Count++;
		while(i > 0)
		{
			long p = (i - 1)/2;
			if(Comp(m_heap[p], x) <= 0)
				break;
			m_heap[i] = m_heap[p];
			i = p;			
		}
		m_heap[i] = x;		
	}
	
	public T Pop()
	{
		if(Count == 0)
			throw new Exception("Queue is empty.");
		
		T result = m_heap[0];
		T x = m_heap[--Count];
		long i = 0;
		while(i * 2 + 1 < Count)
		{
			long c1 = i * 2 + 1, c2 = i * 2 + 2;
			if(c2 < Count && Comp(m_heap[c2], m_heap[c1]) < 0)
				c1 = c2;
			if(Comp(m_heap[c1], x) >= 0)
				break;
			m_heap[i] = m_heap[c1];
			i = c1;
		}
		m_heap[i] = x;
		
		return result;		
	}
	
	public T Peek() => m_heap[0];
}

public class UnionFind
{
	private long[] par = null;
	private long[] rank = null;
	private long[] size = null;
	
	public long Size(long x) => size[Root(x)];
	public bool IsSame(long x, long y) => (Root(x) == Root(y));

	public UnionFind(long n)
	{
		par = new long[n];
		rank = new long[n];
		size = new long[n];
		for(long i = 0; i < n; i++)
		{
			par[i] = i;
			rank[i] = 0;
			size[i] = 1;
		}
	}

	public long Root(long x)
	{
		if(par[x] == x)
			return x;

		long r = Root(par[x]);
		par[x] = r;
		return r;
	}
	
	public bool Unite(long x, long y)
	{
		long rx = Root(x);
		long ry = Root(y);
		if(rx == ry)
			return false;
		
		if(rank[rx] < rank[ry])
		{
			long tmp = rx;
			rx = ry;
			ry = tmp;
		}
		else if(rank[rx] == rank[ry])
			rank[rx]++;

		par[ry] = rx;
		size[rx] = size[rx] + size[ry];
		return true;
	}
}

public static class MyIO
{
	private static string[] args = new string[0];
	private static int cnt = 0;
	private static IEnumerable<string> getArgs(long N) => Range(0, N).Select(_ => getArg());
	private static string getArg()
	{
		if(cnt == args.Length) { args = Console.ReadLine().Split(); cnt = 0; }
		return args[cnt++];
	}

	public static int GetInt() => int.Parse(getArg());
	public static long GetLong() => long.Parse(getArg());
	public static double GetDouble() => double.Parse(getArg());
	public static decimal GetDecimal() => decimal.Parse(getArg());
	public static string GetString() => getArg();
	public static char GetChar() => getArg()[0];
	public static int[] GetInts(long N) => getArgs(N).Select(int.Parse).ToArray();
	public static long[] GetLongs(long N) => getArgs(N).Select(long.Parse).ToArray();
	public static double[] GetDoubles(long N) => getArgs(N).Select(double.Parse).ToArray();
	public static decimal[] GetDecimals(long N) => getArgs(N).Select(decimal.Parse).ToArray();
	public static string[] GetStrings(long N) => getArgs(N).ToArray();
}

public static class MyUtil
{
	public static void chmax<T>(ref T x, T y) where T : IComparable<T> { if(x.CompareTo(y) < 0) x = y; }
	public static void chmin<T>(ref T x, T y) where T : IComparable<T> { if(x.CompareTo(y) > 0)	x = y; }
	public static void swap<T>(ref T x, ref T y) { T tmp = x; x = y; y = tmp; }
	public static long rightShift(long x, long y) => (x >> (int)y);
	public static long leftShift(long x, long y) => (x << (int)y);
	public static bool contains(long s, long x) => (rightShift(s, x) & 1L) == 1L;
	public static long gcd(long x, long y) => (y == 0) ? x : gcd(y, x % y);
	public static long lcm(long x, long y) => (x / gcd(x,y)) * y;	
	public static IEnumerable<int> Range(long start, long count) => Enumerable.Range((int)start, (int)count);
	public static void Sort(this List<string> source) => source.Sort(StringComparer.Ordinal);
}