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;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Linq;

using E = System.Linq.Enumerable;
using System.Threading;

internal partial class Solver {
    public void Run() {
        var h = ni();
        var w = ni();
        var ch = ni() - 1;
        var cw = ni() - 1;
        var dh = ni() - 1;
        var de = ni() - 1;
        var map = ns(h);
        var deque = new Deque<(int Row, int Col, int Warp)>();
        deque.PushBack((ch, cw, 0));
        var visited = new bool[h, w];
        int ans = -1;
        while (deque.Count > 0) {
            var (row, col, warp) = deque.PopFront();
            if (row == dh && col == de) {
                ans = warp;
                break;
            }
            if (visited[row, col]) continue;
            visited[row, col] = true;
            for (int dr = -2; dr <= 2; dr++) {
                for (int dc = -2; dc <= 2; dc++) {
                    var d = Math.Abs(dr) + Math.Abs(dc);
                    if (d == 0) continue;
                    var nr = row + dr;
                    var nc = col + dc;
                    if ((0 <= nr && nr < h) && (0 <= nc && nc < w) && map[nr][nc] == '.') {
                        if (d == 1) {
                            deque.PushFront((nr, nc, warp));
                        } else {
                            deque.PushBack((nr, nc, warp + 1));
                        }
                    }
                }
            }
        }
        cout.WriteLine(ans);
    }
}

public partial class Deque<T> {
    private T[] _array;
    private int _head;
    private int _tail;
    public int Count { get; private set; }

    public Deque(int capacity = 16) {
        _array = new T[capacity];
        _head = 0;
        _tail = 0;
    }

    public void Clear() {
        _head = _tail = Count = 0;
    }

    public void PushBack(T value) {
        if (Count + 1 == _array.Length) {
            Expand();
        }
        Count++;

        _array[_tail++] = value;
        if (_tail == _array.Length) {
            _tail = 0;
        }
    }

    public void PushFront(T value) {
        if (Count + 1 == _array.Length) {
            Expand();
        }
        Count++;

        if (--_head == -1) {
            _head += _array.Length;
        }
        _array[_head] = value;
    }

    public T PopBack() {
        if (Count == 0) {
            throw new Exception("empty");
        }

        Count--;
        if (--_tail == -1) {
            _tail += _array.Length;
        }
        return _array[_tail];
    }

    public T PeekBack() {
        if (Count == 0) {
            throw new Exception("empty");
        }

        return this[Count - 1];
    }

    public T PopFront() {
        if (Count == 0) {
            throw new Exception("empty");
        }

        var ret = _array[_head];
        Count--;
        if (++_head == _array.Length) {
            _head = 0;
        }
        return ret;
    }

    public T PeekFront() {
        if (Count == 0) {
            throw new Exception("empty");
        }

        return _array[_head];
    }

    public T this[int index] {
        get {
            if (index < 0 || index >= Count) {
                throw new Exception("Invalid index");
            }
            index += _head;
            if (index >= _array.Length) {
                index -= _array.Length;
            }

            return _array[index];
        }
        set {
            if (index < 0 || index >= Count) {
                throw new Exception("Invalid index");
            }
            index += _head;
            if (index >= _array.Length) {
                index -= _array.Length;
            }

            _array[index] = value;
        }
    }

    private void Expand() {
        var newarray = new T[_array.Length * 2];

        if (_head < _tail) {
            Array.Copy(_array, _head, newarray, 0, Count);
        } else {
            Array.Copy(_array, _head, newarray, 0, _array.Length - _head);
            Array.Copy(_array, 0, newarray, _array.Length - _head, _tail);
        }

        _array = newarray;
        _head = 0;
        _tail = Count == newarray.Length ? 0 : Count;
    }

}
// PREWRITEN CODE BEGINS FROM HERE

static public class StringExtensions {
    static public string JoinToString<T>(this IEnumerable<T> source, string separator = " ") {
        return string.Join(separator, source);
    }
}

internal partial class Solver : Scanner {
    static readonly int? StackSizeInMebiByte = null; //50;
    public static void StartAndJoin(Action action, int maxStackSize) {
        var thread = new Thread(new ThreadStart(action), maxStackSize);
        thread.Start();
        thread.Join();
    }

    public static void Main() {
#if LOCAL
        byte[] inputBuffer = new byte[1000000];
        var inputStream = Console.OpenStandardInput(inputBuffer.Length);
        using (var reader = new StreamReader(inputStream, Console.InputEncoding, false, inputBuffer.Length)) {
            Console.SetIn(reader);
            new Solver(Console.In, Console.Out).Run();
        }
#else
        Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false });
        if (StackSizeInMebiByte.HasValue) {
            StartAndJoin(() => new Solver(Console.In, Console.Out).Run(), StackSizeInMebiByte.Value * 1024 * 1024);
        } else {
            new Solver(Console.In, Console.Out).Run();
        }
        Console.Out.Flush();
#endif
    }

#pragma warning disable IDE0052
    private readonly TextReader cin;
    private readonly TextWriter cout;
    private readonly TextWriter cerr;
#pragma warning restore IDE0052

    public Solver(TextReader reader, TextWriter writer)
        : base(reader) {
        cin = reader;
        cout = writer;
        cerr = Console.Error;
    }

    public Solver(string input, TextWriter writer)
        : this(new StringReader(input), writer) {
    }

#pragma warning disable IDE1006
#pragma warning disable IDE0051
    private int ni() { return NextInt(); }
    private int[] ni(int n) { return NextIntArray(n); }
    private long nl() { return NextLong(); }
    private long[] nl(int n) { return NextLongArray(n); }
    private double nd() { return NextDouble(); }
    private double[] nd(int n) { return NextDoubleArray(n); }
    private string ns() { return Next(); }
    private string[] ns(int n) { return NextArray(n); }
#pragma warning restore IDE1006
#pragma warning restore IDE0051
}

#if DEBUG
internal static class LinqPadExtension {
    public static string TextDump<T>(this T obj) {
        if (obj is IEnumerable) return (obj as IEnumerable).Cast<object>().JoinToString().Dump();
        else return obj.ToString().Dump();
    }
    public static T Dump<T>(this T obj) {
        return LINQPad.Extensions.Dump(obj);
    }
}
#endif

public class Scanner {
    private readonly TextReader Reader;
    private readonly CultureInfo ci = CultureInfo.InvariantCulture;

    private readonly char[] buffer = new char[2 * 1024];
    private int cursor = 0, length = 0;
    private string Token;
    private readonly StringBuilder sb = new StringBuilder(1024);

    public Scanner()
        : this(Console.In) {
    }

    public Scanner(TextReader reader) {
        Reader = reader;
    }

    public int NextInt() { return checked((int)NextLong()); }
    public long NextLong() {
        var s = Next();
        long r = 0;
        int i = 0;
        bool negative = false;
        if (s[i] == '-') {
            negative = true;
            i++;
        }
        for (; i < s.Length; i++) {
            r = r * 10 + (s[i] - '0');
#if DEBUG
            if (!char.IsDigit(s[i])) throw new FormatException();
#endif
        }
        return negative ? -r : r;
    }
    public double NextDouble() { return double.Parse(Next(), ci); }
    public string[] NextArray(int size) {
        string[] array = new string[size];
        for (int i = 0; i < size; i++) {
            array[i] = Next();
        }

        return array;
    }
    public int[] NextIntArray(int size) {
        int[] array = new int[size];
        for (int i = 0; i < size; i++) {
            array[i] = NextInt();
        }

        return array;
    }

    public long[] NextLongArray(int size) {
        long[] array = new long[size];
        for (int i = 0; i < size; i++) {
            array[i] = NextLong();
        }

        return array;
    }

    public double[] NextDoubleArray(int size) {
        double[] array = new double[size];
        for (int i = 0; i < size; i++) {
            array[i] = NextDouble();
        }

        return array;
    }

    public string Next() {
        if (Token == null) {
            if (!StockToken()) {
                throw new Exception();
            }
        }
        var token = Token;
        Token = null;
        return token;
    }

    public bool HasNext() {
        if (Token != null) {
            return true;
        }

        return StockToken();
    }

    private bool StockToken() {
        while (true) {
            sb.Clear();
            while (true) {
                if (cursor >= length) {
                    cursor = 0;
                    if ((length = Reader.Read(buffer, 0, buffer.Length)) <= 0) {
                        break;
                    }
                }
                var c = buffer[cursor++];
                if (33 <= c && c <= 126) {
                    sb.Append(c);
                } else {
                    if (sb.Length > 0) break;
                }
            }

            if (sb.Length > 0) {
                Token = sb.ToString();
                return true;
            }

            return false;
        }
    }
}