// AC

#include <iostream>
#include <vector>

using namespace std;

#define N 1000
#define K 20
#define Q 200000

int n, q;
string grid[N+1];

int count = 0;
int block_x[N*N+1];
int min_y[N*N+1], max_y[N*N+1];
int what[N+1][N+1];

vector<int> tree[N*N+1];

int answer[Q+1];
vector<vector<int>> queries[N+1][N+1];

int dist[N+1][N+1];
int seen[N+1][N+1];
int start[N+1][N+1];

int done[N*N+1];

int total[N*N+1];

void dfs(int node, int prev) {
    total[node] = 1;
    for (auto child : tree[node]) {
        if (child == prev || done[child]) continue;
        dfs(child, node);
        total[node] += total[child];
    }
}

int find_median(int node, int prev, int size) {
    int max_total = 0;
    int heavy_child = 0;
    for (auto child : tree[node]) {
        if (child == prev || done[child]) continue;
        if (total[child] > max_total) {
            max_total = total[child];
            heavy_child = child;
        }
    }
    if (max_total <= size/2) return node;
    else return find_median(heavy_child, node, size);
}

int find_root(int r) {
    dfs(r, 0);
    return find_median(r, 0, total[r]);
}

int rc = 0;
void process_root(int r) {
    rc++;
    int x = block_x[r];
    vector<pair<int,int>> queue;
    for (int y = min_y[r]; y <= max_y[r]; y++) {
        dist[y][x] = 0;
        seen[y][x] = rc;
        start[y][x] = y;
        queue.push_back({y,x});
    }
    int dy[4] = {0, 0, 1, -1};
    int dx[4] = {1, -1, 0, 0};
    for (int i = 0; i < queue.size(); i++) {
        int cy = queue[i].first;
        int cx = queue[i].second;
        for (int j = 0; j < 4; j++) {
            int uy = cy + dy[j];
            int ux = cx + dx[j];
            if (grid[uy][ux] == '#' && seen[uy][ux] != rc && !done[what[uy][ux]]) {
                seen[uy][ux] = rc;
                start[uy][ux] = start[cy][cx];
                dist[uy][ux] = dist[cy][cx] + 1;
                queue.push_back({uy, ux});
                for (auto v : queries[uy][ux]) {
                    int qy = v[0];
                    int qx = v[1];
                    int qi = v[2];
                    if (seen[qy][qx] == rc) {
                        int d = dist[qy][qx] + dist[uy][ux] +
                                abs(start[qy][qx] - start[uy][ux]);
                        answer[qi] = min(answer[qi], d);
                    }
                }
            }
        }
    }
    done[r] = 1;
}

int main() {
    cin >> n >> q;
    for (int i = 1; i <= n; i++) {
        cin >> grid[i];
        grid[i] = '.' + grid[i];
    }

    int other = 0;
    for (int x = 1; x <= n; x++) {
        for (int y = 1; y <= n; y++) {
            if (grid[y][x] == '#') {
                if (grid[y-1][x] == '.') {
                    count++;
                    block_x[count] = x;
                    min_y[count] = y;
                }
                max_y[count] = y;
                what[y][x] = count;
                if (what[y][x-1] && other != what[y][x-1]) {
                    other = what[y][x-1];
                    tree[other].push_back(count);
                    tree[count].push_back(other);
                }
            } else {
                other = 0;
            }
        }
    }

    for (int i = 1; i <= q; i++) {
        int y1, x1, y2, x2;
        cin >> y1 >> x1 >> y2 >> x2;
        queries[y1][x1].push_back({y2, x2, i});
        queries[y2][x2].push_back({y1, x1, i});
        if (what[y1][x1] == what[y2][x2]) {
            answer[i] = abs(y1 - y2);
        } else {
            answer[i] = 1e9;
        }
    }

    int i = 1;
    while (true) {
        while (i <= count && done[i]) i++;
        if (i == count + 1) break;
        int root = find_root(i);
        process_root(root);
    }

    for (int i = 1; i <= q; i++) {
        cout << answer[i] << "\n";
    }
}
