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 = math.floor(newk / 2)
    local k = newk
    while ku > 0 and self.lower(ku, k) do
        self:_swap(ku, k)
        k = math.floor(k/2)
        ku = math.floor(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 <= math.floor(#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
--------------------------------------
local K1 = 10000
local INF = math.floor(10^18)
--
local abs = math.abs
local floor = math.floor
--
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 = floor(id / K1), id % K1
    return h, w
end
local function make_tuple(id, weight)
    return {weight, id}
end
local function unpack_tuple(t)
    return t[1], t[2]
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[1] < v2[1]
    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
                --richtraceback()
                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)

Measured memory_bytes: 51076