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 Lua (Lua 5.3.5) (judge verdict: Time Limit Exceeded)

local read = setmetatable({}, {__index = function(t, k) local a = {} for i=1,#k do table.insert(a, '*'..string.sub(k, i, i)) end local r = io.read local u = table.unpack or unpack return function() return r(u(a)) end end})
read.N = function(N) local t={} for i=1,N do t[i]=read.n() end return t end
string.totable = function(s) local t={} local u=string.sub for i=1,#s do t[i] = u(s, i, i) end return t end
string.split = function(s) local t={} for w in string.gmatch(s, "[^%s]+") do table.insert(t, w) end return (table.unpack or unpack)(t) end
local function array(dimensi0n, default_val) assert(type(default_val) ~= 'table') local n=dimensi0n local m={}if default_val~=nil then m[1]={__index=function()return default_val end}end for i=2,n do m[i]={__index=function(p, k)local c=setmetatable({},m[i-1])rawset(p,k,c)return c end}end return setmetatable({},m[n])end
local function tostringxx(o, depth) depth = depth or 0 if depth > 10 then return "<too deep!>" end if o == _G then return "<_G>" end local indent0 = (" "):rep((depth) * 2) local indent1 = (" "):rep((depth+1) * 2) local indent2= (" "):rep((depth+2) * 2) if type(o) == 'table' then local keys = {} local types = {} for k in pairs(o) do types[type(k)] = true table.insert(keys, k) end local types_count = 0 local lasttype for k in pairs(types) do types_count = types_count + 1 lasttype = k end if types_count == 1 and (lasttype == 'string' or lasttype == 'number') then table.sort(keys) end local inside = {} for i=1,#keys do local k = keys[i] local v = o[k] if type(k) == 'string' then k = string.format('%q', k) end table.insert(inside, indent1 .. '['..tostring(k)..'] = ' .. tostringxx(v, depth + 1)) end return '{\n' .. table.concat(inside, ',\n') .. '\n' .. indent0 .. '}' else if type(o) == 'string' then o = string.format('%q', o) end return tostring(o) end end
local function richtraceback() local x = 2 while true do local info = debug.getinfo(x) if not info then break end local fname = '<' .. info.short_src .. ":" .. info.linedefined .. ">" if info.name then fname = info.name end print(info.short_src .. ":" .. info.currentline .. ": in " .. ("%q"):format(fname)) print(" LOCALS:") local p = 1 while true do local name, val = debug.getlocal(x,p) if not name then break end print(" " .. name .. ": " .. tostringxx(val, 3)) p = p + 1 end print(" UPVALUES:") for p=1,info.nups do local name, val = debug.getupvalue(info.func,p) if not name then break end print(" " .. name .. ": " .. tostringxx(val, 3)) end x = x + 1 end end
local function myassert(b) if not b then richtraceback() error("assertion failed") end end 
--
-- heap
local Heap = {}
function Heap.new(upper_func)
    local self = setmetatable({}, {__index = Heap})
    self.a = {}
    self.upper_func = upper_func
    self.upper = function(k1, k2)
        --assert(k1 < k2)
        if k1 == 0 then
            return false
        else
            return upper_func(self.a[k1], self.a[k2])
        end
    end
    self.lower = function(k1, k2)
        return not self.upper(k1, k2)
    end
    return self
end

function Heap:count()
    return #self.a
end

function Heap:_swap(k1, k2)
    local old_k1 = self.a[k1]
    self.a[k1] = self.a[k2]
    self.a[k2] = old_k1
end

function Heap:upheap(newk)
    local ku = newk // 2
    local k = newk
    while ku > 0 and self.lower(ku, k) do
        self:_swap(ku, k)
        k = k//2
        ku = ku//2
    end
end

function Heap:insertq(e)
    table.insert(self.a, e)
    self:upheap(#self.a)
end

function Heap:downheap(newk)
    local k = newk
    while k <= #self.a//2 do
        local kdl = k*2
        local kdr = kdl + 1
        local kd
        if kdr <= #self.a and self.lower(kdl, kdr) then
            kd = kdr
        else
            kd = kdl
        end
        if self.upper(k, kd) then
            break
        end
        self:_swap(k, kd)
        k = kd
    end
end

function Heap:top()
    assert(#self.a >= 1)
    return self.a[1]
end

function Heap:remove_top()
    --assert(#self.a >= 1)
    local v = self.a[1]
    self:_swap(1, #self.a)
    table.remove(self.a)
    self:downheap(1)
    return v
end

function Heap:replace_top(e)
    assert(#self.a >= 1)
    local old_v = self.a[1]
    local swapped = false
    if self.upper_func(old_v, e) then
        self.a[1] = e
        self:downheap(1)
        swapped = true
    end
    return swapped, old_v
end

--------------------------------------

local K1 = 10000
local K2 = K1 * K1
local INF = math.floor(10^18)
--
local abs = math.abs
--
local H, W = read.nn()
local Ch, Cw = read.nn()
local Dh, Dw = read.nnl()
local S = {}
for i=1,H do
    S[i] = read.l():totable()
end
local function isopen(h, w)
    return S[h] and S[h][w] == '.'
end
local function getid(h, w)
    return w + h * K1
end
local function gethw(id)
    local h, w = id // K1, id % K1
    return h, w
end
local function make_tuple(id, weight)
    return weight * K2 + id
end
local function unpack_tuple(t)
    local weight, id = t // K2, t % K2
    return weight, id
end

-- dijkstra's algorithm
local function find_mincost(srch, srcw, dsth, dstw)
    local srcid = getid(srch, srcw)
    local dstid = getid(dsth, dstw)
    local from_src = {} -- if v is unreachable, from_src[v] == nil.
    from_src[srcid] = 0
    local q = Heap.new(function (v1, v2)
        --local w1 = unpack_tuple(v1)
        --local w2 = unpack_tuple(v2)
        --return w1 < w2
        return v1 // K2 < v2 // K2
    end)
    local finished = {}
    q:insertq(make_tuple(srcid, 0))
    while q:count() > 0 do
        local elem = q:remove_top()
        local cur_d, id = unpack_tuple(elem)
        if not finished[id] then
            finished[id] = true
            if id == dstid then
                return cur_d
            end
            local h, w = gethw(id)
            for dh=-2,2 do
                for dw=-2,2 do
                    if isopen(h+dh,w+dw) then
                        local aa = abs(dh)+abs(dw)
                        if aa == 0 then
                            -- 5x5 center
                        else
                            -- move A or B?
                            local step = (aa == 1) and 0 or 1
                            local toid = getid(h+dh,w+dw)
                            if not finished[toid] then
                                -- compare costs
                                local before = from_src[toid] or INF
                                local after = cur_d + step
                                if after < before then
                                    from_src[toid] = after
                                    q:insertq(make_tuple(toid, after))
                                end
                            end
                        end
                    end
                end
            end
        end
    end
    return -1
end

local cost = find_mincost(Ch, Cw, Dh, Dw)
print(cost)