import java.io.BufferedReader
import java.io.InputStream
import java.io.InputStreamReader
import java.lang.AssertionError
import java.util.*
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min

val MOD = 1_000_000_007L

val INF = 1e18.toLong()
fun dijk2(g: Array<List<Int>>, s: Int): LongArray {
  val n = g.size
  val D = LongArray(n){INF}
  D[s] = 0
  val visited = BooleanArray(n)
  val que = IntArray(n)
  var h = 0
  var t = 0
  que[h++] = s
  while(h > t) {
    val u = que[t++]
    if (visited[u]) continue
    visited[u] = true

    for (v in g[u]) {
      if (D[u] + 1 < D[v]) {
        D[v] = D[u] + 1
        que[h++] = v
      }
    }
  }
  return D
}
class UnionFind(n: Int) {
  private val par = IntArray(n){it}
  private val rank = IntArray(n){1} // 集合の要素数
  private val visits = IntArray(n) // 訪れた場所をfind毎に用意するのがもったいないのでつかいまわす

  fun find(x: Int): Int {
    var ptr = 0
    var i = x
    while(par[i] != i) {
      visits[ptr++] = i
      i = par[i]
    }

    for (j in 0 until ptr) {
      par[visits[j]] = i
    }
    return i
  }

  private fun merge(node: Int, rt: Int): Int {
    par[node] = rt
    rank[rt] += rank[node]
    return rt
  }

  fun unite(x: Int, y: Int): Boolean {
    val x1 = find(x)
    val y1 = find(y)
    return if (x1 == y1) false
    else {
      if (rank[x1] < rank[y1])
        merge(x1, y1)
      else
        merge(y1, x1)

      true
    }
  }

  fun isSame(x: Int, y: Int) = find(x) == find(y)

  fun isRoot(x: Int) = par[x] == x

  /**
   * xを解決する必要がないときは直にrankをみる
   */
  fun cntNodes(x: Int): Int = rank[find(x)]

  fun inspect() = run{par}
}
class Solver(stream: InputStream, private val out: java.io.PrintWriter) {
  fun solve() {
    val N = ni()
    val M = ni()
    val Ch = ni() - 1
    val Cw = ni() - 1
    val Dh = ni() - 1
    val Dw = ni() - 1
    val mat = Array(N) { ns().map{it == '.'} }

    val D = arrayOf(
      intArrayOf(1, 0),
      intArrayOf(0, 1),
      intArrayOf(-1, 0),
      intArrayOf(0, -1)
    )
    val uf = UnionFind(N * M)
    for (h in 0 until N) {
      for (w in 0 until M) {
        if (!mat[h][w]) continue
        for (d in D) {
          if (h + d[0] in (0 until N) && w + d[1] in (0 until M) && mat[h+d[0]][w+d[1]]) {
            uf.unite(h*M + w, (h + d[0])*M + w + d[1])
          }
        }
      }
    }
    val g0 = Array(N * M) { mutableListOf<Int>() }
    for (h in 0 until N) {
      for (w in 0 until M) {
        if (!mat[h][w]) continue
        val u = uf.find(h*M + w)
        debug{"$h:$w $u"}
        for (i in -2 .. 2) {
          for (j in -2 .. 2) {
            if (h + i in (0 until N) && w + j in (0 until M) && mat[h+i][w+j]) {
              val v = uf.find((h + i)*M + w + j)
              debug{"$h:$w $u $v"}
              if (u != v) g0[u].add(v)
            }
          }
        }
      }
    }

    val g = Array(N * M) {
      g0[it].distinct()
    }
    debug{g.joinToString(" ")}

    val dist = dijk2(g, uf.find(Ch*M + Cw))
    val ans = dist[uf.find(Dh*M + Dw)]
    out.println(if (ans == INF) -1 else ans)
  }










































  private val isDebug = try {
    // なんか本番でエラーでる
    System.getenv("MY_DEBUG") != null
  } catch (t: Throwable) {
    false
  }

  private var tokenizer: StringTokenizer? = null
  private val reader = BufferedReader(InputStreamReader(stream), 32768)
  private fun next(): String {
    while (tokenizer == null || !tokenizer!!.hasMoreTokens()) {
      tokenizer = StringTokenizer(reader.readLine())
    }
    return tokenizer!!.nextToken()
  }

  private fun ni() = next().toInt()
  private fun nl() = next().toLong()
  private fun ns() = next()
  private fun na(n: Int, offset: Int = 0): IntArray {
    return map(n) { ni() + offset }
  }
  private fun nal(n: Int, offset: Int = 0): LongArray {
    val res = LongArray(n)
    for (i in 0 until n) {
      res[i] = nl() + offset
    }
    return res
  }

  private fun na2(n: Int, offset: Int = 0): Array<IntArray> {
    val a  = Array(2){IntArray(n)}
    for (i in 0 until n) {
      for (e in a) {
        e[i] = ni() + offset
      }
    }
    return a
  }

  private inline fun map(n: Int, f: (Int) -> Int): IntArray {
    val res = IntArray(n)
    for (i in 0 until n) {
      res[i] = f(i)
    }
    return res
  }

  private inline fun debug(msg: () -> String) {
    if (isDebug) System.err.println(msg())
  }

  private inline fun debug(a: LongArray) {
    debug { a.joinToString(" ") }
  }

  private inline fun debug(a: IntArray) {
    debug { a.joinToString(" ") }
  }

  private inline fun debug(a: BooleanArray) {
    debug { a.map { if (it) 1 else 0 }.joinToString("") }
  }

  private inline fun debugDim(A: Array<LongArray>) {
    if (isDebug) {
      for (a in A) {
        debug(a)
      }
    }
  }
  private inline fun debugDim(A: Array<IntArray>) {
    if (isDebug) {
      for (a in A) {
        debug(a)
      }
    }
  }

  /**
   * 勝手にimport消されるのを防ぎたい
   */
  private fun hoge() {
    min(1, 2)
    max(1, 2)
    abs(-10)
  }

  private inline fun assert(b: Boolean) = run{if (!b) throw AssertionError()}
}

fun main() {
  val out = java.io.PrintWriter(System.out)
  Solver(System.`in`, out).solve()
  out.flush()
}


Measured memory_bytes: 192828