import java.io.*;
import java.util.LinkedList;
import java.util.StringTokenizer;

public class Main {
    static int H;
    static int W;
    static int Ch;
    static int Cw;
    static int Dh;
    static int Dw;
    static char[][] maze;
    static boolean[][] find;
    static int[] X = new int[] { 0, 1, 0, -1 };
    static int[] Y = new int[] { 1, 0, -1, 0 };
    static int ans = Integer.MAX_VALUE;
    static boolean findAns = false;

    public static void main(String[] args) {
        MyScanner sc = new MyScanner();
        H = sc.nextInt();
        W = sc.nextInt();
        Ch = sc.nextInt() - 1;
        Cw = sc.nextInt() - 1;
        Dh = sc.nextInt() - 1;
        Dw = sc.nextInt() - 1;
        maze = new char[H][W];
        find = new boolean[H][W];
        for (int i = 0; i < H; i++) {
            String s = sc.next();
            maze[i] = s.toCharArray();
        }
        LinkedList<int[]> queue = new LinkedList<>();
        dfs(Ch, Cw, queue, 0);
        int count = 1;
        while (!queue.isEmpty() && ans == Integer.MAX_VALUE) {
            int size = queue.size();
            for (int a = 0; a < size; a++) {
                int[] pop = queue.pollFirst();
                if (inMaze(pop[0], pop[1])) {
                    int newX = pop[0] - 2;
                    int newY = pop[1] - 2;
                    for (int i = newX; i < newX + 5; i++) {
                        for (int j = newY; j < newY + 5; j++) {
                            if (inMaze(i, j)) {
                                if (!find[i][j] && maze[i][j] != '#') {
                                    dfs(i, j, queue, count);
                                }
                            }
                        }
                    }
                }
            }
            count++;
        }
        System.out.println(ans == Integer.MAX_VALUE ? -1 : ans);
    }

    public static void dfs(int height, int width, LinkedList<int[]> queue, int count) {
        if (!inMaze(height, width)) {
            return;
        }
        if (find[height][width] || maze[height][width] == '#')
            return;
        find[height][width] = true;
        if (height == Dh && width == Dw) {
            ans = Math.min(count, ans);
            findAns = true;
        }
        queue.addLast(new int[] {height, width});
        for (int i = 0; i < 4; i++) {
            int newX = height + X[i];
            int newY = width + Y[i];
            dfs(newX, newY, queue, count);
        }
    }

    public static boolean inMaze(int x, int y) {
        return x >= 0 && x < maze.length && y >= 0 && y < maze[0].length;
    }

    public static PrintWriter out;

    public static class MyScanner {
        BufferedReader br;
        StringTokenizer st;

        public MyScanner() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        double nextDouble() {
            return Double.parseDouble(next());
        }

        String nextLine(){
            String str = "";
            try {
                str = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }

    }
}


import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.NoSuchElementException;

public class Main {

	static int H;
	static int W;
	static int Ch;
	static int Cw;
	static int Dh;
	static int Dw;
	static char[][] maze;
	static boolean[][] find;
	static int[] X = new int[] { 0, 1, 0, -1 };
	static int[] Y = new int[] { 1, 0, -1, 0 };
	static int ans = Integer.MAX_VALUE;
	static boolean findAns = false;

	public static void main(String[] args) {
		FastScanner sc = new FastScanner();
		H = sc.nextInt();
		W = sc.nextInt();
		Ch = sc.nextInt() - 1;
		Cw = sc.nextInt() - 1;
		Dh = sc.nextInt() - 1;
		Dw = sc.nextInt() - 1;
		maze = new char[H][W];
		find = new boolean[H][W];
		for (int i = 0; i < H; i++) {
			String s = sc.next();
			maze[i] = s.toCharArray();
		}
		LinkedList<int[]> queue = new LinkedList<>();
		dfs(Ch, Cw, queue, 0);
		int count = 1;
		while (!queue.isEmpty() && ans == Integer.MAX_VALUE) {
			int size = queue.size();
			for (int z = 0; z < size; z++) {
				int[] pop = queue.pollFirst();
				if (inMaze(pop[0], pop[1])) {
					int newX = pop[0] - 2;
					int newY = pop[1] - 2;
					for (int i = newX; i < newX + 5; i++) {
						for (int j = newY; j < newY + 5; j++) {
							if (inMaze(i, j)) {
								if (!find[i][j] && maze[i][j] != '#') {
									dfs(i, j, queue, count);
								}
							}
						}
					}
				}
			}
			count++;
		}
		System.out.println(ans == Integer.MAX_VALUE ? -1 : ans);
	}

	public static void dfs(int h, int w, LinkedList<int[]> queue, int count) {
		if (!inMaze(h, w)) {
			return;
		}
		if (find[h][w] || maze[h][w] == '#')
			return;
		find[h][w] = true;
		if (h == Dh && w == Dw) {
			ans = Math.min(count, ans);
			findAns = true;
		}
		queue.addLast(new int[] {h, w});
		for (int i = 0; i < 4; i++) {
			int newX = h + X[i];
			int newY = w + Y[i];
			dfs(newX, newY, queue, count);
		}
	}

	public static boolean inMaze(int x, int y) {
		return x >= 0 && x < maze.length && y >= 0 && y < maze[0].length;
	}

}

class FastScanner {
	private final InputStream in = System.in;
	private final byte[] buffer = new byte[1024];
	private int ptr = 0;
	private int buflen = 0;

	private boolean hasNextByte() {
		if (ptr < buflen) {
			return true;
		} else {
			ptr = 0;
			try {
				buflen = in.read(buffer);
			} catch (IOException e) {
				e.printStackTrace();
			}
			if (buflen <= 0) {
				return false;
			}
		}
		return true;
	}

	private int readByte() {
		if (hasNextByte())
			return buffer[ptr++];
		else
			return -1;
	}

	private static boolean isPrintableChar(int c) {
		return 33 <= c && c <= 126;
	}

	public boolean hasNext() {
		while (hasNextByte() && !isPrintableChar(buffer[ptr]))
			ptr++;
		return hasNextByte();
	}

	public String next() {
		if (!hasNext())
			throw new NoSuchElementException();
		StringBuilder sb = new StringBuilder();
		int b = readByte();
		while (isPrintableChar(b)) {
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	public long nextLong() {
		if (!hasNext())
			throw new NoSuchElementException();
		long n = 0;
		boolean minus = false;
		int b = readByte();
		if (b == '-') {
			minus = true;
			b = readByte();
		}
		if (b < '0' || '9' < b) {
			throw new NumberFormatException();
		}
		while (true) {
			if ('0' <= b && b <= '9') {
				n *= 10;
				n += b - '0';
			} else if (b == -1 || !isPrintableChar(b)) {
				return minus ? -n : n;
			} else {
				throw new NumberFormatException();
			}
			b = readByte();
		}
	}

	public int nextInt() {
		long nl = nextLong();
		if (nl < Integer.MIN_VALUE || nl > Integer.MAX_VALUE)
			throw new NumberFormatException();
		return (int) nl;
	}

	public double nextDouble() {
		return Double.parseDouble(next());
	}
}


// Utilities
import java.io.*;
import java.util.*;

public class Main {
	static int H, W;
	static int sr, sc, er, ec;
	static char[][] grid;
	static boolean[][] vis;
	static Stack<Pair> stk, nstk;
	static int magic = -1;

	public static void main(String[] args) throws IOException {
		H = in.iscan(); W = in.iscan();
		sr = in.iscan()-1; sc = in.iscan()-1; er = in.iscan()-1; ec = in.iscan()-1;
		grid = new char[H][W];
		for (int i = 0; i < H; i++) {
			grid[i] = in.sscan().toCharArray();
		}
		vis = new boolean[H][W];
		while (!vis[er][ec]) {
			magic++;
			if (magic == 0) {
				stk = new Stack<Pair>();
				bfs(sr, sc);
			}
			else {
				nstk = new Stack<Pair>();
				while (!stk.isEmpty()) {
					Pair pi = stk.pop();
					for (int i = Math.max(0, pi.r - 2); i <= Math.min(H-1, pi.r + 2); i++) {
						for (int j = Math.max(0, pi.c - 2); j <= Math.min(W-1, pi.c + 2); j++) {
							if (!vis[i][j] && grid[i][j] == '.') {
								bfs(i, j);
							}
						}
					}
				}
				for (Pair pi : nstk) stk.push(new Pair(pi.r, pi.c));
				if (stk.isEmpty() && !vis[er][ec]) {
					out.println(-1);
					out.close();
					System.exit(0);
				}
			}
		}
		out.println(magic);
		out.close();
	}

	static int[][] d = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
	static void bfs(int r, int c) {
		Queue<Pair> q = new LinkedList<Pair>();
		q.add(new Pair(r, c));
		if (magic == 0) stk.push(new Pair(r, c));
		else nstk.push(new Pair(r, c));
		vis[r][c] = true;
		while (!q.isEmpty()) {
			Pair p = q.poll();
			for (int i = 0; i < 4; i++) {
				int nr = p.r + d[i][0], nc = p.c + d[i][1];
				if (nr >= 0 && nr < H && nc >= 0 && nc < W && grid[nr][nc] == '.' && !vis[nr][nc]) {
					vis[nr][nc] = true;
					q.add(new Pair(nr, nc));
					if (magic == 0) stk.push(new Pair(nr, nc));
					else nstk.push(new Pair(nr, nc));
				}
			}
		}
	}

	static class Pair {
		int r, c;
		Pair(int r, int c){ this.r = r; this.c = c; }
	}

	static INPUT in = new INPUT(System.in);
	static PrintWriter out = new PrintWriter(System.out);
	private static class INPUT {

		private InputStream stream;
		private byte[] buf = new byte[1024];
		private int curChar, numChars;

		public INPUT (InputStream stream) {
			this.stream = stream;
		}

		public INPUT (String file) throws IOException {
			this.stream = new FileInputStream (file);
		}

		public int cscan () throws IOException {
			if (curChar >= numChars) {
				curChar = 0;
				numChars = stream.read (buf);
			}

			if (numChars == -1)
				return numChars;

			return buf[curChar++];
		}

		public int iscan () throws IOException {
			int c = cscan (), sgn = 1;

			while (space (c))
				c = cscan ();

			if (c == '-') {
				sgn = -1;
				c = cscan ();
			}

			int res = 0;

			do {
				res = (res << 1) + (res << 3);
				res += c - '0';
				c = cscan ();
			}
			while (!space (c));

			return res * sgn;
		}

		public String sscan () throws IOException {
			int c = cscan ();

			while (space (c))
				c = cscan ();

			StringBuilder res = new StringBuilder ();

			do {
				res.appendCodePoint (c);
				c = cscan ();
			}
			while (!space (c));

			return res.toString ();
		}

		public double dscan () throws IOException {
			int c = cscan (), sgn = 1;

			while (space (c))
				c = cscan ();

			if (c == '-') {
				sgn = -1;
				c = cscan ();
			}

			double res = 0;

			while (!space (c) && c != '.') {
				if (c == 'e' || c == 'E')
					return res * UTILITIES.fast_pow (10, iscan ());

				res *= 10;
				res += c - '0';
				c = cscan ();
			}

			if (c == '.') {
				c = cscan ();
				double m = 1;

				while (!space (c)) {
					if (c == 'e' || c == 'E')
						return res * UTILITIES.fast_pow (10, iscan ());

					m /= 10;
					res += (c - '0') * m;
					c = cscan ();
				}
			}

			return res * sgn;
		}

		public long lscan () throws IOException {
			int c = cscan (), sgn = 1;

			while (space (c))
				c = cscan ();

			if (c == '-') {
				sgn = -1;
				c = cscan ();
			}

			long res = 0;

			do {
				res = (res << 1) + (res << 3);
				res += c - '0';
				c = cscan ();
			}
			while (!space (c));

			return res * sgn;
		}

		public boolean space (int c) {
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}
	}

	public static class UTILITIES {

		static final double EPS = 10e-6;

		public static int lower_bound (int[] arr, int x) {
			int low = 0, high = arr.length, mid = -1;

			while (low < high) {
				mid = (low + high) / 2;

				if (arr[mid] >= x)
					high = mid;
				else
					low = mid + 1;
			}

			return low;
		}

		public static int upper_bound (int[] arr, int x) {
			int low = 0, high = arr.length, mid = -1;

			while (low < high) {
				mid = (low + high) / 2;

				if (arr[mid] > x)
					high = mid;
				else
					low = mid + 1;
			}

			return low;
		}

		public static int gcd (int a, int b) {
			return b == 0 ? a : gcd (b, a % b);
		}

		public static int lcm (int a, int b) {
			return a * b / gcd (a, b);
		}

		public static long fast_pow_mod (long b, long x, int mod) {
			if (x == 0) return 1;
			if (x == 1) return b;
			if (x % 2 == 0) return fast_pow_mod (b * b % mod, x / 2, mod) % mod;

			return b * fast_pow_mod (b * b % mod, x / 2, mod) % mod;
		}

		public static int fast_pow (int b, int x) {
			if (x == 0) return 1;
			if (x == 1) return b;
			if (x % 2 == 0) return fast_pow (b * b, x / 2);

			return b * fast_pow (b * b, x / 2);
		}

		public static long choose (long n, long k) {
			k = Math.min (k, n - k);
			long val = 1;

			for (int i = 0; i < k; ++i)
				val = val * (n - i) / (i + 1);

			return val;
		}

		public static long permute (int n, int k) {
			if (n < k) return 0;
			long val = 1;

			for (int i = 0; i < k; ++i)
				val = (val * (n - i));

			return val;
		}
	}
}


import java.util.Deque;
import java.util.LinkedList;
import java.util.Scanner;

/**
 * Created by enpingkuang on 2020/9/11 11:30 下午
 */
public class Main {

    static class Node{
        int i;
        int j;
        int value;

        Node(int i,int j,int value){
            this.i = i;
            this.j =j;
            this.value =value;
        }
    }

    private static int[][] dir = {{-1,0},{1,0},{0,-1},{0,1}};

    private static int vis[][] = new int[1003][1003];

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int h = scanner.nextInt();
        int w = scanner.nextInt();
        int s = scanner.nextInt();
        int e= scanner.nextInt();
        int ts = scanner.nextInt();
        int te = scanner.nextInt();
        String[] map = new String[h+1];
        for(int i=1;i<=h;i++){
            map[i] =scanner.next();
        }
        for(int i = 1;i<=h;i++){
            for(int j = 1;j<=w;j++){
                vis[i][j] = 100000000;
            }
        }
        vis[s][e] = 0;
        Deque<Node> deque = new LinkedList<>();
        deque.add(new Node(s,e,0));
        while(!deque.isEmpty()){
            Node node = deque.pollFirst();
            int now_i = node.i;
            int now_j = node.j;
            int now_value = node.value;
            for(int i = 0;i<4;i++){
                int tmp_i = dir[i][0] + now_i;
                int tmp_j = dir[i][1] + now_j;
                if(tmp_i <=0 || tmp_i > h || tmp_j <=0 || tmp_j > w)continue;
                if(vis[tmp_i][tmp_j] > now_value  && map[i].charAt(tmp_j-1) != '#') {
                    deque.addFirst(new Node(tmp_i, tmp_j, now_value));
                    vis[tmp_i][tmp_j] = now_value;
                }
            }
            for(int i = now_i-2;i<=now_i+2;i++){
                if(i <=0 || i > h)continue;
                for(int j = now_j-2;j<=now_j+2;j++){
                    if(j <=0 || j > w)continue;
                    if(vis[i][j] > now_value+1 && map[i].charAt(j-1) != '#') {
                        deque.addLast(new Node(i, j, now_value+1));
                        vis[i][j] = now_value+1;
                    }
                }
            }
        }
        System.out.println(vis[ts][te] == 100000000?-1:vis[ts][te]);
    }
}


import java.util.Deque;
import java.util.LinkedList;
import java.util.Scanner;

/**
 * Created by enpingkuang on 2020/9/11 11:30 下午
 */
public class Main {

    static class Node{
        int i;
        int j;
        int value;

        Node(int i,int j,int value){
            this.i = i;
            this.j =j;
            this.value =value;
        }
    }

    private static boolean vis[][] = new boolean[1003][1003];

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int h = scanner.nextInt();
        int w = scanner.nextInt();
        int s = scanner.nextInt();
        int e= scanner.nextInt();
        int ts = scanner.nextInt();
        int te = scanner.nextInt();
        String[] map = new String[h+1];
        for(int i=1;i<=h;i++){
            map[i] =scanner.next();
        }
        Deque<Node> deque = new LinkedList<>();
        deque.add(new Node(s,e,0));
        vis[s][e] = true;
        int ans = -1;
        while(!deque.isEmpty()){
            Node node = deque.pollFirst();
            int now_i = node.i;
            int now_j = node.j;
            int now_value = node.value;
            if(now_i == ts && now_j == te){
                if(ans != -1) {
                    ans = Math.min(ans, now_value);
                }else {
                    ans = now_value;
                }
            }
            for(int i = now_i-1;i<=now_i+1;i++){
                if(i <=0 || i > h)continue;
                for(int j = now_j-1;j<=now_j+1;j++){
                    if(j <=0 || j > w)continue;
                    if(!vis[i][j] && map[i].charAt(j-1) != '#') {
                        deque.addFirst(new Node(i, j, now_value));
                        vis[i][j] = true;
                    }
                }
            }
            for(int i = now_i-2;i<=now_i+2;i+=2){
                if(i <=0 || i > h)continue;
                for(int j = now_j-2;j<=now_j+2;j+=2){
                    if(j <=0 || j > w)continue;
                    if(!vis[i][j] && map[i].charAt(j-1) != '#') {
                        deque.addLast(new Node(i, j, now_value+1));
                        vis[i][j] = true;
                    }
                }
            }
        }
        System.out.println(ans);
    }
}


import java.util.Deque;
import java.util.LinkedList;
import java.util.Scanner;

/**
 * Created by enpingkuang on 2020/9/11 11:30 下午
 */
public class Main {

    static class Node{
        int i;
        int j;
        int value;

        Node(int i,int j,int value){
            this.i = i;
            this.j =j;
            this.value =value;
        }
    }

    private static boolean vis[][] = new boolean[1003][1003];

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int h = scanner.nextInt();
        int w = scanner.nextInt();
        int s = scanner.nextInt();
        int e= scanner.nextInt();
        int ts = scanner.nextInt();
        int te = scanner.nextInt();
        String[] map = new String[h+1];
        for(int i=1;i<=h;i++){
            map[i] =scanner.next();
        }
        Deque<Node> deque = new LinkedList<>();
        deque.add(new Node(s,e,0));
        int ans = -1;
        while(!deque.isEmpty()){
            Node node = deque.pollFirst();
            int now_i = node.i;
            int now_j = node.j;
            int now_value = node.value;
            if(now_i == ts && now_j == te){
                if(ans != -1) {
                    ans = Math.min(ans, now_value);
                }else {
                    ans = now_value;
                }
            }
            for(int i = now_i-1;i<=now_i+1;i++){
                if(i <=0 || i > h)continue;
                for(int j = now_j-1;j<=now_j+1;j++){
                    if(j <=0 || j > w)continue;
                    if(!vis[i][j] && map[i].charAt(j-1) != '#') {
                        deque.addFirst(new Node(i, j, now_value));
                        vis[i][j] = true;
                    }
                }
            }
            for(int i = now_i-2;i<=now_i+2;i++){
                if(i <=0 || i > h)continue;
                for(int j = now_j-2;j<=now_j+2;j++){
                    if(j <=0 || j > w)continue;
                    if(!vis[i][j] && map[i].charAt(j-1) != '#') {
                        deque.addLast(new Node(i, j, now_value+1));
                        vis[i][j] = true;
                    }
                }
            }
        }
        System.out.println(ans);
    }
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const long long INF = 1e15;

int main(){
    ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);

    int h,w;
    cin >> h >> w;

    int sx,sy,gx,gy;
    cin >> sy >> sx >> gy >> gx;
    sx--;sy--;gx--;gy--;

    pair<int,int> s = make_pair(sx,sy), g = make_pair(gx,gy);
    string sur[h];

    for(int i = 0; i < h; i++) cin >> sur[i];

    auto inout = [&](int x,int y){
        if(0 <= x && x < w && 0 <= y && y < h) return true;
        else return false;
    };

    queue<pair<int,int>> p,q;

    int dx[4] = {0,0,1,-1}, dy[4] = {1,-1,0,0};

    p.push(s);

    int can = 0;

    while(!p.empty()){
        while(!p.empty()){
            pair<int,int> now = p.front();
            p.pop();
            q.push(now);
            for(int i = 0; i < 4; i++){
                pair<int,int> nxt = make_pair(now.first+dx[i],now.second+dy[i]);
                if(0 <= nxt.first && nxt.first < w && 0 <= nxt.second && nxt.second < h){
                    if(sur[nxt.second][nxt.first] == '.'){
                        if(nxt == g){
                            cout << can << endl;
                            return 0;
                        }
                        p.push(nxt);
                        sur[nxt.second][nxt.first] = '#';
                    }
                }
            }
        }
        can++;
        while(!q.empty()){
            pair<int,int> now = q.front();
            q.pop();
            for(int i = -2; i < 3; i++){
                for(int j = -2; j < 3; j++){
                    pair<int,int> nxt = make_pair(now.first+i,now.second+j);
                    if(0 <= nxt.first && nxt.first < w && 0 <= nxt.second && nxt.second < h){
                        if(sur[nxt.second][nxt.first] == '.'){
                            p.push(nxt);
                            sur[nxt.second][nxt.first] = '#';
                            if(nxt == g){
                                cout << can << endl;
                                return 0;
                            }
                        }
                    }
                }
            }
        }
    }

    cout << -1 << endl;

    return 0;
}


#include <bits/stdc++.h>

using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using usize = std::size_t;
using namespace std;

#define rep(i, max) for(i32 i = 0; i < (i32)max; ++i)
#define loop while(true)
#define allOf(collection) collection.begin(), collection.end()

unique_ptr<string> readLine() { unique_ptr<string> line(new string()); getline(cin, *line); return line; }
template<typename T1, typename T2> pair<T1, T2> readPair() { T1 res1; cin >> res1; T2 res2; cin >> res2; readLine(); return make_pair(res1, res2);}
template<typename T> unique_ptr<vector<T>> readVector(usize num) { unique_ptr<vector<T>> list(new vector<T>(num)); rep(i, num) cin >> (*list)[i]; readLine(); return list; }
void readValues() { readLine(); }
template<typename H, typename... T> void readValues(H& head, T&&... tails){ H a; cin >> a; head = a; readValues(forward<T>(tails)...); }
void writeLine() { cout << endl; }
template<typename T> void write(const T& arg) { cout << arg; }
template<typename T> void writeLine(const vector<T>& arg){ if(arg.empty()) { writeLine(); return; } write(arg[0]); for(int i = 1; i < arg.size(); ++i){ write(" "); write(arg[i]); } writeLine(); }
template<typename T> void writeLine(const T& arg) { cout << arg << endl; }
void recursiveCombination(vector<i32>& indexes, i32 s, i32 rest, function<void(vector<i32>&)> f) { if (rest == 0) { f(indexes); } else { if (s < 0) return; recursiveCombination(indexes, s - 1, rest, f); indexes[rest - 1] = s; recursiveCombination(indexes, s - 1, rest - 1, f); } }
void foreachWithCombination(i32 n, i32 k, function<void(vector<i32>&)> f) { auto indexes = vector<i32>(k); recursiveCombination(indexes, n - 1, k, f); }
void foreachWithPermutaton(i32 n, function<void(vector<i32>&)> f) { auto indexes = vector<i32>(); indexes.reserve(n); rep(i, (usize)n) indexes.push_back(i); do f(indexes); while (next_permutation(allOf(indexes))); }
void foreachWithPermutaton(i32 n, i32 k, function<void(vector<i32>&)> f){ foreachWithCombination(n, k, [=](vector<i32>& combIndexes){ foreachWithPermutaton(k, [=](vector<i32>& permIndexes){ auto indexes = vector<i32>(); indexes.reserve(k); rep(i, (usize)k){ indexes.push_back(combIndexes[permIndexes[i]]); } f(indexes); }); }); }
void program();
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    program();
}

struct Info {
    i32 h, w;
    Info(i32 h_, i32 w_){
        h = h_;
        w = w_;
    }
};

void program() {
    i32 h, w, cH, cW, dH, dW;
    readValues(h, w, cH, cW, dH, dW);
    auto s = vector<string>();
    rep(i, h){
        s.push_back(*readLine());
    }

    auto que = queue<Info>();
    s[cH - 1][cW - 1] = 'd';
    que.emplace(cH - 1, cW - 1);
    auto list = vector<set<Info>>();
    int warpCount = 0;
    bool goaled = false;
    auto newPoints = vector<Info>();
    newPoints.emplace_back(cH - 1, cW - 1);
    loop{
        auto alSet = vector<Info>();
        for(const auto& item: newPoints) {
            alSet.push_back(item);
        }

        while(!que.empty()){
            auto info = que.front();
            que.pop();

            if(info.h == dH - 1 && info.w == dW - 1) {
                goaled = true;
                goto exit5;
            }

            if(info.h + 1 < h && s[info.h + 1][info.w] == '.'){
                s[info.h + 1][info.w] = 'd';
                alSet.emplace_back(info.h + 1, info.w);
                que.emplace(info.h + 1, info.w);
            }
            if(0 <= info.h - 1 && s[info.h - 1][info.w] == '.'){
                s[info.h - 1][info.w] = 'd';
                alSet.emplace_back(info.h - 1, info.w);
                que.emplace(info.h - 1, info.w);
            }
            if(info.w + 1 < w && s[info.h][info.w + 1] == '.'){
                s[info.h][info.w + 1] = 'd';
                alSet.emplace_back(info.h, info.w + 1);
                que.emplace(info.h, info.w + 1);
            }
            if(0 <= info.w - 1 && s[info.h][info.w - 1] == '.'){
                s[info.h][info.w - 1] = 'd';
                alSet.emplace_back(info.h, info.w - 1);
                que.emplace(info.h, info.w - 1);
            }
        }
        newPoints.clear();
        for(const auto& item: alSet){
            for(i32 i = max(0, item.h - 2); i <= min(h - 1, item.h + 2); ++i){
                for(i32 j = max(0, item.w - 2); j <= min(w - 1, item.w + 2); ++j){
                    if(s[i][j] == '.') {
                        s[i][j] = 'd';
                        que.emplace(i, j);
                        newPoints.emplace_back(i, j);
                    }
                }
            }
        }
        if(newPoints.size() == 0) goto exit5;
        ++warpCount;
    }
    exit5:

    writeLine(goaled ? warpCount : -1);
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const long long INF = 1e15;

int main(){
    ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);

    int h,w;
    cin >> h >> w;

    int sx,sy,gx,gy;
    cin >> sy >> sx >> gy >> gx;
    sx--;sy--;gx--;gy--;

    pair<int,int> s = make_pair(sx,sy), g = make_pair(gx,gy);
    string sur[h];

    for(int i = 0; i < h; i++) cin >> sur[i];

    queue<pair<int,int>> p,q;

    int dx[4] = {0,0,1,-1}, dy[4] = {1,-1,0,0};

    p.push(s);

    int can = 0;

    while(!p.empty()){
        while(!p.empty()){
            pair<int,int> now = p.front();
            p.pop();
            q.push(now);
            for(int i = 0; i < 4; i++){
                pair<int,int> nxt = make_pair(now.first+dx[i],now.second+dy[i]);
                if(0 <= nxt.first && nxt.first < w && 0 <= nxt.second && nxt.second < h){
                    if(sur[nxt.second][nxt.first] == '.'){
                        if(nxt == g){
                            cout << can << endl;
                            return 0;
                        }
                        p.push(nxt);
                        sur[nxt.second][nxt.first] = '#';
                    }
                }
            }
        }
        can++;
        while(!q.empty()){
            pair<int,int> now = q.front();
            q.pop();
            for(int i = -2; i < 3; i++){
                for(int j = -2; j < 3; j++){
                    pair<int,int> nxt = make_pair(now.first+i,now.second+j);
                    if(0 <= nxt.first && nxt.first < w && 0 <= nxt.second && nxt.second < h){
                        if(sur[nxt.second][nxt.first] == '.'){
                            p.push(nxt);
                            sur[nxt.second][nxt.first] = '#';
                            if(nxt == g){
                                cout << can << endl;
                                return 0;
                            }
                        }
                    }
                }
            }
        }
    }

    cout << -1 << endl;

    return 0;
}


#include<bits/stdc++.h>
using namespace std;

int h,w;
int ch,cw;
int dh,dw;
int dx[4] = {1,-1,0,0};
int dy[4] = {0,0,1,-1};

//スタートから見て何番目の領域かを記録
void dfs(vector<string> G, vector< vector<int> > &visited, int nowx, int nowy, int loop){
    visited[nowy][nowx] = loop;
    //cout<<nowx<<" "<<nowy<<" "<<loop<<endl;
    //ループなしで行けるところ
    for(int i=0;i<4;i++){
        int nextx = nowx+dx[i];
        int nexty = nowy+dy[i];
        if(nextx>=0 && nextx<w && nexty>=0 && nexty<h && G[nexty][nextx]!='#' && visited[nexty][nextx]==INT_MAX){
            dfs(G, visited,nextx,nexty,visited[nowy][nowx]);
        }
    }
    //ループで行けるところ
    for(int y=-2;y<=2;y++){
        for(int x=-2;x<=2;x++){
            if((x==0 && y==0) || (x==0 && y==1) || (x==0 && y==-1) || (x==1 && y==0) || (x==-1 && y==0)) continue;
            int nextx = nowx+x;
            int nexty = nowy+y;
            if(nextx>=0 && nextx<w && nexty>=0 && nexty<h && G[nexty][nextx]!='#' && visited[nexty][nextx]>loop+1){
                dfs(G,visited,nextx,nexty, loop+1);
            }
        }
    }
    return;
}

int main(){
    cin>>h>>w;
    cin>>ch>>cw;
    ch--; cw--;
    cin>>dh>>dw;
    dh--; dw--;
    vector<string> G;
    //最小で何回のループでこれるか、来れないならINF
    vector< vector<int> > visited(h, vector<int>(w,INT_MAX));
    for(int i=0;i<h;i++){
        string s;
        cin>>s;
        G.push_back(s);
    }
    dfs(G,visited,cw,ch,0);
    if(visited[dh][dw]==INT_MAX) cout<<-1<<endl;
    else cout<<visited[dh][dw]<<endl;
    return 0;

}


#include<bits/stdc++.h>
using namespace std;

int h,w;
int ch,cw;
int dh,dw;
int dx[4] = {1,-1,0,0};
int dy[4] = {0,0,1,-1};

//スタートから見て何番目の領域かを記録
void dfs(vector<string> G, vector< vector<int> > &visited, int nowx, int nowy, int loop){
    visited[nowy][nowx] = loop;
    cout<<nowx<<" "<<nowy<<" "<<loop<<endl;
    if(nowy==dh && nowx==dw) return;
    //ループなしで行けるところ
    for(int i=0;i<4;i++){
        int nextx = nowx+dx[i];
        int nexty = nowy+dy[i];
        if(nextx>=0 && nextx<w && nexty>=0 && nexty<h && G[nexty][nextx]!='#' && visited[nexty][nextx]==INT_MAX){
            dfs(G, visited,nextx,nexty,visited[nowy][nowx]);
        }
    }
    //ループで行けるところ
    for(int y=-2;y<=2;y++){
        for(int x=-2;x<=2;x++){
            if((x==0 && y==0) || (x==0 && y==1) || (x==0 && y==-1) || (x==1 && y==0) || (x==-1 && y==0)) continue;
            int nextx = nowx+x;
            int nexty = nowy+y;
            if(nextx>=0 && nextx<w && nexty>=0 && nexty<h && G[nexty][nextx]!='#' && visited[nexty][nextx]==INT_MAX){
                dfs(G,visited,nextx,nexty, min(loop+1,visited[nexty][nextx]));
            }
        }
    }
    return;
}

int main(){
    cin>>h>>w;
    cin>>ch>>cw;
    ch--; cw--;
    cin>>dh>>dw;
    dh--; dw--;
    vector<string> G;
    //最小で何回のループでこれるか、来れないならINF
    vector< vector<int> > visited(h, vector<int>(w,INT_MAX));
    for(int i=0;i<h;i++){
        string s;
        cin>>s;
        G.push_back(s);
    }
    dfs(G,visited,cw,ch,0);
    if(visited[dh][dw]==INT_MAX) cout<<-1<<endl;
    else cout<<visited[dh][dw]<<endl;
    return 0;

}


/* lib.cpp */

#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <queue>
#include <algorithm>
#include <iostream>
#include <iomanip>

#define overload4(_1,_2,_3,_4,name,...) name
#define overload3(_1,_2,_3,name,...) name
#define rep1(n) for(ll i=0;i<n;++i)
#define rep2(i,n) for(ll i=0;i<n;++i)
#define rep3(i,a,b) for(ll i=a;i<b;++i)
#define rep4(i,a,b,c) for(ll i=a;i<b;i+=c)
#define rep(...) overload4(__VA_ARGS__,rep4,rep3,rep2,rep1)(__VA_ARGS__)
#define rrep1(n) for(ll i=(n)-1;i>=0;i--)
#define rrep2(i,n) for(ll i=(n)-1;i>=0;i--)
#define rrep3(i,a,b) for(ll i=(b)-1;i>=(a);i--)
#define rrep4(i,a,b,c) for(ll i=a+(b-a-1)/c*c;i>=a;i-=c)
#define rrep(...) overload4(__VA_ARGS__,rrep4,rrep3,rrep2,rrep1)(__VA_ARGS__)
#define each(i,...) for(auto&& i:__VA_ARGS__)
#define all1(i) begin(i),end(i)
#define all2(i,a) begin(i),begin(i)+a
#define all3(i,a,b) begin(i)+a,begin(i)+b
#define all(...) overload3(__VA_ARGS__,all3,all2,all1)(__VA_ARGS__)
#define rall1(i) (i).rbegin(),(i).rend()
#define rall2(i,k) (i).rbegin(),(i).rbegin()+k
#define rall3(i,a,b) (i).rbegin()+a,(i).rbegin()+b
#define rall(...) overload3(__VA_ARGS__,rall3,rall2,rall1)(__VA_ARGS__)
#define sum(...) accumulate(all(__VA_ARGS__),0LL)
#define dsum(...) accumulate(all(__VA_ARGS__),0.0L)
#define elif else if
#define unless(a) if(!(a))
#define mp make_pair
#define mt make_tuple
#define INT(...) int __VA_ARGS__;in(__VA_ARGS__)
#define LL(...) ll __VA_ARGS__;in(__VA_ARGS__)
#define ULL(...) ull __VA_ARGS__;in(__VA_ARGS__)
#define STR(...) string __VA_ARGS__;in(__VA_ARGS__)
#define CHR(...) char __VA_ARGS__;in(__VA_ARGS__)
#define DBL(...) double __VA_ARGS__;in(__VA_ARGS__)
#define LD(...) ld __VA_ARGS__;in(__VA_ARGS__)
#define Sort(a) sort(all(a))
#define Rev(a) reverse(all(a))
#define Uniq(a) sort(all(a));a.erase(unique(all(a)),end(a))
#define vec(type,name,...) vector<type> name(__VA_ARGS__)
#define VEC(type,name,size) vector<type> name(size);in(name)
#define vv(type,name,h,...) vector<vector<type>>name(h,vector<type>(__VA_ARGS__))
#define VV(type,name,h,w) vector<vector<type>>name(h,vector<type>(w));in(name)
#define vvv(type,name,h,w,...) vector<vector<vector<type>>>name(h,vector<vector<type>>(w,vector<type>(__VA_ARGS__)))

using namespace std;
using ll = long long;
using ull = unsigned ll;
using ld = long double;
using pll = pair<ll, ll>;
using graph = vector<vector<int>>;

const ll LINF = 0x1fffffffffffffff;
const ll MINF = 0x1fffffffffff;
const ll INF = 0x3fffffff;
const ll MOD = 1e9 + 7;
const ll MODD = 998244353;
const ld EPS = 1e-9;
const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};
const int edx[8] = {1, 1, 0, -1, -1, -1, 0, 1};
const int edy[8] = {0, 1, 1, 1, 0, -1, -1, -1};

template<class T> inline T min(const vector<T> &v){ return *min_element(all(v)); }
inline char min(const string &v){ return *min_element(all(v)); }
template<class T> inline T max(const vector<T> &v){ return *max_element(all(v)); }
inline char max(const string &v){ return *max_element(all(v)); }
template <class T> inline void chmin(T &a, T b) { a = min(a, b); }
template <class T> inline void chmax(T &a, T b) { a = max(a, b); }

inline int scan(){ return getchar(); }
inline void scan(int &a){ scanf("%d", &a); }
inline void scan(unsigned &a){ scanf("%u", &a); }
inline void scan(long &a){ scanf("%ld", &a); }
inline void scan(long long &a){ scanf("%lld", &a); }
inline void scan(unsigned long long &a){ scanf("%llu", &a); }
inline void scan(char &a){ cin >> a; }
inline void scan(float &a){ scanf("%f", &a); }
inline void scan(double &a){ scanf("%lf", &a); }
inline void scan(long double &a){ scanf("%Lf", &a); }
inline void scan(vector<bool> &vec){ for(unsigned i = 0; i < vec.size(); i++) { int a; scan(a); vec[i] = a; } }
inline void scan(char a[]){ scanf("%s", a); }
inline void scan(string &a){ cin >> a; }
template<class T> inline void scan(vector<T> &vec);
template<class T, size_t size> inline void scan(array<T, size> &vec);
template<class T, class L> inline void scan(pair<T, L> &p);
template<class T, size_t size> inline void scan(T (&vec)[size]);
template<class T> inline void scan(vector<T> &vec){ for(auto &i : vec) scan(i); }
template<class T> inline void scan(deque<T> &vec){ for(auto &i : vec) scan(i); }
template<class T, size_t size> inline void scan(array<T, size> &vec){ for(auto &i : vec) scan(i); }
template<class T, class L> inline void scan(pair<T, L> &p){ scan(p.first); scan(p.second); }
template<class T, size_t size> inline void scan(T (&vec)[size]){ for(auto &i : vec) scan(i); }
template<class T> inline void scan(T &a){ cin >> a; }
inline void in(){}
template <class Head, class... Tail> inline void in(Head &head, Tail&... tail){ scan(head); in(tail...); }
inline void print(){ putchar(' '); }
inline void print(const bool &a){ printf("%d", a); }
inline void print(const int &a){ printf("%d", a); }
inline void print(const unsigned &a){ printf("%u", a); }
inline void print(const long &a){ printf("%ld", a); }
inline void print(const long long &a){ printf("%lld", a); }
inline void print(const unsigned long long &a){ printf("%llu", a); }
inline void print(const char &a){ printf("%c", a); }
inline void print(const char a[]){ printf("%s", a); }
inline void print(const float &a){ printf("%.15f", a); }
inline void print(const double &a){ printf("%.15f", a); }
inline void print(const long double &a){ printf("%.15Lf", a); }
inline void print(const string &a){ for(auto&& i : a) print(i); }
template<class T> inline void print(const vector<T> &vec);
template<class T, size_t size> inline void print(const array<T, size> &vec);
template<class T, class L> inline void print(const pair<T, L> &p);
template<class T, size_t size> inline void print(const T (&vec)[size]);
template<class T> inline void print(const vector<T> &vec){ if(vec.empty()) return; print(vec[0]); for(auto i = vec.begin(); ++i != vec.end(); ){ putchar(' '); print(*i); } }
template<class T> inline void print(const deque<T> &vec){ if(vec.empty()) return; print(vec[0]); for(auto i = vec.begin(); ++i != vec.end(); ){ putchar(' '); print(*i); } }
template<class T, size_t size> inline void print(const array<T, size> &vec){ print(vec[0]); for(auto i = vec.begin(); ++i != vec.end(); ){ putchar(' '); print(*i); } }
template<class T, class L> inline void print(const pair<T, L> &p){ print(p.first); putchar(' '); print(p.second); }
template<class T, size_t size> inline void print(const T (&vec)[size]){ print(vec[0]); for(auto i = vec; ++i != end(vec); ){ putchar(' '); print(*i); } }
template<class T> inline void print(const T &a){ cout << a; }
inline int out(){ putchar('\n'); return 0; }
template<class T> inline int out(const T &t){ print(t); putchar('\n'); return 0; }
template<class Head, class... Tail> inline int out(const Head &head, const Tail&... tail){ print(head); putchar(' '); out(tail...); return 0; }

inline int first(bool i = true){ return out(i?"first":"second"); }
inline int yes(bool i = true){ return out(i?"yes":"no"); }
inline int Yes(bool i = true){ return out(i?"Yes":"No"); }
inline int No(){ return out("No"); }
inline int YES(bool i = true){ return out(i?"YES":"NO"); }
inline int NO(){ return out("NO"); }
inline int Yay(bool i = true){ return out(i?"Yay!":":("); }
inline int possible(bool i = true){ return out(i?"possible":"impossible"); }
inline int Possible(bool i = true){ return out(i?"Possible":"Impossible"); }
inline int POSSIBLE(bool i = true){ return out(i?"POSSIBLE":"IMPOSSIBLE"); }
inline void Case(ll i){ printf("Case #%lld: ", i); }

ll modpow(ll a, ll b, ll p = MOD) { ll ret = 1; while (b != 0) { if ((b & 1) == 1) ret *= a; a *= a; if (a >= p) a %= p; if (ret >= p) ret %= p; b >>= 1; } return ret; }
int digit(ll x, ll base = 10) { int ret = 0; while (x) { x /= base; ret++; } return ret; }
int sumOfDigit(ll x, ll base = 10) { int ret = 0; while(x) { ret += x % base; x /= base; } return ret; }
ll factrial(int n) { ll ret = 1; for(int i = 1;i <= n;i++) { ret *= i; } return ret; }
ll gcd(ll a, ll b) { while(b != 0) { a %= b; swap(a, b); } return abs(a); }
ll lcm(ll a, ll b) { return a / gcd(a, b) * b; }
ll modinv(ll a, ll p = MOD) { ll b = p, u = 1, v = 0; while(b) { ll tmp = a / b; a -= tmp * b; u -= tmp * v; swap(a, b); swap(u, v); } u %= p; if (u < 0) u += p; return u; }
bool isprime(ull x) { if(x <= 1) return false; for(int i = 2;i * i <= x;i++) if(x % i == 0) return false; return true; }
map<ll, ll> factor(ull x){ map<ll, ll> ret; for(ll i = 2; i * i <= x; i++) while(x % i == 0){ ret[i]++; x /= i; } if(x != 1) ret[x]++; return ret; }
set<ll> divisor(ull x){ set<ll> ret; for(ll i = 1; i * i <= x; i++) if(x % i == 0){ ret.insert(i); ret.insert(x / i); } return ret; }
ll minDivisor(ull x, ll n = 2) { if(x <= 1) return 1; for(int i = n;i * i <= x;i++) if(x % i == 0) return i; return x; }
ll countDivisor(ull x) { map<ll, ll> m = factor(x); ll ret = 1; for(auto i : m) { ret *= i.second + 1; } return ret; }

class disjoint_set
{
    vector<int> _parent, _size;

public:
    disjoint_set(int n) : _parent(n), _size(n) {
        for (int i = 0; i < n; i++) {
            _parent[i] = i;
            _size[i] = 1;
        }
    }
    int root(int x) {
        if (_parent[x] == x) return x;
        return _parent[x] = root(_parent[x]);
    }
    void unite(int x, int y) {
        int rx = root(x);
        int ry = root(y);
        if (rx == ry) return;
        _parent[rx] = ry;
        _size[ry] += _size[rx];
    }
    bool same(int x, int y) { return root(x) == root(y); }
    int size(int x) { return _size[root(x)]; }
};

void init() { cin.tie(nullptr); cout << fixed << setprecision(15); }

vector<ll> dijkstra(const graph& g, ll n, ll v) {
    priority_queue<pll, vector<pll>, greater<pll>> q;
    vector<bool> seen(n);
    vector<ll> d(n);
    vector<ll> prev(n);

    rep(i, n) {
        seen[i] = false;
        d[i] = INF;
        prev[i] = -1;
    }
    d[v] = 0;
    q.push(mp(0, 0));

    while(!q.empty()) {
        ll v = q.top().second;
        seen[v] = true;
        q.pop();
        for(auto i : g[v]) {
            if(seen[i]) continue;
            if(d[i] > d[v] + 1) {
                d[i] = d[v] + 1;
                prev[i] = v;
                q.push(mp(d[i], i));
            }
        }
    }
    return prev;
}

/*
ll binary_search() {
    ll left = 0, right = INF;
    while(abs(right - left) > 1) {
        ll mid = left + (right - left) / 2;
        if(f(mid)) left = mid;
        else right = mid;
    }
}
*/

int solve() {
    LL(h, w);
    LL(ch, cw);
    LL(dh, dw);
    ch--;cw--;dh--;dw--;
    vector<string> s(h);
    rep(i, h) {
        cin >> s[i];
    }
    vector<ll> wx, wy;
    rep(i, -2, 2 + 1) {
        rep(j, -2, 2 + 1) {
            if(i == 2 || j == 2) {
                wx.push_back(i);
                wy.push_back(j);
            }
        }
    }
    priority_queue<pair<ll, pll>, vector<pair<ll, pll>>, greater<pair<ll, pll>>> q;
    ll seen[h][w], d[h][w];

    rep(i, h) {
        rep(j, w) {
            seen[i][j] = 0;
            d[i][j] = INF;
        }
    }
    d[ch][cw] = 0;
    q.push(mp(0, pll(ch, cw)));

    while(!q.empty()) {
        pll v = q.top().second;
        ll x = v.first, y = v.second;
        seen[x][y] = 1;
        q.pop();
        rep(i, 4) {
            ll nx = x + dx[i], ny = y + dy[i];
            if(nx < 0 || h <= nx || ny < 0 || w <= ny) continue;
            if(s[nx][ny] == '#') continue;
            if(seen[nx][ny]) continue;
            if(d[nx][ny] > d[x][y]) {
                d[nx][ny] = d[x][y];
                q.push(mp(d[nx][ny], pll(nx, ny)));
            }
        }
        rep(i, 16) {
            ll nx = x + wx[i], ny = y + wy[i];
            if(nx < 0 || h <= nx || ny < 0 || w <= ny) continue;
            if(s[nx][ny] == '#') continue;
            if(seen[nx][ny]) continue;
            if(d[nx][ny] > d[x][y] + 1) {
                d[nx][ny] = d[x][y] + 1;
                q.push(mp(d[nx][ny], pll(nx, ny)));
            }
        }
    }
    if(d[dh][dw] == INF) out(-1);
    else out(d[dh][dw]);
    return 0;
}

int main() { init(); solve(); return 0; }


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define rep(i,N) for(int i=0;i<(int)N;i++)
#pragma GCC optimize("O3")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
static inline void PUT(char c)
{
  static char buf[1<<15],*ptr=buf;
  if(ptr==buf+strlen(buf)||c==0){fwrite(buf,1,ptr-buf,stdout),ptr=buf;}*ptr++=c;
}
static inline int IN(void)
{
  int x=0,f=0,c=getchar();while(c<48||c>57){f^=c==45,c=getchar();}
  while(c>47&&c<58){x=x*10+c-48,c=getchar();}return f?-x:x;
}
static inline void OUT(int a)
{
  if(a<0)PUT('-'),a=-a;
  int d[40],i=0;do{d[i++]=a%10;}while(a/=10);
  while(i--){PUT(d[i]+48);}PUT('\n');
}
const int qsz=1e6;int qLen,qHead,Q[1000000];
static inline void PUSH(int n){Q[(qHead+qLen)%qsz]=n;qLen++;}
static inline int POP(void){int q=Q[qHead];qLen--;qHead=(qHead+1)%qsz;return q;}
int H,W,grid[1000][1000];
const int dx[24]={0,1,0,-1,0,0,1,1,1,1,-1,-1,-1,-1,2,2,2,2,2,-2,-2,-2,-2,-2};
const int dy[24]={1,0,-1,0,2,-2,1,2,-1,-2,1,2,-1,-2,0,1,2,-1,-2,0,1,2,-1,-2};
static inline int f(int x,int y){return W*x+y;}
static inline void DFS(int x,int y)
{
  if(x>=0&&x<H&&y>=0&&y<W&&!grid[x][y])
  {
    grid[x][y]=1;PUSH(f(x,y));rep(i,4){DFS(x+dx[i],y+dy[i]);}
  }
}
int main(void)
{
  int C[2],D[2],step=0;H=IN(),W=IN(),C[0]=IN()-1,C[1]=IN()-1,D[0]=IN()-1,D[1]=IN()-1;
  rep(i,H){char str[1001];if(!scanf("%s",str)){return -1;}rep(j,W){grid[i][j]=(str[j]=='#');}}
  PUSH(f(C[0],C[1]));
  while(qLen)
  {
    int size=qLen;
    while(size--){int x=POP();DFS(x/W,x%W);}
    size=qLen;
    while(size--)
    {
      int z=POP(),x=z/W,y=z%W;
      if(x==D[0]&&y==D[1]){return OUT(step),0;}
      rep(i,20)
      {
        int nx=x+dx[4+i],ny=y+dy[4+i];
        if(nx>=0&&nx<H&&ny>=0&&ny<W&&!grid[nx][ny]){PUSH(f(nx,ny));}
      }
    }
    step++;
  }
  return puts("-1"),0;
}


#include <ctype.h>
#include <float.h>
#include <inttypes.h>
#include <limits.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <math.h>
#ifdef __cplusplus
#include <bits/stdc++.h>
#endif
#pragma GCC target("avx2")
#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")

#define getchar getchar_unlocked
#define putchar putchar_unlocked
int32_t nextint(void){ char c=getchar(); while(c!='-'&&(c<'0'||'9'<c)) c=getchar(); bool s=false; if(c=='-'){s=true;c=getchar();} uint32_t x=0; while('0'<=c && c<='9'){ x=x*10+c-'0'; c=getchar(); } return s?-x:x; }
int64_t nextlong(void){ char c=getchar(); while(c!='-'&&(c<'0'||'9'<c)) c=getchar(); int s=0; if(c=='-'){s=1;c=getchar();} uint64_t x=0; while('0'<=c && c<='9'){ x=x*10+c-'0'; c=getchar(); } return s?-x:x; }
uint32_t nextstr(char *s){ char c=getchar(); while(c==' '||c=='\n') c=getchar(); uint32_t len=0; while(c!=' '&&c!='\n'){ *s++=c; len++; c=getchar(); } *s='\0'; return len; }
void rsorta_d32(void *base, const int count, const int size, const int index){
	typedef int32_t rsort_t;
	rsort_t (*a)[size] = (rsort_t(*)[size])base;
	rsort_t (*b)[size] = (rsort_t(*)[size])malloc(count*size*sizeof(rsort_t));
	int c[0x100];
	for(int k=0; k<4; k++){
		memset(c, 0, sizeof(c)); for(int i=0; i<count; i++){ c[(a[i][index]>>(k<<3))&0xFF]++; } for(int i=1; i<0x100; i++) c[i]+=c[i-1]; for(int i=count-1; i>=0; i--){ int to=--c[(a[i][index]>>(k<<3))&0xFF]; for(int j=0; j<size; j++){ b[to][j]=a[i][j]; } }{rsort_t(*t)[size]=a; a=b; b=t;}
	}
	free(b);
}

char m[1000][1001];
int d[1000][1000];
int s[1000000][2];
int main(void){
	int h=nextint();
	int w=nextint();
	int ch=nextint()-1;
	int cw=nextint()-1;
	int dh=nextint()-1;
	int dw=nextint()-1;
	for(int i=0; i<h; i++){
		nextstr(m[i]);
	}
	int k=0;
	int sl=0, sr=0;
	d[ch][cw]=1;
	s[sl][0]=ch, s[sl][1]=cw, sr++;
	while(1){
		k++;
		if(sl==sr) break;
		int tl=sl;
		while(sl<sr){
			int x=s[sl][0], y=s[sl][1]; sl++;
			{int i=x-1, j=y; if(0<=i&&i<h&&0<=j&&j<w && m[i][j]=='.' && d[i][j]==0){ d[i][j]=k; s[sr][0]=i, s[sr][1]=j, sr++;}}
			{int i=x+1, j=y; if(0<=i&&i<h&&0<=j&&j<w && m[i][j]=='.' && d[i][j]==0){ d[i][j]=k; s[sr][0]=i, s[sr][1]=j, sr++;}}
			{int i=x, j=y-1; if(0<=i&&i<h&&0<=j&&j<w && m[i][j]=='.' && d[i][j]==0){ d[i][j]=k; s[sr][0]=i, s[sr][1]=j, sr++;}}
			{int i=x, j=y+1; if(0<=i&&i<h&&0<=j&&j<w && m[i][j]=='.' && d[i][j]==0){ d[i][j]=k; s[sr][0]=i, s[sr][1]=j, sr++;}}
		}
		if(d[dh][dw]!=0){
			printf("%d\n", k-1);
			return 0;
		}
		int tr=sr;
		while(tl<tr){
			int x=s[tl][0], y=s[tl][1]; tl++;
			if(d[x][y]==k){
				for(int i=x-2; i<=x+2; i++){
					for(int j=y-2; j<=y+2; j++){
						if(0<=i&&i<h&&0<=j&&j<w && m[i][j]=='.' && d[i][j]==0){
							d[i][j]=k+1;
							s[sr][0]=i, s[sr][1]=j, sr++;
						}
					}
				}
			}
		}
	}
	printf("%d\n", -1);
}


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
typedef long long ll;
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define REP(i,l,r) for(ll i=l;i<(ll)(r);i++) //ll
#define max(l,r) ((l)>(r)?l:r)
#define min(l,r) ((l)<(r)?l:r)
#define swap(l,r) {ll tp=l;l=r;r=tp;}
const ll MOD = 1000000007;
const int INF = (1<<30);
int upcmpii(const void *a, const void *b){return(*(int*)a==*(int*)b?0:(*(int*)a>*(int*)b?1:-1));}
void sort_ui(int*a, int n){qsort(a,n,sizeof(int),upcmpii);}

int H,W;
int sx,sy,gx,gy;
char s[1010][1010];
int cnt[1010][1010] = {0};
ll ans = 0;
const int dx[] = {0,0,1,-1}, dy[] = {1,-1,0,0};
int qxf = 0, qxb = 0, quex[101010101];
int qyf = 0, qyb = 0, quey[101010101];

void dfs(int cx,int cy){
    cnt[cx][cy] = ans+1;
    rep(i,4){
        int nx = cx+dx[i];
        int ny = cy+dy[i];
        if(nx >= 0 && nx < H && ny >= 0 && ny < W){
            if(cnt[nx][ny] <= 0 && s[nx][ny] == '.'){
                dfs(nx,ny);
            }
        }
    }
    rep(i,5) rep(j,5) {
        int nx = cx-2+i;
        int ny = cy-2+j;
        if(nx >= 0 && nx < H && ny >= 0 && ny < W){
            if(cnt[nx][ny] == 0 && s[nx][ny] == '.'){
                cnt[nx][ny] = -1;
                quex[qxb++] = nx;
                quey[qyb++] = ny;
            }
        }
    }
}

void solve(){
    dfs(sx,sy);
    while(cnt[gx][gy] <= 0){
        ans++;
        int m = qxb-qxf;
        int tmp = 0;
        rep(i,m){
            int nnx = quex[qxf++],nny = quey[qyf++];
            if(cnt[nnx][nny] == -1) { dfs(nnx,nny); tmp++; }
        }
        if(tmp == 0 && cnt[gx][gy] == 0){
            ans = -1;
            break;
        }
    }
}

int main(){
    scanf("%d%d", &H,&W);
    scanf("%d%d%d%d", &sx,&sy,&gx,&gy);
    sx--;sy--;gx--;gy--;
    rep(i, H) scanf("%s", s[i]);

    solve();

    printf("%lld", ans);
}


#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
int acs(const void *a, const void *b) {
  return *(int*)a - *(int*)b;
} /* 1,2,3,4.. */
int des(const void *a, const void *b) {
  return *(int*)b - *(int*)a;
} /* 8,7,6,5.. */
int cmp_char(const void *a, const void *b) {
  return *(char*)a - *(char*)b;
} /* a,b,c,d.. */
int cmp_str(const void *a, const void *b) {
  return strcmp(*(const char **)a, *(const char **)b);
} /* aaa,aab.. */
#define min(a,b) (a < b ? a : b)
#define max(a,b) (a > b ? a : b)
#define rep(i, l, r) for (int i = l; i < r; i++)
#define MAX 1005
#define MOD 1000000007
#define INF 1000000009
typedef long long int lli;

typedef struct {
  int front;
  int rear;
  int data[20000000][2];
} queue;

queue que;

void initQueue(queue *p) {
  p->front = p->rear = 0;
}

bool emptyQueue(queue *p) {
  return p->front == p->rear;
}

bool fullQueue(queue *p) {
  return (p->front - 1 == p->rear) || (p->front == 0 && p->rear == 20000000 - 1);
}

void queuePop(queue *p) {
  if ( emptyQueue(p) ) {
    printf("UnderFlow\n");
    exit(1);
  } else {
    p->front++;
    if (p->front == 20000000)
      p->front = 0;
  }
}

void queuePush(queue *p, int y, int x) {
  if ( fullQueue(p) ) {
    printf("OverFlow\n");
    exit(1);
  } else {
    p->data[p->rear][0] = y;
    p->data[p->rear][1] = x;
    p->rear++;
    if ( p->rear == 20000000 )
      p->rear = 0;
  }
}

int H, W, Ch, Cw, Dh, Dw;

char S[MAX][MAX];

int main(void) {
  scanf("%d %d", &H, &W);
  scanf("%d %d", &Ch, &Cw);
  scanf("%d %d", &Dh, &Dw);

  rep(i, 0, H) scanf("%s", S[i]);

  int dist[MAX][MAX];
  rep(i, 0, MAX) rep(j, 0, MAX) dist[i][j] = INF;

  int ax[4] = {0, 1, 0, -1};
  int ay[4] = {1, 0, -1, 0};

  initQueue(&que);
  queuePush(&que, Ch-1, Cw-1);
  dist[Ch-1][Cw-1] = 0;
  while ( !emptyQueue(&que) ) {
    int y = que.data[que.front][0];
    int x = que.data[que.front][1];
    queuePop(&que);
    if ( y == Dh-1 && x == Dw-1 ) {
      printf("%d\n", dist[y][x]);
      return 0;
    }
    rep(i, 0, 4) {
      int ny = y + ay[i];
      int nx = x + ax[i];
      if ( ny < 0 || H <= ny ) continue;
      if ( nx < 0 || W <= nx ) continue;
      if ( S[ny][nx] == '#' ) continue;
      if ( dist[ny][nx] <= dist[y][x] ) continue;
      dist[ny][nx] = dist[y][x];
      queuePush(&que, ny, nx);
    }

    rep(by, -2, 3) rep(bx, -2, 3) {
      int ny = y + by;
      int nx = x + bx;
      if ( ny < 0 || H <= ny ) continue;
      if ( nx < 0 || W <= nx ) continue;
      if ( S[ny][nx] == '#' ) continue;
      if ( dist[ny][nx] <= dist[y][x] + 1 ) continue;
      dist[ny][nx] = dist[y][x] + 1;
      queuePush(&que, ny, nx);
    }
  }
  printf("-1\n");
  return 0;
}


#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
int acs(const void *a, const void *b) {
  return *(int*)a - *(int*)b;
} /* 1,2,3,4.. */
int des(const void *a, const void *b) {
  return *(int*)b - *(int*)a;
} /* 8,7,6,5.. */
int cmp_char(const void *a, const void *b) {
  return *(char*)a - *(char*)b;
} /* a,b,c,d.. */
int cmp_str(const void *a, const void *b) {
  return strcmp(*(const char **)a, *(const char **)b);
} /* aaa,aab.. */
#define min(a,b) (a < b ? a : b)
#define max(a,b) (a > b ? a : b)
#define rep(i, l, r) for (int i = l; i < r; i++)
#define MAX 1005
#define MOD 1000000007
#define INF 1000000009
typedef long long int lli;

typedef struct {
  int front;
  int rear;
  int data[20000000][2];
} queue;

queue que;

void initQueue(queue *p) {
  p->front = p->rear = 0;
}

bool emptyQueue(queue *p) {
  return p->front == p->rear;
}

bool fullQueue(queue *p) {
  return (p->front - 1 == p->rear) || (p->front == 0 && p->rear == MAX - 1);
}

void queuePop(queue *p) {
  if ( emptyQueue(p) ) {
    printf("UnderFlow\n");
    exit(1);
  } else {
    p->front++;
    if (p->front == MAX)
      p->front = 0;
  }
}

void queuePush(queue *p, int y, int x) {
  if ( fullQueue(p) ) {
    printf("OverFlow\n");
    exit(1);
  } else {
    p->data[p->rear][0] = y;
    p->data[p->rear][1] = x;
    p->rear++;
    if ( p->rear == MAX )
      p->rear = 0;
  }
}

int H, W, Ch, Cw, Dh, Dw;

char S[MAX][MAX];

int main(void) {
  scanf("%d %d", &H, &W);
  scanf("%d %d", &Ch, &Cw);
  scanf("%d %d", &Dh, &Dw);

  rep(i, 0, H) scanf("%s", S[i]);

  int dist[MAX][MAX];
  rep(i, 0, MAX) rep(j, 0, MAX) dist[i][j] = INF;

  int ax[4] = {0, 1, 0, -1};
  int ay[4] = {1, 0, -1, 0};

  initQueue(&que);
  queuePush(&que, Ch-1, Cw-1);
  dist[Ch-1][Cw-1] = 0;
  while ( !emptyQueue(&que) ) {
    int y = que.data[que.front][0];
    int x = que.data[que.front][1];
    queuePop(&que);
    if ( y == Dh-1 && x == Dw-1 ) {
      printf("%d\n", dist[y][x]);
      return 0;
    }
    rep(i, 0, 4) {
      int ny = y + ay[i];
      int nx = x + ax[i];
      if ( ny < 0 || H <= ny ) continue;
      if ( nx < 0 || W <= nx ) continue;
      if ( S[ny][nx] == '#' ) continue;
      if ( dist[ny][nx] <= dist[y][x] ) continue;
      dist[ny][nx] = dist[y][x];
      queuePush(&que, ny, nx);
    }

    rep(by, -2, 3) rep(bx, -2, 3) {
      int ny = y + by;
      int nx = x + bx;
      if ( ny < 0 || H <= ny ) continue;
      if ( nx < 0 || W <= nx ) continue;
      if ( S[ny][nx] == '#' ) continue;
      if ( dist[ny][nx] <= dist[y][x] + 1 ) continue;
      dist[ny][nx] = dist[y][x] + 1;
      queuePush(&que, ny, nx);
    }
  }
  printf("-1\n");
  return 0;
}


#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
int acs(const void *a, const void *b) {
  return *(int*)a - *(int*)b;
} /* 1,2,3,4.. */
int des(const void *a, const void *b) {
  return *(int*)b - *(int*)a;
} /* 8,7,6,5.. */
int cmp_char(const void *a, const void *b) {
  return *(char*)a - *(char*)b;
} /* a,b,c,d.. */
int cmp_str(const void *a, const void *b) {
  return strcmp(*(const char **)a, *(const char **)b);
} /* aaa,aab.. */
#define min(a,b) (a < b ? a : b)
#define max(a,b) (a > b ? a : b)
#define rep(i, l, r) for (int i = l; i < r; i++)
#define MAX 1005
#define MOD 1000000007
#define INF 1000000009
typedef long long int lli;

typedef struct {
  int front;
  int rear;
  int data[16777216][2];
} queue;

queue que;

void initQueue(queue *p) {
  p->front = p->rear = 0;
}

bool emptyQueue(queue *p) {
  return p->front == p->rear;
}

bool fullQueue(queue *p) {
  return (p->front - 1 == p->rear) || (p->front == 0 && p->rear == MAX - 1);
}

void queuePop(queue *p) {
  if ( emptyQueue(p) ) {
    printf("UnderFlow\n");
    exit(1);
  } else {
    p->front++;
    if (p->front == MAX)
      p->front = 0;
  }
}

void queuePush(queue *p, int y, int x) {
  if ( fullQueue(p) ) {
    printf("OverFlow\n");
    exit(1);
  } else {
    p->data[p->rear][0] = y;
    p->data[p->rear][1] = x;
    p->rear++;
    if ( p->rear == MAX )
      p->rear = 0;
  }
}

int H, W, Ch, Cw, Dh, Dw;

char S[MAX][MAX];

int main(void) {
  scanf("%d %d", &H, &W);
  scanf("%d %d", &Ch, &Cw);
  scanf("%d %d", &Dh, &Dw);

  rep(i, 0, H) scanf("%s", S[i]);

  int dist[MAX][MAX];
  rep(i, 0, MAX) rep(j, 0, MAX) dist[i][j] = INF;

  int ax[4] = {0, 1, 0, -1};
  int ay[4] = {1, 0, -1, 0};

  initQueue(&que);
  queuePush(&que, Ch-1, Cw-1);
  dist[Ch-1][Cw-1] = 0;
  while ( !emptyQueue(&que) ) {
    int y = que.data[que.front][0];
    int x = que.data[que.front][1];
    queuePop(&que);
    if ( y == Dh-1 && x == Dw-1 ) {
      printf("%d\n", dist[y][x]);
      return 0;
    }
    rep(i, 0, 4) {
      int ny = y + ay[i];
      int nx = x + ax[i];
      if ( ny < 0 || H <= ny ) continue;
      if ( nx < 0 || W <= nx ) continue;
      if ( S[ny][nx] == '#' ) continue;
      if ( dist[ny][nx] <= dist[y][x] ) continue;
      dist[ny][nx] = dist[y][x];
      queuePush(&que, ny, nx);
    }

    rep(by, -2, 3) rep(bx, -2, 3) {
      int ny = y + by;
      int nx = x + bx;
      if ( ny < 0 || H <= ny ) continue;
      if ( nx < 0 || W <= nx ) continue;
      if ( S[ny][nx] == '#' ) continue;
      if ( dist[ny][nx] <= dist[y][x] + 1 ) continue;
      dist[ny][nx] = dist[y][x] + 1;
      queuePush(&que, ny, nx);
    }
  }
  printf("-1\n");
  return 0;
}


const { listenerCount } = require("process");

function main(input = "") {
    const WALL = -1, ROAD = 99999999;
    const lines = input.split("\n");
    const header = lines.slice(0, 3).map((line) => (line.split(" ").map((v) => (Number(v)))));
    const H = header[0][0], W = header[0][1];
    const Ch = header[1][0] - 1, Cw = header[1][1] - 1;
    const Dh = header[2][0] - 1, Dw = header[2][1] - 1;
    const Dest = Dh * W + Dw;
    const GRID = lines.slice(3).map((line) => (line.split("").map((v) => (v === "#" ? WALL : ROAD))))
    const MAZE = new Int32Array(Array().concat(...GRID));

    let fill = (h = 0, w = 0, v = 0, arr = []) => {
        let id = h * W + w;
        if (MAZE[id] > v) {
            MAZE[id] = v;
            arr.push(id)
            if (0 <= h - 1) fill(h - 1, w, v, arr);
            if (h + 1 < H) fill(h + 1, w, v, arr);
            if (0 <= w - 1) fill(h, w - 1, v, arr);
            if (w + 1 < W) fill(h, w + 1, v, arr);
        }
    }

    let getWarpList = (area = [0]) => {
        let set = new Set();
        area.forEach((v) => {
            let ih = 0 | v / W;
            let iw = v - ih * W;
            _warpList(ih, iw, set);
        })
        return set;
    }

    let _warpList = (h = 0, w = 0, set = new Set([0])) => {
        let v = MAZE[h * W + w];
        for (let ih = -2; ih <= 2; ih++) {
            let th = h + ih;
            if (0 <= th && th < H) {
                for (let iw = -2; iw <= 2; iw++) {
                    let tw = w + iw;
                    if (0 <= tw && tw < W) {
                        let toId = th * W + tw
                        if (MAZE[toId] > v) {
                            set.add(toId);
                        }
                    }
                }
            }
        }
    }

    let area = [];
    let ch = Ch, cw = Cw;
    let color = 1;
    fill(ch, cw, color, area);
    while (true) {
        color++;
        let lst = getWarpList(area)
        area.length = 0;
        for (const v of lst) {
            let ih = 0 | v / W;
            let iw = v - ih * W;
            fill(ih, iw, color, area);
        }
        if (area.length === 0) {
            break;
        }
    }

    return MAZE[Dest] === ROAD ? -1 : MAZE[Dest] - 1;
}

//******************************
exports.main = main;

function Main(input) {
    console.log(main(input.trim()));
}

if (process.argv[2] !== "test") {
    Main(require("fs").readFileSync("/dev/stdin", "utf8"));
}


(async () => {
    let input = '';
    for await (const chunk of process.stdin) input += chunk;
    const lines = input.split(/\n/);
    const [h, w] = lines[0].split(/\s/).map(v => +v);
    const [ch, cw] = lines[1].split(/\s/).map(v => v - 1);
    const [dh, dw] = lines[2].split(/\s/).map(v => v - 1);
    const counts = lines.slice(3, h + 3).map(line => line.split('').slice(0, w).map(c => c == '#' ? -1 : Infinity));

    let que = {0: [], 1: []};
    counts[ch][cw] = 0;
    que[0].push([ch, cw, 0]);

    const addQue = (queNumber, x, y, count) => {
        if(x < 0)return;
        if(x >= h)return;
        if(y < 0)return;
        if(y >= w)return;
        if(counts[x][y] <= count)return;
        que[queNumber].push([x, y, count]);
        counts[x][y] = count;
    }

    while(que[0].length || que[1].length){
        if(!que[0].length){
            que[0] = que[1];
            que[1] = [];
        }
        const [x, y, count] = que[0].pop();
        if(x == dh && y == dw)break;

        addQue(0, x - 1, y, count);
        addQue(0, x + 1, y, count);
        addQue(0, x, y - 1, count);
        addQue(0, x, y + 1, count);
        for(let i = -2; i <= 2; i++){
            for(let j = -2; j <= 2; j++){
                addQue(1, x + i, y + j, count + 1);
            }
        }
    }

    if(counts[dh][dw] == Infinity){
        console.log(-1);
    }else{
        console.log(counts[dh][dw]);
    }

})();


"use strict";
var input=require("fs").readFileSync("/dev/stdin","utf8");
var cin=input.split(/ |\n/),cid=0;
function next(){return +cin[cid++];}
function nextstr(){return cin[cid++];}
function nextbig(){return BigInt(cin[cid++]);}
function nexts(n,a){return a?cin.slice(cid,cid+=n):cin.slice(cid,cid+=n).map(a=>+a);}
function nextm(h,w,a){var r=[],i=0;if(a)for(;i<h;i++)r.push(cin.slice(cid,cid+=w));else for(;i<h;i++)r.push(cin.slice(cid,cid+=w).map(a=>+a));return r;}
function xArray(v){var a=arguments,l=a.length,r="Array(a["+--l+"]).fill().map(x=>{return "+v+";})";while(--l)r="Array(a["+l+"]).fill().map(x=>"+r+")";return eval(r);}

var myOut = main();
if(myOut !== undefined)console.log(String(myOut));

function main(){
  var dy = [-1,0,1,0], dx = [0,1,0,-1];
  var h = next(), w = next();
  var [sy,sx] = nexts(2);
  var [gy,gx] = nexts(2);
  sy--,sx--,gy--,gx--;
  var s = nexts(h,1);
  var map = xArray(1e9,h,w);
  map[sy][sx] = 0;
  var q1 = [sy,sx], q2 = [], d = 0;
  while(q1.length){
    while(q1.length){
      var qx = q1.pop(), qy = q1.pop();
      if(map[qy][qx] < d)continue;
      for(var i = 0; i < 4; i++){
        var nx = qx+dx[i], ny = qy+dy[i];
        if(nx < 0 || nx === w || ny < 0 || ny === h)continue;
        if(s[ny][nx] === "#")continue;
        if(map[ny][nx] <= d)continue;
        map[ny][nx] = d;
        q1.push(ny,nx);
      }
      for(var y = -2; y <= 2; y++)for(var x = -2; x <= 2; x++){
        var nx = qx+x, ny = qy+y;
        if(nx < 0 || nx >= w || ny < 0 || ny >= h)continue;
        if(s[ny][nx] === "#")continue;
        if(map[ny][nx] <= d+1)continue;
        map[ny][nx] = d+1;
        q2.push(ny,nx);
      }
    }
    d++, q1 = q2, q2 = [];
  }
  return map[gy][gx] === 1e9 ? -1 : map[gy][gx];
}


(async () => {
    let input = '';
    for await (const chunk of process.stdin) input += chunk;
    const lines = input.split(/\n/);
    const [h, w] = lines[0].split(/\s/).map(v => +v);
    const [ch, cw] = lines[1].split(/\s/).map(v => v - 1);
    const [dh, dw] = lines[2].split(/\s/).map(v => v - 1);
    const counts = lines.slice(3, h + 3).map(line => line.split('').slice(0, w).map(c => c == '#' ? -1 : Infinity));

    let que = {0: [], 1: []};
    que[0].push([ch, cw, 0]);

    const addQue = (queNumber, x, y, count) => {
        if(x < 0)return;
        if(x >= h)return;
        if(y < 0)return;
        if(y >= w)return;
        if(counts[x][y] <= count)return;
        que[queNumber].push([x, y, count]);
    }

    while(que[0].length || que[1].length){
        if(!que[0].length){
            que[0] = que[1];
            que[1] = [];
        }
        const [x, y, count] = que[0].pop();

        if(x < 0)continue;
        if(x >= h)continue;
        if(y < 0)continue;
        if(y >= w)continue;
        if(counts[x][y] > count){
            counts[x][y] = count;
            if(x == dh && y == dw)break;
        }else{
            continue;
        }

        addQue(0, x - 1, y, count);
        addQue(0, x + 1, y, count);
        addQue(0, x, y - 1, count);
        addQue(0, x, y + 1, count);
        for(let i = -2; i <= 2; i++){
            for(let j = -2; j <= 2; j++){
                addQue(1, x + i, j + i, count + 1);
            }
        }
    }

    if(counts[dh][dw] == Infinity){
        console.log(-1);
    }else{
        console.log(counts[dh][dw]);
    }

})();


(async () => {
    let input = '';
    for await (const chunk of process.stdin) input += chunk;
    const lines = input.split(/\n/);
    const [h, w] = lines[0].split(/\s/).map(v => +v);
    const [ch, cw] = lines[1].split(/\s/).map(v => v - 1);
    const [dh, dw] = lines[2].split(/\s/).map(v => v - 1);
    const counts = lines.slice(3, h + 3).map(line => line.split('').slice(0, w).map(c => c == '#' ? -1 : Infinity));

    let que = {0: [], 1: []};
    que[0].push([ch, cw, 0]);
    while(que[0].length || que[1].length){
        if(!que[0].length){
            que[0] = que[1];
            que[1] = [];
        }
        const [x, y, count] = que[0].pop();

        if(x < 0)continue;
        if(x >= h)continue;
        if(y < 0)continue;
        if(y >= w)continue;
        if(counts[x][y] > count){
            counts[x][y] = count;
            if(x == dh && y == dw)break;
        }else{
            continue;
        }

        que[0].push([x - 1, y, count]);
        que[0].push([x + 1, y, count]);
        que[0].push([x, y - 1, count]);
        que[0].push([x, y + 1, count]);
        for(let i = -2; i <= 2; i++){
            for(let j = -2; j <= 2; j++){
                if(counts[x + i][y + j] > count + 1){
                    que[1].push([x + i, y + j, count + 1]);
                }
            }
        }
    }

    if(counts[dh][dw] == Infinity){
        console.log(-1);
    }else{
        console.log(counts[dh][dw]);
    }

})();


(async () => {
    let input = '';
    for await (const chunk of process.stdin) input += chunk;
    const lines = input.split(/\n/);
    const [h, w] = lines[0].split(/\s/).map(v => +v);
    const [ch, cw] = lines[1].split(/\s/).map(v => v - 1);
    const [dh, dw] = lines[2].split(/\s/).map(v => v - 1);
    const counts = lines.slice(3, h + 3).map(line => line.split('').slice(0, w).map(c => c == '#' ? -1 : Infinity));

    let que = {0: [], 1: []};
    que[0].push([ch, cw, 0]);
    while(que[0].length || que[1].length){
        if(!que[0].length){
            que[0] = que[1];
            que[1] = [];
        }
        const [x, y, count] = que[0].pop();

        if(x < 0)continue;
        if(x >= h)continue;
        if(y < 0)continue;
        if(y >= w)continue;
        if(counts[x][y] > count){
            counts[x][y] = count;
            if(x == dh && y == dw)break;
        }else{
            continue;
        }

        que[0].push([x - 1, y, count]);
        que[0].push([x + 1, y, count]);
        que[0].push([x, y - 1, count]);
        que[0].push([x, y + 1, count]);
        for(let i = -2; i <= 2; i++){
            for(let j = -2; j <= 2; j++){
                que[1].push([x + i, y + j, count + 1]);
            }
        }
    }

    if(counts[dh][dw] == Infinity){
        console.log(-1);
    }else{
        console.log(counts[dh][dw]);
    }

})();


package main

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"strconv"
)

func min(x, y int) int {
	if x < y {
		return x
	}
	return y
}

func max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

func main() {
	defer flush()

	H := readInt()
	W := readInt()
	Ch := readInt() - 1
	Cw := readInt() - 1
	Dh := readInt() - 1
	Dw := readInt() - 1
	S := make([]string, H)
	for i := 0; i < H; i++ {
		S[i] = readString()
	}

	t := make([][]int, H)
	for i := 0; i < H; i++ {
		t[i] = make([]int, W)
		for j := 0; j < W; j++ {
			if S[i][j] == '#' {
				t[i][j] = -1
			} else {
				t[i][j] = math.MaxInt64
			}
		}
	}

	warpCount := 0
	t[Ch][Cw] = warpCount
	q := make([][2]int, 0, 1024)
	q = append(q, [2]int{Ch, Cw})

	warpq := make([][2]int, 0, 1024)
	for len(q) != 0 {
		for len(q) != 0 {
			warpq = append(warpq, q[0])
			h, w := q[0][0], q[0][1]
			q = q[1:]
			if h-1 >= 0 && t[h-1][w] > warpCount {
				q = append(q, [2]int{h - 1, w})
				t[h-1][w] = t[h][w]
			}
			if h+1 < H && t[h+1][w] > warpCount {
				q = append(q, [2]int{h + 1, w})
				t[h+1][w] = t[h][w]
			}
			if w-1 >= 0 && t[h][w-1] > warpCount {
				q = append(q, [2]int{h, w - 1})
				t[h][w-1] = t[h][w]
			}
			if w+1 < W && t[h][w+1] > warpCount {
				q = append(q, [2]int{h, w + 1})
				t[h][w+1] = t[h][w]
			}
		}

		if t[Dh][Dw] != math.MaxInt64 {
			break
		}

		warpCount++
		for i := 0; i < len(warpq); i++ {
			h, w := warpq[i][0], warpq[i][1]
			for i := max(0, h-2); i <= min(H-1, h+2); i++ {
				for j := max(0, w-2); j <= min(W-1, w+2); j++ {
					if t[i][j] <= warpCount {
						continue
					}
					t[i][j] = warpCount
					q = append(q, [2]int{i, j})
				}
			}
		}
		warpq = warpq[:0]
	}

	if t[Dh][Dw] == math.MaxInt64 {
		println(-1)
	} else {
		println(t[Dh][Dw])
	}
}

const (
	ioBufferSize = 1 * 1024 * 1024 // 1 MB
)

var stdinScanner = func() *bufio.Scanner {
	result := bufio.NewScanner(os.Stdin)
	result.Buffer(make([]byte, ioBufferSize), ioBufferSize)
	result.Split(bufio.ScanWords)
	return result
}()

func readString() string {
	stdinScanner.Scan()
	return stdinScanner.Text()
}

func readInt() int {
	result, err := strconv.Atoi(readString())
	if err != nil {
		panic(err)
	}
	return result
}

var stdoutWriter = bufio.NewWriter(os.Stdout)

func flush() {
	stdoutWriter.Flush()
}

func println(args ...interface{}) (int, error) {
	return fmt.Fprintln(stdoutWriter, args...)
}


package main

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"strconv"
)

func min(x, y int) int {
	if x < y {
		return x
	}
	return y
}

func max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

func main() {
	defer flush()

	H := readInt()
	W := readInt()
	Ch := readInt() - 1
	Cw := readInt() - 1
	Dh := readInt() - 1
	Dw := readInt() - 1
	S := make([]string, H)
	for i := 0; i < H; i++ {
		S[i] = readString()
	}

	t := make([][]int, H)
	for i := 0; i < H; i++ {
		t[i] = make([]int, W)
		for j := 0; j < W; j++ {
			if S[i][j] == '#' {
				t[i][j] = -1
			} else {
				t[i][j] = math.MaxInt64
			}
		}
	}

	a := 0
	t[Ch][Cw] = a
	q := make([][2]int, 0, 1024)
	q = append(q, [2]int{Ch, Cw})

	warpq := make([][2]int, 0, 1024)
	for len(q) != 0 {
		for len(q) != 0 {
			h, w := q[0][0], q[0][1]
			warpq = append(warpq, [2]int{h, w})
			q = q[1:]
			if h-1 >= 0 && t[h-1][w] > a {
				q = append(q, [2]int{h - 1, w})
				t[h-1][w] = t[h][w]
			}
			if h+1 < H && t[h+1][w] > a {
				q = append(q, [2]int{h + 1, w})
				t[h+1][w] = t[h][w]
			}
			if w-1 >= 0 && t[h][w-1] > a {
				q = append(q, [2]int{h, w - 1})
				t[h][w-1] = t[h][w]
			}
			if w+1 < W && t[h][w+1] > a {
				q = append(q, [2]int{h, w + 1})
				t[h][w+1] = t[h][w]
			}
		}

		if t[Dh][Dw] != math.MaxInt64 {
			break
		}

		a++
		for i := 0; i < len(warpq); i++ {
			h, w := warpq[i][0], warpq[i][1]
			for i := max(0, h-2); i <= min(H-1, h+2); i++ {
				for j := max(0, w-2); j <= min(W-1, w+2); j++ {
					if t[i][j] <= a {
						continue
					}
					t[i][j] = a
					q = append(q, [2]int{i, j})
				}
			}
		}
		warpq = warpq[:0]
	}

	if t[Dh][Dw] == math.MaxInt64 {
		println(-1)
	} else {
		println(t[Dh][Dw])
	}
}

const (
	ioBufferSize = 1 * 1024 * 1024 // 1 MB
)

var stdinScanner = func() *bufio.Scanner {
	result := bufio.NewScanner(os.Stdin)
	result.Buffer(make([]byte, ioBufferSize), ioBufferSize)
	result.Split(bufio.ScanWords)
	return result
}()

func readString() string {
	stdinScanner.Scan()
	return stdinScanner.Text()
}

func readInt() int {
	result, err := strconv.Atoi(readString())
	if err != nil {
		panic(err)
	}
	return result
}

var stdoutWriter = bufio.NewWriter(os.Stdout)

func flush() {
	stdoutWriter.Flush()
}

func println(args ...interface{}) (int, error) {
	return fmt.Fprintln(stdoutWriter, args...)
}


package main

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"strconv"
)

func min(x, y int) int {
	if x < y {
		return x
	}
	return y
}

func max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

func main() {
	defer flush()

	H := readInt()
	W := readInt()
	Ch := readInt() - 1
	Cw := readInt() - 1
	Dh := readInt() - 1
	Dw := readInt() - 1
	S := make([]string, H)
	for i := 0; i < H; i++ {
		S[i] = readString()
	}

	t := make([][]int, H)
	for i := 0; i < H; i++ {
		t[i] = make([]int, W)
		for j := 0; j < W; j++ {
			if S[i][j] == '#' {
				t[i][j] = -1
			} else {
				t[i][j] = math.MaxInt64
			}
		}
	}

	a := 0
	t[Ch][Cw] = a
	q := make([][2]int, 0, 1024)
	q = append(q, [2]int{Ch, Cw})

	for len(q) != 0 {
		warpq := make([][2]int, 0, 1024)
		for len(q) != 0 {
			h, w := q[0][0], q[0][1]
			warpq = append(warpq, [2]int{h, w})
			q = q[1:]
			if h-1 >= 0 && t[h-1][w] > a {
				q = append(q, [2]int{h - 1, w})
				t[h-1][w] = t[h][w]
			}
			if h+1 < H && t[h+1][w] > a {
				q = append(q, [2]int{h + 1, w})
				t[h+1][w] = t[h][w]
			}
			if w-1 >= 0 && t[h][w-1] > a {
				q = append(q, [2]int{h, w - 1})
				t[h][w-1] = t[h][w]
			}
			if w+1 < W && t[h][w+1] > a {
				q = append(q, [2]int{h, w + 1})
				t[h][w+1] = t[h][w]
			}
		}

		if t[Dh][Dw] != math.MaxInt64 {
			break
		}

		a++
		for i := 0; i < len(warpq); i++ {
			h, w := warpq[i][0], warpq[i][1]
			for i := max(0, h-2); i <= min(H-1, h+2); i++ {
				for j := max(0, w-2); j <= min(W-1, w+2); j++ {
					if t[i][j] <= a {
						continue
					}
					t[i][j] = a
					q = append(q, [2]int{i, j})
				}
			}
		}
	}

	if t[Dh][Dw] == math.MaxInt64 {
		println(-1)
	} else {
		println(t[Dh][Dw])
	}
}

const (
	ioBufferSize = 1 * 1024 * 1024 // 1 MB
)

var stdinScanner = func() *bufio.Scanner {
	result := bufio.NewScanner(os.Stdin)
	result.Buffer(make([]byte, ioBufferSize), ioBufferSize)
	result.Split(bufio.ScanWords)
	return result
}()

func readString() string {
	stdinScanner.Scan()
	return stdinScanner.Text()
}

func readInt() int {
	result, err := strconv.Atoi(readString())
	if err != nil {
		panic(err)
	}
	return result
}

var stdoutWriter = bufio.NewWriter(os.Stdout)

func flush() {
	stdoutWriter.Flush()
}

func println(args ...interface{}) (int, error) {
	return fmt.Fprintln(stdoutWriter, args...)
}


package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"math"
	"os"
)

var mod = 1000000007
var inf = 1000000007

func main() {
	r := bufio.NewReader(os.Stdin)
	var H, W int
	fmt.Fscan(r, &H)
	fmt.Fscan(r, &W)

	var ch, cw int
	fmt.Fscan(r, &ch)
	fmt.Fscan(r, &cw)
	ch--
	cw--
	var dh, dw int
	fmt.Fscan(r, &dh)
	fmt.Fscan(r, &dw)
	dh--
	dw--

	matrix := make([]string, H)
	for i := 0; i < H; i++ {
		fmt.Fscan(r, &matrix[i])
	}

	// 各ポイントへのコスト
	d := make([][]int, H)
	for i := 0; i < H; i++ {
		c := make([]int, W)
		for j := 0; j < W; j++ {
			c[j] = math.MaxInt64
		}
		d[i] = c
	}

	ph := &pheap{}
	heap.Init(ph)
	heap.Push(ph, ppoint{0, cw, ch, 0})
	for ph.Len() > 0 {
		p := heap.Pop(ph).(ppoint)
		if d[p.y][p.x] <= p.nc {
			continue
		}

		d[p.y][p.x] = p.nc

		if p.x == dw && p.y == dh {
			break
		}

		for i := -2; i <= 2; i++ {
			for j := -2; j <= 2; j++ {
				if i == 0 && j == 0 {
					continue
				}
				cost := 0
				if (abs(i) == 2 || abs(j) == 2) || (abs(i) == 1 && abs(j) == 1) {
					cost = 1
				}

				//上下左右の探索対象を探す
				nx := p.x + i
				ny := p.y + j
				// 探索対象ならキューに追加
				if nx < 0 || nx >= W || ny < 0 || ny >= H {
					continue
				}
				if matrix[ny][nx] == '#' {
					continue
				}
				if d[ny][nx] < d[p.y][p.x]+cost {
					continue
				}
				heap.Push(ph, ppoint{cost, nx, ny, d[p.y][p.x] + cost})
			}
		}
	}

	// ゴールポイントのコストを出力
	if d[dh][dw] == math.MaxInt64 {
		fmt.Println(-1)
	} else {
		fmt.Println(d[dh][dw])
	}

}

type ppoint struct {
	p  int
	x  int
	y  int
	nc int
}

// priority_queue
type pheap []ppoint

func (h pheap) Len() int           { return len(h) }
func (h pheap) Less(i, j int) bool { return h[i].p < h[j].p }
func (h pheap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
func (h *pheap) Push(x interface{}) {
	*h = append(*h, x.(ppoint))
}
func (h *pheap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

// Queue ...
type Queue []point

// pop ...
func (q *Queue) empty() bool {
	return len(*q) == 0
}

// push ...
func (q *Queue) push(i point) {
	*q = append(*q, i)
}

// pop ...
func (q *Queue) pop() (point, bool) {
	if q.empty() {
		return point{}, false
	} else {
		res := (*q)[0]
		*q = (*q)[1:]
		return res, true
	}
}

// permutations
func permutations(arr []int) [][]int {
	var helper func([]int, int)
	res := [][]int{}

	helper = func(arr []int, n int) {
		if n == 1 {
			tmp := make([]int, len(arr))
			copy(tmp, arr)
			res = append(res, tmp)
		} else {
			for i := 0; i < n; i++ {
				helper(arr, n-1)
				if n%2 == 1 {
					tmp := arr[i]
					arr[i] = arr[n-1]
					arr[n-1] = tmp
				} else {
					tmp := arr[0]
					arr[0] = arr[n-1]
					arr[n-1] = tmp
				}
			}
		}
	}
	helper(arr, len(arr))
	return res
}

// Union-Find
type unionFind struct {
	d []int
}

func newUnionFind(n int) *unionFind {
	uf := new(unionFind)
	uf.d = make([]int, n)
	for i := 0; i < n; i++ {
		uf.d[i] = -1
	}
	return uf
}

func (uf *unionFind) find(x int) int {
	if uf.d[x] < 0 {
		return x
	}
	uf.d[x] = uf.find(uf.d[x])
	return uf.d[x]
}

func (uf *unionFind) unite(x, y int) bool {
	rootX := uf.find(x)
	rootY := uf.find(y)
	if rootX == rootY {
		return false
	}

	if uf.d[rootX] < uf.d[rootY] {
		uf.d[rootX] += uf.d[rootY]
		uf.d[rootY] = rootX
	} else {
		uf.d[rootY] += uf.d[rootX]
		uf.d[rootX] = rootY
	}

	return true
}

func (uf *unionFind) same(x, y int) bool {
	return uf.find(x) == uf.find(y)
}

func (uf *unionFind) size(x int) int {
	return -uf.d[uf.find(x)]
}

// mod
func modpow(a, n, mod int) int {
	res := 1
	for n > 0 {
		if n%2 != 0 {
			res = res * a % mod
		}
		a = a * a % mod
		n = n / 2
	}
	return res
}

func modinv(n, mod int) int {
	return modpow(n, mod-2, mod)
}

func modcomb(n, a, mod int) int {
	x := 1
	y := 1
	for i := 0; i < a; i++ {
		x = x * (n - i)
		x %= mod
		y = y * (i + 1)
		y %= mod
	}
	return x * modpow(y, mod-2, mod) % mod
}

func modfactorial(n, mod int) int {
	result := 1
	for i := 1; i <= n; i++ {
		result = (result * i) % mod
	}
	return result
}

// Combination ...
type Combination struct {
	facts, invs []int
	mod         int
}

// NewCombination ...
func NewCombination(n, mod int) Combination {
	return Combination{
		facts: make([]int, n+1),
		invs:  make([]int, n+1),
		mod:   mod,
	}
}

func (cmb *Combination) calc(n, k int) int {
	ret := cmb.facts[n] * cmb.invs[k]
	ret %= cmb.mod
	ret = ret * cmb.invs[n-k]
	ret %= cmb.mod
	return ret
}

func (cmb *Combination) init(n int) {
	cmb.facts[0] = 1
	// 階乗を算出
	for i := 1; i <= n; i++ {
		cmb.facts[i] = cmb.facts[i-1] * i % cmb.mod
	}
	// 逆元を算出
	cmb.invs[n] = modinv(cmb.facts[n], cmb.mod)
	for i := n - 1; i >= 0; i-- {
		cmb.invs[i] = cmb.invs[i+1] * (i + 1) % cmb.mod
	}
}

// Utility
func min(x, y int) int {
	if x < y {
		return x
	}
	return y
}

func max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

func abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}

func primeFactor(x int) map[int]int {
	res := make(map[int]int)
	for i := 2; i*i <= x; i++ {
		for x%i == 0 {
			res[i]++
			x = x / i
		}
	}
	if x != 1 {
		res[x] = 1
	}
	return res
}

func divisor(x int) []int {
	res := make([]int, 0)
	for i := 1; i*i <= x; i++ {
		if x%i == 0 {
			res = append(res, i)
			if i != x/i {
				res = append(res, x/i)
			}
		}
	}
	return res
}

func gcd(x, y int) int {
	if y == 0 {
		return x
	}
	return gcd(y, x%y)
}

func lcm(x, y int) int {
	return x / gcd(x, y) * y
}

func reverseString(s string) string {
	r := []rune(s)
	for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
		r[i], r[j] = r[j], r[i]
	}
	return string(r)
}

func pow(a, n int) int {
	ret := 1
	for i := 1; i <= n; i++ {
		ret *= a
	}
	return ret
}

// Stack ...
type Stack []int

// pop ...
func (s *Stack) empty() bool {
	return len(*s) == 0
}

// push ...
func (s *Stack) push(i int) {
	*s = append(*s, i)
}

// pop ...
func (s *Stack) pop() (int, bool) {
	if s.empty() {
		return 0, false
	} else {
		index := len(*s) - 1
		res := (*s)[index]
		*s = (*s)[:index]
		return res, true
	}
}

// sortable points
type point struct {
	x int
	y int
}

type points []point

func (p points) Len() int {
	return len(p)
}

func (p points) Less(i, j int) bool {
	return p[i].x < p[j].x
}

func (p points) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}


package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"math"
	"os"
)

var mod = 1000000007
var inf = 1000000007

func main() {
	r := bufio.NewReader(os.Stdin)
	var H, W int
	fmt.Fscan(r, &H)
	fmt.Fscan(r, &W)

	var ch, cw int
	fmt.Fscan(r, &ch)
	fmt.Fscan(r, &cw)
	ch--
	cw--
	var dh, dw int
	fmt.Fscan(r, &dh)
	fmt.Fscan(r, &dw)
	dh--
	dw--

	matrix := make([]string, H)
	for i := 0; i < H; i++ {
		fmt.Fscan(r, &matrix[i])
	}

	// 各ポイントへのコスト
	d := make([][]int, H)
	for i := 0; i < H; i++ {
		c := make([]int, W)
		for j := 0; j < W; j++ {
			c[j] = math.MaxInt64
		}
		d[i] = c
	}

	ph := &pheap{}
	heap.Init(ph)
	heap.Push(ph, ppoint{0, cw, ch, 0})
	for ph.Len() > 0 {
		p := heap.Pop(ph).(ppoint)
		if d[p.y][p.x] < p.nc {
			continue
		}

		d[p.y][p.x] = p.nc

		if p.x == dw && p.y == dh {
			break
		}

		for i := -2; i <= 2; i++ {
			for j := -2; j <= 2; j++ {
				if i == 0 && j == 0 {
					continue
				}
				cost := 0
				if (abs(i) == 2 || abs(j) == 2) || (abs(i) == 1 && abs(j) == 1) {
					cost = 1
				}

				//上下左右の探索対象を探す
				nx := p.x + i
				ny := p.y + j

				if 0 <= nx && nx < W && 0 <= ny && ny < H && matrix[ny][nx] != '#' && d[ny][nx] > d[p.y][p.x]+cost {
					// 探索対象ならキューに追加
					heap.Push(ph, ppoint{cost, nx, ny, d[p.y][p.x] + cost})
				}
			}
		}
	}

	// ゴールポイントのコストを出力
	if d[dh][dw] == math.MaxInt64 {
		fmt.Println(-1)
	} else {
		fmt.Println(d[dh][dw])
	}

}

type ppoint struct {
	p  int
	x  int
	y  int
	nc int
}

// priority_queue
type pheap []ppoint

func (h pheap) Len() int           { return len(h) }
func (h pheap) Less(i, j int) bool { return h[i].p < h[j].p }
func (h pheap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
func (h *pheap) Push(x interface{}) {
	*h = append(*h, x.(ppoint))
}
func (h *pheap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

// Queue ...
type Queue []point

// pop ...
func (q *Queue) empty() bool {
	return len(*q) == 0
}

// push ...
func (q *Queue) push(i point) {
	*q = append(*q, i)
}

// pop ...
func (q *Queue) pop() (point, bool) {
	if q.empty() {
		return point{}, false
	} else {
		res := (*q)[0]
		*q = (*q)[1:]
		return res, true
	}
}

// permutations
func permutations(arr []int) [][]int {
	var helper func([]int, int)
	res := [][]int{}

	helper = func(arr []int, n int) {
		if n == 1 {
			tmp := make([]int, len(arr))
			copy(tmp, arr)
			res = append(res, tmp)
		} else {
			for i := 0; i < n; i++ {
				helper(arr, n-1)
				if n%2 == 1 {
					tmp := arr[i]
					arr[i] = arr[n-1]
					arr[n-1] = tmp
				} else {
					tmp := arr[0]
					arr[0] = arr[n-1]
					arr[n-1] = tmp
				}
			}
		}
	}
	helper(arr, len(arr))
	return res
}

// Union-Find
type unionFind struct {
	d []int
}

func newUnionFind(n int) *unionFind {
	uf := new(unionFind)
	uf.d = make([]int, n)
	for i := 0; i < n; i++ {
		uf.d[i] = -1
	}
	return uf
}

func (uf *unionFind) find(x int) int {
	if uf.d[x] < 0 {
		return x
	}
	uf.d[x] = uf.find(uf.d[x])
	return uf.d[x]
}

func (uf *unionFind) unite(x, y int) bool {
	rootX := uf.find(x)
	rootY := uf.find(y)
	if rootX == rootY {
		return false
	}

	if uf.d[rootX] < uf.d[rootY] {
		uf.d[rootX] += uf.d[rootY]
		uf.d[rootY] = rootX
	} else {
		uf.d[rootY] += uf.d[rootX]
		uf.d[rootX] = rootY
	}

	return true
}

func (uf *unionFind) same(x, y int) bool {
	return uf.find(x) == uf.find(y)
}

func (uf *unionFind) size(x int) int {
	return -uf.d[uf.find(x)]
}

// mod
func modpow(a, n, mod int) int {
	res := 1
	for n > 0 {
		if n%2 != 0 {
			res = res * a % mod
		}
		a = a * a % mod
		n = n / 2
	}
	return res
}

func modinv(n, mod int) int {
	return modpow(n, mod-2, mod)
}

func modcomb(n, a, mod int) int {
	x := 1
	y := 1
	for i := 0; i < a; i++ {
		x = x * (n - i)
		x %= mod
		y = y * (i + 1)
		y %= mod
	}
	return x * modpow(y, mod-2, mod) % mod
}

func modfactorial(n, mod int) int {
	result := 1
	for i := 1; i <= n; i++ {
		result = (result * i) % mod
	}
	return result
}

// Combination ...
type Combination struct {
	facts, invs []int
	mod         int
}

// NewCombination ...
func NewCombination(n, mod int) Combination {
	return Combination{
		facts: make([]int, n+1),
		invs:  make([]int, n+1),
		mod:   mod,
	}
}

func (cmb *Combination) calc(n, k int) int {
	ret := cmb.facts[n] * cmb.invs[k]
	ret %= cmb.mod
	ret = ret * cmb.invs[n-k]
	ret %= cmb.mod
	return ret
}

func (cmb *Combination) init(n int) {
	cmb.facts[0] = 1
	// 階乗を算出
	for i := 1; i <= n; i++ {
		cmb.facts[i] = cmb.facts[i-1] * i % cmb.mod
	}
	// 逆元を算出
	cmb.invs[n] = modinv(cmb.facts[n], cmb.mod)
	for i := n - 1; i >= 0; i-- {
		cmb.invs[i] = cmb.invs[i+1] * (i + 1) % cmb.mod
	}
}

// Utility
func min(x, y int) int {
	if x < y {
		return x
	}
	return y
}

func max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

func abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}

func primeFactor(x int) map[int]int {
	res := make(map[int]int)
	for i := 2; i*i <= x; i++ {
		for x%i == 0 {
			res[i]++
			x = x / i
		}
	}
	if x != 1 {
		res[x] = 1
	}
	return res
}

func divisor(x int) []int {
	res := make([]int, 0)
	for i := 1; i*i <= x; i++ {
		if x%i == 0 {
			res = append(res, i)
			if i != x/i {
				res = append(res, x/i)
			}
		}
	}
	return res
}

func gcd(x, y int) int {
	if y == 0 {
		return x
	}
	return gcd(y, x%y)
}

func lcm(x, y int) int {
	return x / gcd(x, y) * y
}

func reverseString(s string) string {
	r := []rune(s)
	for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
		r[i], r[j] = r[j], r[i]
	}
	return string(r)
}

func pow(a, n int) int {
	ret := 1
	for i := 1; i <= n; i++ {
		ret *= a
	}
	return ret
}

// Stack ...
type Stack []int

// pop ...
func (s *Stack) empty() bool {
	return len(*s) == 0
}

// push ...
func (s *Stack) push(i int) {
	*s = append(*s, i)
}

// pop ...
func (s *Stack) pop() (int, bool) {
	if s.empty() {
		return 0, false
	} else {
		index := len(*s) - 1
		res := (*s)[index]
		*s = (*s)[:index]
		return res, true
	}
}

// sortable points
type point struct {
	x int
	y int
}

type points []point

func (p points) Len() int {
	return len(p)
}

func (p points) Less(i, j int) bool {
	return p[i].x < p[j].x
}

func (p points) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}


package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"math"
	"os"
)

var mod = 1000000007
var inf = 1000000007

func main() {
	r := bufio.NewReader(os.Stdin)
	var H, W int
	fmt.Fscan(r, &H)
	fmt.Fscan(r, &W)

	var ch, cw int
	fmt.Fscan(r, &ch)
	fmt.Fscan(r, &cw)
	ch--
	cw--
	var dh, dw int
	fmt.Fscan(r, &dh)
	fmt.Fscan(r, &dw)
	dh--
	dw--

	matrix := make([]string, H)
	for i := 0; i < H; i++ {
		fmt.Fscan(r, &matrix[i])
	}

	// 各ポイントへのコスト
	d := make([][]int, H)
	for i := 0; i < H; i++ {
		c := make([]int, W)
		for j := 0; j < W; j++ {
			c[j] = math.MaxInt64
		}
		d[i] = c
	}
	// スタートポイントのコストは0
	// d[ch][cw] = 0

	ph := &pheap{}

	heap.Init(ph)
	heap.Push(ph, ppoint{0, cw, ch, 0})

	for ph.Len() > 0 {
		p := heap.Pop(ph).(ppoint)
		if d[p.y][p.x] <= p.nc {
			continue
		}

		d[p.y][p.x] = p.nc

		if p.x == dw && p.y == dh {
			break
		}

		for i := -2; i <= 2; i++ {
			for j := -2; j <= 2; j++ {
				if i == 0 && j == 0 {
					continue
				}
				cost := 0
				if (abs(i) == 2 || abs(j) == 2) || (abs(i) == 1 && abs(j) == 1) {
					cost = 1
				}

				//上下左右の探索対象を探す
				nx := p.x + i
				ny := p.y + j

				if 0 <= nx && nx < W && 0 <= ny && ny < H && matrix[ny][nx] != '#' && d[ny][nx] == math.MaxInt64 {
					// 探索対象ならキューに追加
					heap.Push(ph, ppoint{cost, nx, ny, d[p.y][p.x] + cost})
				}
			}
		}
	}

	// ゴールポイントのコストを出力
	if d[dh][dw] == math.MaxInt64 {
		fmt.Println(-1)
	} else {
		fmt.Println(d[dh][dw])
	}

}

type ppoint struct {
	p  int
	x  int
	y  int
	nc int
}

// priority_queue
type pheap []ppoint

func (h pheap) Len() int           { return len(h) }
func (h pheap) Less(i, j int) bool { return h[i].p < h[j].p }
func (h pheap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
func (h *pheap) Push(x interface{}) {
	*h = append(*h, x.(ppoint))
}
func (h *pheap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

// Queue ...
type Queue []point

// pop ...
func (q *Queue) empty() bool {
	return len(*q) == 0
}

// push ...
func (q *Queue) push(i point) {
	*q = append(*q, i)
}

// pop ...
func (q *Queue) pop() (point, bool) {
	if q.empty() {
		return point{}, false
	} else {
		res := (*q)[0]
		*q = (*q)[1:]
		return res, true
	}
}

// permutations
func permutations(arr []int) [][]int {
	var helper func([]int, int)
	res := [][]int{}

	helper = func(arr []int, n int) {
		if n == 1 {
			tmp := make([]int, len(arr))
			copy(tmp, arr)
			res = append(res, tmp)
		} else {
			for i := 0; i < n; i++ {
				helper(arr, n-1)
				if n%2 == 1 {
					tmp := arr[i]
					arr[i] = arr[n-1]
					arr[n-1] = tmp
				} else {
					tmp := arr[0]
					arr[0] = arr[n-1]
					arr[n-1] = tmp
				}
			}
		}
	}
	helper(arr, len(arr))
	return res
}

// Union-Find
type unionFind struct {
	d []int
}

func newUnionFind(n int) *unionFind {
	uf := new(unionFind)
	uf.d = make([]int, n)
	for i := 0; i < n; i++ {
		uf.d[i] = -1
	}
	return uf
}

func (uf *unionFind) find(x int) int {
	if uf.d[x] < 0 {
		return x
	}
	uf.d[x] = uf.find(uf.d[x])
	return uf.d[x]
}

func (uf *unionFind) unite(x, y int) bool {
	rootX := uf.find(x)
	rootY := uf.find(y)
	if rootX == rootY {
		return false
	}

	if uf.d[rootX] < uf.d[rootY] {
		uf.d[rootX] += uf.d[rootY]
		uf.d[rootY] = rootX
	} else {
		uf.d[rootY] += uf.d[rootX]
		uf.d[rootX] = rootY
	}

	return true
}

func (uf *unionFind) same(x, y int) bool {
	return uf.find(x) == uf.find(y)
}

func (uf *unionFind) size(x int) int {
	return -uf.d[uf.find(x)]
}

// mod
func modpow(a, n, mod int) int {
	res := 1
	for n > 0 {
		if n%2 != 0 {
			res = res * a % mod
		}
		a = a * a % mod
		n = n / 2
	}
	return res
}

func modinv(n, mod int) int {
	return modpow(n, mod-2, mod)
}

func modcomb(n, a, mod int) int {
	x := 1
	y := 1
	for i := 0; i < a; i++ {
		x = x * (n - i)
		x %= mod
		y = y * (i + 1)
		y %= mod
	}
	return x * modpow(y, mod-2, mod) % mod
}

func modfactorial(n, mod int) int {
	result := 1
	for i := 1; i <= n; i++ {
		result = (result * i) % mod
	}
	return result
}

// Combination ...
type Combination struct {
	facts, invs []int
	mod         int
}

// NewCombination ...
func NewCombination(n, mod int) Combination {
	return Combination{
		facts: make([]int, n+1),
		invs:  make([]int, n+1),
		mod:   mod,
	}
}

func (cmb *Combination) calc(n, k int) int {
	ret := cmb.facts[n] * cmb.invs[k]
	ret %= cmb.mod
	ret = ret * cmb.invs[n-k]
	ret %= cmb.mod
	return ret
}

func (cmb *Combination) init(n int) {
	cmb.facts[0] = 1
	// 階乗を算出
	for i := 1; i <= n; i++ {
		cmb.facts[i] = cmb.facts[i-1] * i % cmb.mod
	}
	// 逆元を算出
	cmb.invs[n] = modinv(cmb.facts[n], cmb.mod)
	for i := n - 1; i >= 0; i-- {
		cmb.invs[i] = cmb.invs[i+1] * (i + 1) % cmb.mod
	}
}

// Utility
func min(x, y int) int {
	if x < y {
		return x
	}
	return y
}

func max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

func abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}

func primeFactor(x int) map[int]int {
	res := make(map[int]int)
	for i := 2; i*i <= x; i++ {
		for x%i == 0 {
			res[i]++
			x = x / i
		}
	}
	if x != 1 {
		res[x] = 1
	}
	return res
}

func divisor(x int) []int {
	res := make([]int, 0)
	for i := 1; i*i <= x; i++ {
		if x%i == 0 {
			res = append(res, i)
			if i != x/i {
				res = append(res, x/i)
			}
		}
	}
	return res
}

func gcd(x, y int) int {
	if y == 0 {
		return x
	}
	return gcd(y, x%y)
}

func lcm(x, y int) int {
	return x / gcd(x, y) * y
}

func reverseString(s string) string {
	r := []rune(s)
	for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
		r[i], r[j] = r[j], r[i]
	}
	return string(r)
}

func pow(a, n int) int {
	ret := 1
	for i := 1; i <= n; i++ {
		ret *= a
	}
	return ret
}

// Stack ...
type Stack []int

// pop ...
func (s *Stack) empty() bool {
	return len(*s) == 0
}

// push ...
func (s *Stack) push(i int) {
	*s = append(*s, i)
}

// pop ...
func (s *Stack) pop() (int, bool) {
	if s.empty() {
		return 0, false
	} else {
		index := len(*s) - 1
		res := (*s)[index]
		*s = (*s)[:index]
		return res, true
	}
}

// sortable points
type point struct {
	x int
	y int
}

type points []point

func (p points) Len() int {
	return len(p)
}

func (p points) Less(i, j int) bool {
	return p[i].x < p[j].x
}

func (p points) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}


H, W = gets.chomp.split(" ").map(&:to_i)
C = gets.chomp.split(" ").map(&:to_i)
D = gets.chomp.split(" ").map(&:to_i)
S = [Array.new(W+4, -2), Array.new(W+4, -2)]
H.times{
  S << [-2, -2] + gets.chomp.chars.map{|s| s=='#' ? -2 : -1} + [-2, -2]
}
S << Array.new(W+4, -2)
S << Array.new(W+4, -2)

def add_lst(c, r, stp, lst)
  (S[c][r] = stp; lst << [c, r]) if S[c][r] == -1
end

WP = (-2..2).to_a.product((-2..2).to_a).select{|c, r| c.abs+r.abs > 1}
idx,stp, nxt = 0, 0, []
add_lst(C[0]+1, C[1]+1, stp, nxt)

until nxt.empty? do
  while nxt.size > idx do
    c, r = nxt[idx]
    add_lst(c, r+1, stp, nxt)
    add_lst(c, r-1, stp, nxt)
    add_lst(c+1, r, stp, nxt)
    add_lst(c-1, r, stp, nxt)
    idx += 1
  end
  wrp = []
  stp += 1
  nxt.each{|c, r|
    WP.each{|i, j| add_lst(c+i, r+j, stp, wrp)}
  }
  idx, nxt = 0, wrp
end

puts S[D[0]+1][D[1]+1]


L=100000000
h,w=gets.split.map &:to_i
ch,cw=gets.split.map &:to_i
dh,dw=gets.split.map &:to_i
cp=(w+4)*(ch+1)+cw+1
dp=(w+4)*(dh+1)+dw+1
d=w+4
f=[nil]*( (h+4)*(w+4) )
h.times{|i|
  gets.chomp.each_char.with_index{|c,j|
    next if c==?#
    f[d*(i+2)+j+2]=L
  }
}
qc=[cp]
qn=[]
dns=[-d,-1,1,d]
dms=(-2..2).flat_map{|i|
  (-2..2).each_with_object([]){|j,r|
    e=i*d+j
    r.push(e) if e.abs>1 && e.abs!=d
  }
}
#p [cp,dp,dns,dms,f]
0.step{|x|
  break if qc.empty? && qn.empty?
  until qc.empty?
    e=qc.pop
    next if f[e]<=x
    f[e]=x
    dns.each{|y|
      qc.push(e+y) if f[e+y]
    }
    dms.each{|y|
      qn.push(e+y) if f[e+y]
    }
  end
  qc=qn
  qn=[]
}
puts f[dp]==L ? -1 : f[dp]


h, w = gets.split.map(&:to_i)
ch, cw = gets.split.map(&:to_i)
dh, dw = gets.split.map(&:to_i)

c = [?., ?#]
s = Array.new(h+3) {Array.new(w+3, c[1])}
h.times {|i| s[i+1][1,w+1] = gets.chars}

move = [[1,0], [-1,0], [0,1], [0,-1]]
warp = (-2..2).to_a.product((-2..2).to_a) - move - [[0,0]]

init = 1 << 20
d = Array.new(h+3) {Array.new(w+3, init)}
d[ch][cw] = 0
t = [[ch, cw]]

(0..).each do |k|
    break if t.empty? || d[dh][dw] < init
    u = []

    while (x,y = t.pop)
        next if d[x][y] < k

        move.each do |i,j|
            xx = x + i
            yy = y + j
            if s[xx][yy] == c[0] && d[xx][yy] > k
                d[xx][yy] = k
                t << [xx, yy]
            end
        end

        warp.each do |i,j|
            xx = x + i
            yy = y + j
            if s[xx][yy] == c[0] && d[xx][yy] > k + 1
                d[xx][yy] = k + 1
                u << [xx, yy]
            end
        end
    end

    t = u
end

p d[dh][dw] == init ? -1 : d[dh][dw]


require 'set'; require 'prime'; require 'pp'
INF=Float::INFINITY; MOD=10**9+7

h,w = gets.chomp.split.map(&:to_i)
ch, cw = gets.chomp.split.map(&:to_i).map{|e| e-1}
dh, dw = gets.chomp.split.map(&:to_i).map{|e| e-1}
grid = Array.new(h, :a)
# h = w= 100
# dh, dw = 99, 99
h.times do |i|
  grid[i] = gets.chomp.chars.map(&:to_sym)
  # grid.push(('.' * w).chars)
end

q = []
q.push [0, ch, cw]
grid[ch][cw] = 0

ans = 10000000
until q.empty?
  count, y, x = q.shift
  # p count
  break if count >= ans
  gridyx = grid[y][x]
  # p ['main', count, [y, x], gridyx]
  next if gridyx < count

  [y-2, 0].max.upto([y+2,h-1].min) do |ny|
    [x-2, 0].max.upto([x+2,w-1].min) do |nx|
      next if ny == y && nx == x
      ncount = count
      is_near = (ny-y).abs + (nx-x).abs == 1
      ncount += 1 unless is_near

      val = grid[ny][nx]
      if ny == dh && nx == dw
        ans = [ans, ncount].min
      elsif val == :'#'
        # skip
      elsif val == :'.' || val > ncount
        grid[ny][nx] = ncount
        if is_near
          q.unshift [ncount, ny, nx]
        else
          q.push [ncount, ny, nx]
        end
      end
    end
  end
end

# grid.each{|l| p l }
if ans == 10000000
  puts -1
else
  puts ans
end


require 'set'; require 'prime'; require 'pp'
INF=Float::INFINITY; MOD=10**9+7

h,w = gets.chomp.split.map(&:to_i)
ch, cw = gets.chomp.split.map(&:to_i).map{|e| e-1}
dh, dw = gets.chomp.split.map(&:to_i).map{|e| e-1}
grid = Array.new(h, :a)
# h = w= 100
# dh, dw = 99, 99
h.times do |i|
  grid[i] = gets.chomp.chars.map(&:to_sym)
  # grid.push(('.' * w).chars)
end

q = []
q.push [0, ch, cw]
grid[ch][cw] = 0

ans = 10000000
until q.empty?
  q.uniq!
  count, y, x = q.shift
  break if count >= ans
  gridyx = grid[y][x]
  # p ['main', count, [y, x], gridyx]
  next if gridyx != :'.' && gridyx < count

  [y-2, 0].max.upto([y+2,h-1].min) do |ny|
    [x-2, 0].max.upto([x+2,w-1].min) do |nx|
      next if ny == y && nx == x
      ncount = count
      is_near = (ny-y).abs + (nx-x).abs == 1
      ncount += 1 unless is_near

      val = grid[ny][nx]
      if ny == dh && nx == dw
        ans = [ans, ncount].min
      elsif val == :'#'
        # skip
      elsif val == :'.' || val > ncount
        grid[ny][nx] = ncount
        if is_near
          q.unshift [ncount, ny, nx]
        else
          q.push [ncount, ny, nx]
        end
      end
    end
  end
end

# grid.each{|l| p l }
if ans == 10000000
  puts -1
else
  puts ans
end