void main() {
  problem();
}

void problem() {
  auto H = scan!int;
  auto W = scan!int;
  auto Cy = scan!int - 1;
  auto Cx = scan!int - 1;
  auto Dx = scan!int - 1;
  auto Dy = scan!int - 1;
  auto MAP = H.iota.map!(y => scan.map!(x => x == '.').array).array;
  bool asMap(Point p) { return MAP[p.y][p.x]; }

  Area[] splitAreas() {
    Area[] areas;
    bool[][] visited = H.iota.map!(_ => W.iota.map!(_ => false).array).array;
    bool unvisited(Point p) { return visited[p.y][p.x] == false; }

    for(int x = 0; x < W; x++) {
      for(int y = 0; y < H; y++) {
        auto entry = Point(x, y);
        if (asMap(entry) == false) continue;
        if (visited[entry.y][entry.x]) continue;

        Area area;
        Point[] newPoints = [entry];
        while(newPoints.length > 0) {
          Point[] nextPoints;
          foreach(p; newPoints) {
            area ~= p;
            visited[p.y][p.x] = true;
            if (p.x > 0) {
              Point pp = Point(p.x - 1, p.y);
              if (unvisited(pp) && asMap(pp)) {
                nextPoints ~= pp;
                visited[pp.y][pp.x] = true;
              }
            }
            if (p.y > 0) {
              Point pp = Point(p.x, p.y - 1);
              if (unvisited(pp) && asMap(pp)) {
                nextPoints ~= pp;
                visited[pp.y][pp.x] = true;
              }
            }
            if (p.x < W - 1) {
              Point pp = Point(p.x + 1, p.y);
              if (unvisited(pp) && asMap(pp)) {
                nextPoints ~= pp;
                visited[pp.y][pp.x] = true;
              }
            }
            if (p.y < H - 1) {
              Point pp = Point(p.x, p.y + 1);
              if (unvisited(pp) && asMap(pp)) {
                nextPoints ~= pp;
                visited[pp.y][pp.x] = true;
              }
            }
          }
          newPoints = nextPoints;
        }

        areas ~= area;
      }
    }
    return areas;
  }

  class StructedArea {
    bool[int] bits;

    this(Area area) {
      foreach(p; area) {
        bits[p.x * 10000 + p.y] = true;
      }
    }

    bool contains(int x, int y) {
      auto k = x * 10000 + y;
      return (k in bits) != null;
    }

    bool canWarpTo(StructedArea other) {
      if (other == this) return false;

      foreach(k; bits.keys) {
        int x = k / 10000;
        int y = k % 10000;
        auto ss = [
          [x-2, y-2], [x-1, y-2], [x-0, y-2], [x+1, y-2], [x+2, y-2],
          [x-2, y-1], [x-1, y-1]            , [x+1, y-1], [x+2, y-1],
          [x-2, y-0],                                     [x+2, y-0],
          [x-2, y+1], [x-1, y+1]            , [x+1, y+1], [x+2, y+1],
          [x-2, y+2], [x-1, y+2], [x-0, y+2], [x+1, y+2], [x+2, y+2]
        ];
        foreach(s; ss) {
          if (other.contains(s[0], s[1])) return true;
        }
      }
      
      return false;
    }
  }

  long solve() {
    long ans;
    auto areas = splitAreas().map!(a => new StructedArea(a)).array;

    bool[ulong][ulong] warps;
    foreach(i; 0..areas.length) {
      bool[ulong] w;
      warps[i] = w;
    }

    foreach(i, from; areas[0..$-1]) {
      foreach(jm, to; areas[i+1..$]) {
        auto j = jm + i + 1;
        if (from.canWarpTo(to)) {
          warps[i][j] = true;
          warps[j][i] = true;
        }
      }
    }
    warps.deb;

    ulong startArea;
    foreach(i, area; areas) {
      if (area.contains(Cx, Cy)) {
        startArea = i;
        break;
      }
    }

    ulong goalArea;
    foreach(i, area; areas) {
      if (area.contains(Dx, Dy)) {
        goalArea = i;
        break;
      }
    }

    [startArea, goalArea].deb;

    bool[ulong] routes;
    routes[startArea] = true;
    while((goalArea in routes) == null) {
    routes.deb;
      foreach(r; routes) {
        foreach(k; warps[r].keys) routes[k] = true;
      }
      ans++;
    }

    return ans;
  }

  solve().writeln;
}

// ----------------------------------------------

import std.stdio, std.conv, std.array, std.string, std.algorithm, std.container, std.range, core.stdc.stdlib, std.math, std.typecons, std.numeric;
T[][] combinations(T)(T[] s, in int m) {   if (!m) return [[]];   if (s.empty) return [];   return s[1 .. $].combinations(m - 1).map!(x => s[0] ~ x).array ~ s[1 .. $].combinations(m); }
string scan(){ static string[] ss; while(!ss.length) ss = readln.chomp.split; string res = ss[0]; ss.popFront; return res; }
T scan(T)(){ return scan.to!T; }
T[] scan(T)(int n){ return n.iota.map!(i => scan!T()).array; }
void deb(T ...)(T t){ debug writeln(t); }
alias Point = Tuple!(int, "x", int, "y");
alias Area = Point[];

// -----------------------------------------------
