//
//  main.cpp
//  olya_and_energy_drinks-877D
//
//  Created by Rafael on 2018-11-26.
//  Copyright © 2018 Rafael. All rights reserved.
//

#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>

// A simple object for priority queues
struct Pnode
{
    int score;
    int value;

    Pnode(int s, int v) : score(s), value(v){}

    bool operator<(const struct Pnode& other) const{
        return score < other.score;
    }
};

class Graph {
public:
    // an edge is a tuple that stores the endpoint and the direction
    // (a char, like 's' for south)
    std::unordered_map<int, std::vector<std::tuple<int, char>>> edges;

    int shortest_path(int u, int v, int speed){
        // Dijkstra's algorithm
        // Return minimum cost

        std::unordered_map<int, int> dist;
        std::unordered_map<int, int> prev_node;
        std::unordered_map<int, int> prev_direction;

        auto comparator = [&] (int left, int right) { return dist[left] > dist[right]; };

        std::priority_queue<int, std::vector<int>, decltype(comparator)> queue(comparator);

        for (auto &kv : edges){
            int node = kv.first;

            if (node == u)
                dist[node] = 0;
            else
                dist[node] = INFINITY;

            prev_node[node] = -1;
            prev_direction[node] = ' ';
//            queue.push(node);
        }

        queue.push(u);

        while (!queue.empty()){
            int node = queue.top();
            queue.pop();

            if (node == v) break;

            for (std::tuple<int, char> edge : edges[node]){
                int neighbor  = std::get<0>(edge);
                int direction = std::get<1>(edge);

                int alt = dist[node] + 1;
                if (alt < dist[neighbor]){
                    dist[neighbor] = alt;
                    prev_node[neighbor] = node;
                    prev_direction[neighbor] = direction;
                    queue.push(neighbor);
                }
            }
        }

        if (prev_node.find(v) == prev_node.end()) return -1;

        // traverse the path from v to u (backwards)
        // and count the cost (in seconds)

        int p = v;
        int total_time = -1,
            run_dist   = 0;
        char run_dir   = ' ';

        while (prev_node[p] != -1){
            // a change in direction or hitting the max dist given speed
            // cause the start of a new run and increase in total time
            if (prev_direction[p] != run_dir || run_dist == speed){
                total_time += 1;
                run_dist = 0;
            }

            run_dist += 1;
            run_dir   = prev_direction[p];

            p = prev_node[p];
        }

        total_time += 1;

        return total_time;
    }

    void add_edge(int u, int v, char direction){
        edges[u].push_back(std::make_tuple(v, direction));
    }

//    void print_edges(){
//        for (const auto kv : edges){
//            for (const auto neighbor : kv.second){
//                std::cout << kv.first << " " << neighbor << std::endl;
//            }
//        }
//    }
};

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

bool is_in(std::set<int> a_set, int key){
    return a_set.find(key) != a_set.end();
}

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    // read grid input and store unavailable cells
    std::set<int> deadcells;
    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;
        for (int j=0; j<m; j++) {
            if (line[j] == '#')
                deadcells.insert(getid(i, j, n, m));
        }
    }

    // attempt to insert the whole grid in the graph
    // but skip connections with unavailab  le cells

    Graph graph;

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            int current = getid(i, j, n, m);

            if (is_in(deadcells, current))
                continue;

            int north = getid(i-1, j, n, m),
                south = getid(i+1, j, n, m),
                east  = getid(i, j+1, n, m),
                west  = getid(i, j-1, n, m);

            if (north > -1 && !is_in(deadcells, north))
                graph.add_edge(current, north, 'n');
            if (south > -1 && !is_in(deadcells, south))
                graph.add_edge(current, south, 's');
            if (west > -1 && !is_in(deadcells, west))
                graph.add_edge(current, west, 'w');
            if (east > -1 && !is_in(deadcells, east))
                graph.add_edge(current, east, 'e');
        }
    }

    // read query
    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    int id1 = getid(x1-1, y1-1, n, m);
    int id2 = getid(x2-1, y2-1, n, m);

    std::cout << graph.shortest_path(id1, id2, k);

    return 0;
}


#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>
#include <algorithm>

class Graph {
public:
    // an edge is a tuple that stores the endpoint and the direction
    // (a char, like 's' for south)
    std::unordered_map<int, std::vector<std::tuple<int, char>>> edges;

    int shortest_path(int u, int v, int speed){
        // Dijkstra's algorithm
        // Return minimum cost

//        static const int inf = std::numeric_limits<int>::max();
        static bool visited[1000000];
        static int  run_dist[1000000];
        static int  time[1000000];
        static int  prev_node[1000000];
        static char prev_direction[1000000];
//
        std::fill_n(visited, 1000000, false);
        std::fill_n(run_dist, 1000000, 0);
        std::fill_n(time, 1000000, 1000000);
        std::fill_n(prev_node, 1000000, -1);
        std::fill_n(prev_direction, 1000000, ' ');

        auto comparator = [&] (int left, int right) { return time[left] > time[right]; };

        std::priority_queue<int, std::vector<int>, decltype(comparator)> queue(comparator);

        time[u] = 0;
        run_dist[u] = 0;

        queue.push(u);

        while (!queue.empty()){
            int node = queue.top();
            queue.pop();

            if (visited[node]) continue;
            else visited[node] = true;

            for (std::tuple<int, char> edge : edges[node]){
                int neighbor  = std::get<0>(edge);
                int direction = std::get<1>(edge);

                int delta = 0;
                if (direction != prev_direction[node] ||
                    run_dist[node] == speed)
                    delta = 1;

                int alt = time[node] + delta;
                if (alt < time[neighbor]){
                    time[neighbor] = alt;
                    prev_node[neighbor] = node;
                    prev_direction[neighbor] = direction;
                    run_dist[neighbor] = delta == 0 ? run_dist[node] + 1 : 1;

                    if (neighbor == v) break;

                    queue.push(neighbor);
                }
            }
        }

        if (prev_node[v] == -1)
            return -1;

        return time[v];

//        return 0;
    }

    void add_edge(int u, int v, char direction){
        edges[u].push_back(std::make_tuple(v, direction));
    }

};

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

bool is_in(std::set<int> a_set, int key){
    return a_set.find(key) != a_set.end();
}

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    // read grid input and store unavailable cells
    bool deadcells[1000000];
    std::fill_n(deadcells, 1000000, false);

    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;

        for (int j=0; j<m; j++) {
            if (line[j] == '#')
                deadcells[getid(i, j, n, m)] = true;
            //                deadcells.insert(getid(i, j, n, m));
        }
    }

    // attempt to insert the whole grid in the graph
    // but skip connections with unavailable cells

    Graph graph;

    int current = -1,
        max = m*n -1;

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            current += 1;

            if (deadcells[current])
                continue;

            int north = current - m,
                south = current + m,
                east  = j == m-1 ? -1 : current + 1,
                west  = j == 0   ? -1 : current - 1;

            if (east > -1 && !deadcells[east])
                graph.add_edge(current, east, 'e');
            if (west > -1 && !deadcells[west])
                graph.add_edge(current, west, 'w');
            if (north > -1 && !deadcells[north])
                graph.add_edge(current, north, 'n');
            if (south <= max && !deadcells[south])
                graph.add_edge(current, south, 's');

        }
    }

    // read query
    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    int id1 = getid(x1-1, y1-1, n, m);
    int id2 = getid(x2-1, y2-1, n, m);

//    if (graph.edges.find(id1) == graph.edges.end())
//        std::cout << -1;

    std::cout << graph.shortest_path(id1, id2, k);
    return 0;
}


//
//  main.cpp
//  olya_and_energy_drinks-877D
//
//  Created by Rafael on 2018-11-26.
//  Copyright © 2018 Rafael. All rights reserved.
//

#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>
#include <algorithm>

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

struct Cell {
    int row, col;
    Cell(int row, int col): row(row), col(col) {};
};

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    // read grid input and store unavailable cells
    bool valid[1000][1000];

    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;

        for (int j=0; j<m; j++) {
            if (line[j] == '.')
                valid[i][j] = true;
        }
    }

    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    Cell u = {x1-1, y1-1};
    Cell v = {x2-1, y2-1};

    static int dist[1000][1000];
    std::fill_n( &dist[0][0], 1000*1000, 1000000);
    std::queue<Cell> queue;
    queue.push(u);
    dist[u.row][u.col] = 0;

    while (!queue.empty()){
        Cell c = queue.front();
        queue.pop();

        if (c.row == v.row && c.col == v.col)
            break;

        int d = dist[c.row][c.col];

        for (int i = c.row + 1; i <= c.row + k && valid[i][c.col] && i <= n; i++) {
            int alt = d + 1;
            if (alt < dist[i][c.col]){
                dist[i][c.col] = alt;
                queue.push(Cell(i,c.col));
            }
        }

        for (int i = c.row - 1; i >= c.row - k && valid[i][c.col] && i>=0; i--) {
            int alt = d + 1;
            if (alt < dist[i][c.col]){
                dist[i][c.col] = alt;
                queue.push(Cell(i,c.col));
            }
        }

        for (int j = c.col + 1; j <= c.col + k && valid[c.row][j] && j<=m; j++) {
            int alt = d + 1;
            if (alt < dist[c.row][j]){
                dist[c.row][j] = alt;
                queue.push(Cell(c.row,j));
            }
        }

        for (int j = c.col - 1; j >= c.col - k && valid[c.row][j] && j>=0; j--) {
            int alt = d + 1;
            if (alt < dist[c.row][j]){
                dist[c.row][j] = alt;
                queue.push(Cell(c.row,j));
            }
        }
    }

    if (dist[v.row][v.col] == 1000000){
        std::cout << -1;
    } else {
        std::cout << dist[v.row][v.col];
    }

    return 0;
}


//
//  main.cpp
//  olya_and_energy_drinks-877D
//
//  Created by Rafael on 2018-11-26.
//  Copyright © 2018 Rafael. All rights reserved.
//

#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>

// A simple object for priority queues
struct Pnode
{
    int score;
    int value;

    Pnode(int s, int v) : score(s), value(v){}

    bool operator<(const struct Pnode& other) const{
        return score < other.score;
    }
};

class Graph {
public:
    // an edge is a tuple that stores the endpoint and the direction
    // (a char, like 's' for south)
    std::unordered_map<int, std::vector<std::tuple<int, char>>> edges;

    int shortest_path(int u, int v, int speed){
        // Dijkstra's algorithm
        // Return minimum cost

        std::unordered_map<int, int> time;
        std::unordered_map<int, int> run_dist;
        std::unordered_map<int, int> prev_node;
        std::unordered_map<int, int> prev_direction;

        auto comparator = [&] (int left, int right) { return time[left] < time[right]; };

//        std::priority_queue<int, std::vector<int>, decltype(comparator)> queue(comparator);
        std::vector<int> queue;
        std::make_heap(queue.begin(), queue.end(), comparator);

        for (auto &kv : edges){
            int node = kv.first;

            time[node] = node == u ? 0 : std::numeric_limits<int>::max();

            prev_node[node] = -1;
//            prev_direction[node] = ' ';
        }

//        queue.push(u);
        queue.push_back(u);
        std::push_heap(queue.begin(), queue.end(), comparator);

        bool in_queue[1000000] = {false};

        while (!queue.empty()){
            int node = queue.front();
            std::pop_heap(queue.begin(), queue.end(), comparator);
            queue.pop_back();
//            int node = queue.top();
//            queue.pop();

            in_queue[node] = false;

            if (node == v) break;

            for (std::tuple<int, char> edge : edges[node]){
                int neighbor  = std::get<0>(edge);
                int direction = std::get<1>(edge);

                int delta = 0;
                if (direction != prev_direction[node] ||
                    run_dist[node] == speed)
                    delta = 1;

                int alt = time[node] + delta;
                if (alt < time[neighbor]){
                    time[neighbor] = alt;
                    prev_node[neighbor] = node;
                    prev_direction[neighbor] = direction;
                    run_dist[neighbor] = delta == 0 ? run_dist[node] + 1 : 1;

                    if (!in_queue[neighbor]){
                        queue.push_back(neighbor);
                        std::push_heap(queue.begin(), queue.end(), comparator);
//                        queue.push(neighbor);
//                        in_queue[neighbor] = true;
                    } else {
                        std::sort_heap(queue.begin(), queue.end(), comparator);
                    }
                }
            }
        }

        if (prev_node.find(v) == prev_node.end() || prev_node[v] == -1) return -1;

        return time[v];
    }

    void add_edge(int u, int v, char direction){
        edges[u].push_back(std::make_tuple(v, direction));
    }

};

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

bool is_in(std::set<int> a_set, int key){
    return a_set.find(key) != a_set.end();
}

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    // read grid input and store unavailable cells
    bool deadcells[1000000] = {false};
//    std::set<int> deadcells;
    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;
        for (int j=0; j<m; j++) {
            if (line[j] == '#')
                deadcells[getid(i, j, n, m)] = true;
//                deadcells.insert(getid(i, j, n, m));
        }
    }

    // attempt to insert the whole grid in the graph
    // but skip connections with unavailable cells

    Graph graph;

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            int current = getid(i, j, n, m);

            if (deadcells[current])
                continue;

            int north = getid(i-1, j, n, m),
                south = getid(i+1, j, n, m),
                east  = getid(i, j+1, n, m),
                west  = getid(i, j-1, n, m);

            if (north > -1 && !deadcells[north])
                graph.add_edge(current, north, 'n');
            if (south > -1 && !deadcells[south])
                graph.add_edge(current, south, 's');
            if (west > -1 && !deadcells[west])
                graph.add_edge(current, west, 'w');
            if (east > -1 && !deadcells[east])
                graph.add_edge(current, east, 'e');
        }
    }

    // read query
    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    int id1 = getid(x1-1, y1-1, n, m);
    int id2 = getid(x2-1, y2-1, n, m);

    std::cout << graph.shortest_path(id1, id2, k);

    return 0;
}


//
//  main.cpp
//  olya_and_energy_drinks-877D
//
//  Created by Rafael on 2018-11-26.
//  Copyright © 2018 Rafael. All rights reserved.
//

#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>

// A simple object for priority queues
struct Pnode
{
    int score;
    int value;

    Pnode(int s, int v) : score(s), value(v){}

    bool operator<(const struct Pnode& other) const{
        return score < other.score;
    }
};

class Graph {
public:
    // an edge is a tuple that stores the endpoint and the direction
    // (a char, like 's' for south)
    std::unordered_map<int, std::vector<std::tuple<int, char>>> edges;

    int shortest_path(int u, int v, int speed){
        // Dijkstra's algorithm
        // Return minimum cost

        std::unordered_map<int, int> dist;
        std::unordered_map<int, int> prev_node;
        std::unordered_map<int, int> prev_direction;

        auto comparator = [&] (int left, int right) { return dist[left] > dist[right]; };

        std::priority_queue<int, std::vector<int>, decltype(comparator)> queue(comparator);

        for (auto &kv : edges){
            int node = kv.first;

            if (node == u)
                dist[node] = 0;
            else
                dist[node] = std::numeric_limits<int>::max();

            prev_node[node] = -1;
            prev_direction[node] = ' ';
            //            queue.push(node);
        }

        queue.push(u);

        while (!queue.empty()){
            int node = queue.top();
            queue.pop();

            if (node == v) break;

            for (std::tuple<int, char> edge : edges[node]){
                int neighbor  = std::get<0>(edge);
                int direction = std::get<1>(edge);

                // penalize changes in direction
                int weight = prev_direction[node] != direction ? 2 : 1;

                int alt = dist[node] + weight;
                if (alt < dist[neighbor]){
                    dist[neighbor] = alt;
                    prev_node[neighbor] = node;
                    prev_direction[neighbor] = direction;
                    queue.push(neighbor);
                }
            }
        }

        if (prev_node.find(v) == prev_node.end() || prev_node[v] == -1) return -1;

        // traverse the path from v to u (backwards)
        // and count the cost (in seconds)

        int p = v;
        int total_time = -1,
            run_dist   = 0;
        char run_dir   = ' ';

        while (prev_node[p] != -1){
            // a change in direction or hitting the max dist given speed
            // cause the start of a new run and increase in total time
            if (prev_direction[p] != run_dir || run_dist == speed){
                total_time += 1;
                run_dist = 0;
            }

            run_dist += 1;
            run_dir   = prev_direction[p];

            p = prev_node[p];
        }

        total_time += 1;

        return total_time;
    }

    void add_edge(int u, int v, char direction){
        edges[u].push_back(std::make_tuple(v, direction));
    }

};

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

bool is_in(std::set<int> a_set, int key){
    return a_set.find(key) != a_set.end();
}

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    // read grid input and store unavailable cells
    bool deadcells[1000000] = {false};
//    std::set<int> deadcells;
    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;
        for (int j=0; j<m; j++) {
            if (line[j] == '#')
                deadcells[getid(i, j, n, m)] = true;
//                deadcells.insert(getid(i, j, n, m));
        }
    }

    // attempt to insert the whole grid in the graph
    // but skip connections with unavailable cells

    Graph graph;

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            int current = getid(i, j, n, m);

            if (deadcells[current])
                continue;

            int north = getid(i-1, j, n, m),
                south = getid(i+1, j, n, m),
                east  = getid(i, j+1, n, m),
                west  = getid(i, j-1, n, m);

            if (north > -1 && !deadcells[north])
                graph.add_edge(current, north, 'n');
            if (south > -1 && !deadcells[south])
                graph.add_edge(current, south, 's');
            if (west > -1 && !deadcells[west])
                graph.add_edge(current, west, 'w');
            if (east > -1 && !deadcells[east])
                graph.add_edge(current, east, 'e');
        }
    }

    // read query
    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    int id1 = getid(x1-1, y1-1, n, m);
    int id2 = getid(x2-1, y2-1, n, m);

    std::cout << graph.shortest_path(id1, id2, k);

    return 0;
}


//
//  main.cpp
//  olya_and_energy_drinks-877D
//
//  Created by Rafael on 2018-11-26.
//  Copyright © 2018 Rafael. All rights reserved.
//

#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>

// A simple object for priority queues
struct Pnode
{
    int score;
    int value;

    Pnode(int s, int v) : score(s), value(v){}

    bool operator<(const struct Pnode& other) const{
        return score < other.score;
    }
};

class Graph {
public:
    // an edge is a tuple that stores the endpoint and the direction
    // (a char, like 's' for south)
    std::unordered_map<int, std::vector<std::tuple<int, char>>> edges;

    int shortest_path(int u, int v, int speed){
        // Dijkstra's algorithm
        // Return minimum cost

        std::unordered_map<int, int> dist;
        std::unordered_map<int, int> prev_node;
        std::unordered_map<int, int> prev_direction;

        auto comparator = [&] (int left, int right) { return dist[left] > dist[right]; };

        std::priority_queue<int, std::vector<int>, decltype(comparator)> queue(comparator);

        for (auto &kv : edges){
            int node = kv.first;

            if (node == u)
                dist[node] = 0;
            else
                dist[node] = std::numeric_limits<int>::max();

            prev_node[node] = -1;
            prev_direction[node] = ' ';
//            queue.push(node);
        }

        queue.push(u);

        while (!queue.empty()){
            int node = queue.top();
            queue.pop();

            if (node == v) break;

            for (std::tuple<int, char> edge : edges[node]){
                int neighbor  = std::get<0>(edge);
                int direction = std::get<1>(edge);

                int alt = dist[node] + 1;
                if (alt < dist[neighbor]){
                    dist[neighbor] = alt;
                    prev_node[neighbor] = node;
                    prev_direction[neighbor] = direction;
                    queue.push(neighbor);
                }
            }
        }

        if (prev_node.find(v) == prev_node.end()) return -1;

        // traverse the path from v to u (backwards)
        // and count the cost (in seconds)

        int p = v;
        int total_time = -1,
            run_dist   = 0;
        char run_dir   = ' ';

        while (prev_node[p] != -1){
            // a change in direction or hitting the max dist given speed
            // cause the start of a new run and increase in total time
            if (prev_direction[p] != run_dir || run_dist == speed){
                total_time += 1;
                run_dist = 0;
            }

            run_dist += 1;
            run_dir   = prev_direction[p];

            p = prev_node[p];
        }

        total_time += 1;

        return total_time;
    }

    void add_edge(int u, int v, char direction){
        edges[u].push_back(std::make_tuple(v, direction));
    }

};

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

bool is_in(std::set<int> a_set, int key){
    return a_set.find(key) != a_set.end();
}

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    // read grid input and store unavailable cells
    std::set<int> deadcells;
    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;
        for (int j=0; j<m; j++) {
            if (line[j] == '#')
                deadcells.insert(getid(i, j, n, m));
        }
    }

    // attempt to insert the whole grid in the graph
    // but skip connections with unavailab  le cells

    Graph graph;

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            int current = getid(i, j, n, m);

            if (is_in(deadcells, current))
                continue;

            int north = getid(i-1, j, n, m),
                south = getid(i+1, j, n, m),
                east  = getid(i, j+1, n, m),
                west  = getid(i, j-1, n, m);

            if (north > -1 && !is_in(deadcells, north))
                graph.add_edge(current, north, 'n');
            if (south > -1 && !is_in(deadcells, south))
                graph.add_edge(current, south, 's');
            if (west > -1 && !is_in(deadcells, west))
                graph.add_edge(current, west, 'w');
            if (east > -1 && !is_in(deadcells, east))
                graph.add_edge(current, east, 'e');
        }
    }

    // read query
    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    int id1 = getid(x1-1, y1-1, n, m);
    int id2 = getid(x2-1, y2-1, n, m);

    std::cout << graph.shortest_path(id1, id2, k);

    return 0;
}


//
//  main.cpp
//  olya_and_energy_drinks-877D
//
//  Created by Rafael on 2018-11-26.
//  Copyright © 2018 Rafael. All rights reserved.
//

#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>
#include <algorithm>

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

struct Cell {
    int row, col;
    Cell(int row, int col): row(row), col(col) {};
};

bool valid[1000][1000];
int dist[1000][1000];

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;

        for (int j=0; j<m; j++) {
            if (line[j] == '.')
                valid[i][j] = true;
        }
    }

    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    Cell u = {x1-1, y1-1};
    Cell v = {x2-1, y2-1};

    std::fill_n(&dist[0][0], 1000*1000, 1000000);
    std::queue<Cell> queue;
    queue.push(u);
    dist[u.row][u.col] = 0;

    while (!queue.empty()){
        Cell c = queue.front();
        queue.pop();

        if (c.row == v.row && c.col == v.col)
            break;

        int d = dist[c.row][c.col];

        for (int i = c.row + 1; i <= c.row + k && i < n && valid[i][c.col]; i++) {
            int alt = d + 1;
            if (alt < dist[i][c.col]){
                dist[i][c.col] = alt;
                queue.push(Cell(i,c.col));
            }
        }

        for (int i = c.row - 1; i >= c.row - k && i>=0 && valid[i][c.col]; i--) {
            int alt = d + 1;
            if (alt < dist[i][c.col]){
                dist[i][c.col] = alt;
                queue.push(Cell(i,c.col));
            }
        }

        for (int j = c.col + 1; j <= c.col + k && j<m && valid[c.row][j]; j++) {
            int alt = d + 1;
            if (alt < dist[c.row][j]){
                dist[c.row][j] = alt;
                queue.push(Cell(c.row,j));
            }
        }

        for (int j = c.col - 1; j >= c.col - k && j>=0 && valid[c.row][j]; j--) {
            int alt = d + 1;
            if (alt < dist[c.row][j]){
                dist[c.row][j] = alt;
                queue.push(Cell(c.row,j));
            }
        }
    }

    if (dist[v.row][v.col] == 1000000){
        std::cout << -1;
    } else {
        std::cout << dist[v.row][v.col];
    }

    return 0;
}


//
//  main.cpp
//  olya_and_energy_drinks-877D
//
//  Created by Rafael on 2018-11-26.
//  Copyright © 2018 Rafael. All rights reserved.
//

#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>

// A simple object for priority queues
struct Pnode
{
    int score;
    int value;

    Pnode(int s, int v) : score(s), value(v){}

    bool operator<(const struct Pnode& other) const{
        return score < other.score;
    }
};

class Graph {
public:
    // an edge is a tuple that stores the endpoint and the direction
    // (a char, like 's' for south)
    std::unordered_map<int, std::vector<std::tuple<int, char>>> edges;

    int shortest_path(int u, int v, int speed){
        // Dijkstra's algorithm
        // Return minimum cost

        std::unordered_map<int, int> dist;
        std::unordered_map<int, int> prev_node;
        std::unordered_map<int, int> prev_direction;

        auto comparator = [&] (int left, int right) { return dist[left] > dist[right]; };

        std::priority_queue<int, std::vector<int>, decltype(comparator)> queue(comparator);

        for (auto &kv : edges){
            int node = kv.first;

            if (node == u)
                dist[node] = 0;
            else
                dist[node] = std::numeric_limits<int>::max();

            prev_node[node] = -1;
            prev_direction[node] = ' ';
//            queue.push(node);
        }

        queue.push(u);

        while (!queue.empty()){
            int node = queue.top();
            queue.pop();

            if (node == v) break;

            for (std::tuple<int, char> edge : edges[node]){
                int neighbor  = std::get<0>(edge);
                int direction = std::get<1>(edge);

                int alt = dist[node] + 1;
                if (alt < dist[neighbor]){
                    dist[neighbor] = alt;
                    prev_node[neighbor] = node;
                    prev_direction[neighbor] = direction;
                    queue.push(neighbor);
                }
            }
        }

        if (prev_node.find(v) == prev_node.end()) return -1;

        // traverse the path from v to u (backwards)
        // and count the cost (in seconds)

        int p = v;
        int total_time = -1,
            run_dist   = 0;
        char run_dir   = ' ';

        while (prev_node[p] != -1){
            // a change in direction or hitting the max dist given speed
            // cause the start of a new run and increase in total time
            if (prev_direction[p] != run_dir || run_dist == speed){
                total_time += 1;
                run_dist = 0;
            }

            run_dist += 1;
            run_dir   = prev_direction[p];

            p = prev_node[p];
        }

        total_time += 1;

        return total_time;
    }

    void add_edge(int u, int v, char direction){
        edges[u].push_back(std::make_tuple(v, direction));
    }

//    void print_edges(){
//        for (const auto kv : edges){
//            for (const auto neighbor : kv.second){
//                std::cout << kv.first << " " << neighbor << std::endl;
//            }
//        }
//    }
};

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

bool is_in(std::set<int> a_set, int key){
    return a_set.find(key) != a_set.end();
}

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    char c;
//    std::cin >> c; // newline

    // read grid input and store unavailable cells
    std::set<int> deadcells;
    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            std::cin >> c;
            if (c == '#')
                deadcells.insert(getid(i, j, n, m));
        }
//        std::cin >> c; // newline
    }

    // attempt to insert the whole grid in the graph
    // but skip connections with unavailab  le cells

    Graph graph;

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            int current = getid(i, j, n, m);

            if (is_in(deadcells, current))
                continue;

            int north = getid(i-1, j, n, m),
                south = getid(i+1, j, n, m),
                east  = getid(i, j+1, n, m),
                west  = getid(i, j-1, n, m);

            if (north > -1 && !is_in(deadcells, north))
                graph.add_edge(current, north, 'n');
            if (south > -1 && !is_in(deadcells, south))
                graph.add_edge(current, south, 's');
            if (west > -1 && !is_in(deadcells, west))
                graph.add_edge(current, west, 'w');
            if (east > -1 && !is_in(deadcells, east))
                graph.add_edge(current, east, 'e');
        }
    }

    // read query
    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    int id1 = getid(x1-1, y1-1, n, m);
    int id2 = getid(x2-1, y2-1, n, m);

    std::cout << graph.shortest_path(id1, id2, k);

    return 0;
}


#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>
#include <algorithm>

struct Cell {
    int row, col;
    Cell(int row, int col): row(row), col(col) {};
};

bool valid[1000][1000];
int dist[1000][1000];

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;

        for (int j=0; j<m; j++) {
            if (line[j] == '.')
                valid[i][j] = true;
        }
    }

    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    Cell u = {x1-1, y1-1};
    Cell v = {x2-1, y2-1};

    std::fill_n(&dist[0][0], 1000*1000, 1000000);
    std::queue<Cell> queue;
    queue.push(u);
    dist[u.row][u.col] = 0;

    while (!queue.empty()){
        Cell c = queue.front();
        queue.pop();

        int row = c.row;
        int col = c.col;

        int d = dist[row][col];
        int alt = d + 1;

        for (int i = row + 1; i < n && i <= row + k && valid[i][col]; i++) {
            if (i == v.row && col == v.col){
                std::cout << alt;
                return 0;
            }

            if (alt < dist[i][col]){
                dist[i][col] = alt;
                queue.emplace(i,col);
            }
        }

        for (int i = row - 1; i >= 0 && i >= row - k && valid[i][col]; i--) {
            if (i == v.row && col == v.col){
                std::cout << alt;
                return 0;
            }

            if (alt < dist[i][col]){
                dist[i][col] = alt;
                queue.emplace(i,col);
            }
        }

        for (int j = col + 1; j < m && j <= col + k && valid[row][j]; j++) {
            if (row == v.row && j == v.col){
                std::cout << alt;
                return 0;
            }

            if (alt < dist[row][j]){
                dist[row][j] = alt;
                queue.emplace(row,j);
            }
        }

        for (int j = col - 1; j >= 0 && j >= col - k && valid[row][j]; j--) {
            if (row == v.row && j == v.col){
                std::cout << alt;
                return 0;
            }

            if (alt < dist[row][j]){
                dist[row][j] = alt;
                queue.emplace(row,j);
            }
        }
    }

    if (dist[v.row][v.col] == 1000000){
        std::cout << -1;
    } else {
        std::cout << dist[v.row][v.col];
    }

    return 0;
}


#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>
#include <algorithm>

struct Cell {
    int row, col;
    Cell(int row, int col): row(row), col(col) {};
};

bool valid[1000][1000];
int dist[1000][1000];

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;

        for (int j=0; j<m; j++) {
            if (line[j] == '.')
                valid[i][j] = true;
        }
    }

    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    Cell u = {x1-1, y1-1};
    Cell v = {x2-1, y2-1};

    std::fill_n(&dist[0][0], 1000*1000, 1000000);
    std::queue<Cell> queue;
    queue.push(u);
    dist[u.row][u.col] = 0;

    while (!queue.empty()){
        Cell c = queue.front();
        queue.pop();

        int row = c.row;
        int col = c.col;

        if (row == v.row && col == v.col)
            break;

        int d = dist[row][col];
        int alt = d + 1;

        for (int i = row + 1; i <= n && i < row + k && valid[i][col]; i++) {
            if (i == v.row && col == v.col){
                std::cout << alt;
                return 0;
            }

            if (alt < dist[i][col]){
                dist[i][col] = alt;
                queue.emplace(i,col);
            }
        }

        for (int i = row - 1; i >= 0 && i >= row - k && valid[i][col]; i--) {
            if (i == v.row && col == v.col){
                std::cout << alt;
                return 0;
            }

            if (alt < dist[i][col]){
                dist[i][col] = alt;
                queue.emplace(i,col);
            }
        }

        for (int j = col + 1; j < m && j <= col + k && valid[row][j]; j++) {
            if (row == v.row && j == v.col){
                std::cout << alt;
                return 0;
            }

            if (alt < dist[row][j]){
                dist[row][j] = alt;
                queue.emplace(row,j);
            }
        }

        for (int j = col - 1; j >= 0 && j >= col - k && valid[row][j]; j--) {
            if (row == v.row && j == v.col){
                std::cout << alt;
                return 0;
            }

            if (alt < dist[row][j]){
                dist[row][j] = alt;
                queue.emplace(row,j);
            }
        }
    }

    if (dist[v.row][v.col] == 1000000){
        std::cout << -1;
    } else {
        std::cout << dist[v.row][v.col];
    }

    return 0;
}


//
//  main.cpp
//  olya_and_energy_drinks-877D
//
//  Created by Rafael on 2018-11-26.
//  Copyright © 2018 Rafael. All rights reserved.
//

#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>

// A simple object for priority queues
struct Pnode
{
    int score;
    int value;

    Pnode(int s, int v) : score(s), value(v){}

    bool operator<(const struct Pnode& other) const{
        return score < other.score;
    }
};

class Graph {
public:
    // an edge is a tuple that stores the endpoint and the direction
    // (a char, like 's' for south)
    std::unordered_map<int, std::vector<std::tuple<int, char>>> edges;

    int shortest_path(int u, int v, int speed){
        // Dijkstra's algorithm
        // Return minimum cost

        std::unordered_map<int, int> time;
        std::unordered_map<int, int> run_dist;
        std::unordered_map<int, int> prev_node;
        std::unordered_map<int, int> prev_direction;

        auto comparator = [&] (int left, int right) { return time[left] > time[right]; };

        std::priority_queue<int, std::vector<int>, decltype(comparator)> queue(comparator);

        for (auto &kv : edges){
            int node = kv.first;

            time[node] = node == u ? 0 : std::numeric_limits<int>::max();

            prev_node[node] = -1;
            prev_direction[node] = ' ';
        }

        queue.push(u);

        while (!queue.empty()){
            int node = queue.top();
            queue.pop();

            if (node == v) break;

            for (std::tuple<int, char> edge : edges[node]){
                int neighbor  = std::get<0>(edge);
                int direction = std::get<1>(edge);

                int delta = 0;
                if (direction != prev_direction[node] ||
                    run_dist[node] == speed)
                    delta = 1;

                int alt = time[node] + delta;
                if (alt < time[neighbor]){
                    time[neighbor] = alt;
                    prev_node[neighbor] = node;
                    prev_direction[neighbor] = direction;
                    run_dist[neighbor] = delta == 0 ? run_dist[node] + 1 : 1;
                    queue.push(neighbor);
                }
            }
        }

        if (prev_node.find(v) == prev_node.end() || prev_node[v] == -1) return -1;

        return time[v];
    }

    void add_edge(int u, int v, char direction){
        edges[u].push_back(std::make_tuple(v, direction));
    }

};

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

bool is_in(std::set<int> a_set, int key){
    return a_set.find(key) != a_set.end();
}

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    // read grid input and store unavailable cells
    bool deadcells[1000000] = {false};
//    std::set<int> deadcells;
    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;
        for (int j=0; j<m; j++) {
            if (line[j] == '#')
                deadcells[getid(i, j, n, m)] = true;
//                deadcells.insert(getid(i, j, n, m));
        }
    }

    // attempt to insert the whole grid in the graph
    // but skip connections with unavailable cells

    Graph graph;

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            int current = getid(i, j, n, m);

            if (deadcells[current])
                continue;

            int north = getid(i-1, j, n, m),
                south = getid(i+1, j, n, m),
                east  = getid(i, j+1, n, m),
                west  = getid(i, j-1, n, m);

            if (north > -1 && !deadcells[north])
                graph.add_edge(current, north, 'n');
            if (south > -1 && !deadcells[south])
                graph.add_edge(current, south, 's');
            if (west > -1 && !deadcells[west])
                graph.add_edge(current, west, 'w');
            if (east > -1 && !deadcells[east])
                graph.add_edge(current, east, 'e');
        }
    }

    // read query
    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    int id1 = getid(x1-1, y1-1, n, m);
    int id2 = getid(x2-1, y2-1, n, m);

    std::cout << graph.shortest_path(id1, id2, k);

    return 0;
}


//
//  main.cpp
//  olya_and_energy_drinks-877D
//
//  Created by Rafael on 2018-11-26.
//  Copyright © 2018 Rafael. All rights reserved.
//

#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>

// A simple object for priority queues
struct Pnode
{
    int score;
    int value;

    Pnode(int s, int v) : score(s), value(v){}

    bool operator<(const struct Pnode& other) const{
        return score < other.score;
    }
};

class Graph {
public:
    // an edge is a tuple that stores the endpoint and the direction
    // (a char, like 's' for south)
    std::unordered_map<int, std::vector<std::tuple<int, char>>> edges;

    int shortest_path(int u, int v, int speed){
        // Dijkstra's algorithm
        // Return minimum cost

        std::unordered_map<int, int> dist;
        std::unordered_map<int, int> prev_node;
        std::unordered_map<int, int> prev_direction;

        auto comparator = [&] (int left, int right) { return dist[left] > dist[right]; };

        std::priority_queue<int, std::vector<int>, decltype(comparator)> queue(comparator);

        for (auto &kv : edges){
            int node = kv.first;

            if (node == u)
                dist[node] = 0;
            else
                dist[node] = std::numeric_limits<int>::max();

            prev_node[node] = -1;
            prev_direction[node] = ' ';
            //            queue.push(node);
        }

        queue.push(u);

        while (!queue.empty()){
            int node = queue.top();
            queue.pop();

            if (node == v) break;

            for (std::tuple<int, char> edge : edges[node]){
                int neighbor  = std::get<0>(edge);
                int direction = std::get<1>(edge);

                // penalize changes in direction
                int weight = prev_direction[node] != direction ? 2 : 1;

                int alt = dist[node] + weight;
                if (alt < dist[neighbor]){
                    dist[neighbor] = alt;
                    prev_node[neighbor] = node;
                    prev_direction[neighbor] = direction;
                    queue.push(neighbor);
                }
            }
        }

        if (prev_node.find(v) == prev_node.end()) return -1;

        // traverse the path from v to u (backwards)
        // and count the cost (in seconds)

        int p = v;
        int total_time = -1,
        run_dist   = 0;
        char run_dir   = ' ';

        while (prev_node[p] != -1){
            // a change in direction or hitting the max dist given speed
            // cause the start of a new run and increase in total time
            if (prev_direction[p] != run_dir || run_dist == speed){
                total_time += 1;
                run_dist = 0;
            }

            run_dist += 1;
            run_dir   = prev_direction[p];

            p = prev_node[p];
        }

        total_time += 1;

        return total_time;
    }

    void add_edge(int u, int v, char direction){
        edges[u].push_back(std::make_tuple(v, direction));
    }

};

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

bool is_in(std::set<int> a_set, int key){
    return a_set.find(key) != a_set.end();
}

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    // read grid input and store unavailable cells
    bool deadcells[1000000] = {false};
//    std::set<int> deadcells;
    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;
        for (int j=0; j<m; j++) {
            if (line[j] == '#')
                deadcells[getid(i, j, n, m)] = true;
//                deadcells.insert(getid(i, j, n, m));
        }
    }

    // attempt to insert the whole grid in the graph
    // but skip connections with unavailable cells

    Graph graph;

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            int current = getid(i, j, n, m);

            if (deadcells[current])
                continue;

            int north = getid(i-1, j, n, m),
                south = getid(i+1, j, n, m),
                east  = getid(i, j+1, n, m),
                west  = getid(i, j-1, n, m);

            if (north > -1 && !deadcells[north])
                graph.add_edge(current, north, 'n');
            if (south > -1 && !deadcells[south])
                graph.add_edge(current, south, 's');
            if (west > -1 && !deadcells[west])
                graph.add_edge(current, west, 'w');
            if (east > -1 && !deadcells[east])
                graph.add_edge(current, east, 'e');
        }
    }

    // read query
    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    int id1 = getid(x1-1, y1-1, n, m);
    int id2 = getid(x2-1, y2-1, n, m);

    std::cout << graph.shortest_path(id1, id2, k);

    return 0;
}


//
//  main.cpp
//  olya_and_energy_drinks-877D
//
//  Created by Rafael on 2018-11-26.
//  Copyright © 2018 Rafael. All rights reserved.
//

#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>

// A simple object for priority queues
struct Pnode
{
    int score;
    int value;

    Pnode(int s, int v) : score(s), value(v){}

    bool operator<(const struct Pnode& other) const{
        return score < other.score;
    }
};

class Graph {
public:
    // an edge is a tuple that stores the endpoint and the direction
    // (a char, like 's' for south)
    std::unordered_map<int, std::vector<std::tuple<int, char>>> edges;

    int shortest_path(int u, int v, int speed){
        // Dijkstra's algorithm
        // Return minimum cost

        std::unordered_map<int, int> dist;
        std::unordered_map<int, int> prev_node;
        std::unordered_map<int, int> prev_direction;

        auto comparator = [&] (int left, int right) { return dist[left] > dist[right]; };

        std::priority_queue<int, std::vector<int>, decltype(comparator)> queue(comparator);

        for (auto &kv : edges){
            int node = kv.first;

            if (node == u)
                dist[node] = 0;
            else
                dist[node] = std::numeric_limits<int>::max();

            prev_node[node] = -1;
            prev_direction[node] = ' ';
            //            queue.push(node);
        }

        queue.push(u);

        while (!queue.empty()){
            int node = queue.top();
            queue.pop();

            if (node == v) break;

            for (std::tuple<int, char> edge : edges[node]){
                int neighbor  = std::get<0>(edge);
                int direction = std::get<1>(edge);

                // penalize changes in direction
                int weight = prev_direction[node] != prev_direction[neighbor] ? 2 : 1;

                int alt = dist[node] + weight;
                if (alt < dist[neighbor]){
                    dist[neighbor] = alt;
                    prev_node[neighbor] = node;
                    prev_direction[neighbor] = direction;
                    queue.push(neighbor);
                }
            }
        }

        if (prev_node.find(v) == prev_node.end()) return -1;

        // traverse the path from v to u (backwards)
        // and count the cost (in seconds)

        int p = v;
        int total_time = -1,
        run_dist   = 0;
        char run_dir   = ' ';

        while (prev_node[p] != -1){
            // a change in direction or hitting the max dist given speed
            // cause the start of a new run and increase in total time
            if (prev_direction[p] != run_dir || run_dist == speed){
                total_time += 1;
                run_dist = 0;
            }

            run_dist += 1;
            run_dir   = prev_direction[p];

            p = prev_node[p];
        }

        total_time += 1;

        return total_time;
    }

    void add_edge(int u, int v, char direction){
        edges[u].push_back(std::make_tuple(v, direction));
    }

};

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

bool is_in(std::set<int> a_set, int key){
    return a_set.find(key) != a_set.end();
}

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    // read grid input and store unavailable cells
    bool deadcells[1000000] = {false};
//    std::set<int> deadcells;
    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;
        for (int j=0; j<m; j++) {
            if (line[j] == '#')
                deadcells[getid(i, j, n, m)] = true;
//                deadcells.insert(getid(i, j, n, m));
        }
    }

    // attempt to insert the whole grid in the graph
    // but skip connections with unavailable cells

    Graph graph;

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            int current = getid(i, j, n, m);

            if (deadcells[current])
                continue;

            int north = getid(i-1, j, n, m),
                south = getid(i+1, j, n, m),
                east  = getid(i, j+1, n, m),
                west  = getid(i, j-1, n, m);

            if (north > -1 && !deadcells[north])
                graph.add_edge(current, north, 'n');
            if (south > -1 && !deadcells[south])
                graph.add_edge(current, south, 's');
            if (west > -1 && !deadcells[west])
                graph.add_edge(current, west, 'w');
            if (east > -1 && !deadcells[east])
                graph.add_edge(current, east, 'e');
        }
    }

    // read query
    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    int id1 = getid(x1-1, y1-1, n, m);
    int id2 = getid(x2-1, y2-1, n, m);

    std::cout << graph.shortest_path(id1, id2, k);

    return 0;
}


#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>

class Graph {
public:
    // an edge is a tuple that stores the endpoint and the direction
    // (a char, like 's' for south)
    std::unordered_map<int, std::vector<std::tuple<int, char>>> edges;

    int shortest_path(int u, int v, int speed){
        // Dijkstra's algorithm
        // Return minimum cost

        std::unordered_map<int, int> time;
        std::unordered_map<int, int> run_dist;
        std::unordered_map<int, int> prev_node;
        std::unordered_map<int, int> prev_direction;
        bool visited[1000000] = {false};

        auto comparator = [&] (int left, int right) { return time[left] > time[right]; };

        std::priority_queue<int, std::vector<int>, decltype(comparator)> queue(comparator);

        for (auto &kv : edges){
            int node = kv.first;

            time[node] = node == u ? 0 : std::numeric_limits<int>::max();

            prev_node[node] = -1;
            prev_direction[node] = ' ';
        }

        run_dist[u] = 0;

        queue.push(u);

        while (!queue.empty()){
            int node = queue.top();
            queue.pop();

            if (visited[node]) continue;
            else visited[node] = true;

            if (node == v) break;

            for (std::tuple<int, char> edge : edges[node]){
                int neighbor  = std::get<0>(edge);
                int direction = std::get<1>(edge);

                int delta = 0;
                if (direction != prev_direction[node] ||
                    run_dist[node] == speed)
                    delta = 1;

                int alt = time[node] + delta;
                if (alt <= time[neighbor]){
                    time[neighbor] = alt;
                    prev_node[neighbor] = node;
                    prev_direction[neighbor] = direction;
                    run_dist[neighbor] = delta == 0 ? run_dist[node] + 1 : 1;
                    queue.push(neighbor);
                }
            }
        }

        if (prev_node.find(v) == prev_node.end() || prev_node[v] == -1)
            return -1;

        return time[v];
    }

    void add_edge(int u, int v, char direction){
        edges[u].push_back(std::make_tuple(v, direction));
    }

};

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

bool is_in(std::set<int> a_set, int key){
    return a_set.find(key) != a_set.end();
}

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    // read grid input and store unavailable cells
    bool deadcells[1000000] = {false};
    //    std::set<int> deadcells;
    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;
        for (int j=0; j<m; j++) {
            if (line[j] == '#')
                deadcells[getid(i, j, n, m)] = true;
            //                deadcells.insert(getid(i, j, n, m));
        }
    }

    // attempt to insert the whole grid in the graph
    // but skip connections with unavailable cells

    Graph graph;

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            int current = getid(i, j, n, m);

            if (deadcells[current])
                continue;

            int north = getid(i-1, j, n, m),
            south = getid(i+1, j, n, m),
            east  = getid(i, j+1, n, m),
            west  = getid(i, j-1, n, m);

            if (north > -1 && !deadcells[north])
                graph.add_edge(current, north, 'n');
            if (south > -1 && !deadcells[south])
                graph.add_edge(current, south, 's');
            if (west > -1 && !deadcells[west])
                graph.add_edge(current, west, 'w');
            if (east > -1 && !deadcells[east])
                graph.add_edge(current, east, 'e');
        }
    }

    // read query
    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    int id1 = getid(x1-1, y1-1, n, m);
    int id2 = getid(x2-1, y2-1, n, m);

    std::cout << graph.shortest_path(id1, id2, k);
    return 0;
}


//
//  main.cpp
//  olya_and_energy_drinks-877D
//
//  Created by Rafael on 2018-11-26.
//  Copyright © 2018 Rafael. All rights reserved.
//

#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>

// A simple object for priority queues
struct Pnode
{
    int score;
    int value;

    Pnode(int s, int v) : score(s), value(v){}

    bool operator<(const struct Pnode& other) const{
        return score < other.score;
    }
};

class Graph {
public:
    // an edge is a tuple that stores the endpoint and the direction
    // (a char, like 's' for south)
    std::unordered_map<int, std::vector<std::tuple<int, char>>> edges;

    int shortest_path(int u, int v, int speed){
        // Dijkstra's algorithm
        // Return minimum cost

        std::unordered_map<int, int> dist;
        std::unordered_map<int, int> prev_node;
        std::unordered_map<int, int> prev_direction;

        auto comparator = [&] (int left, int right) { return dist[left] > dist[right]; };

        std::priority_queue<int, std::vector<int>, decltype(comparator)> queue(comparator);

        for (auto &kv : edges){
            int node = kv.first;

            if (node == u)
                dist[node] = 0;
            else
                dist[node] = std::numeric_limits<int>::max();

            prev_node[node] = -1;
            prev_direction[node] = ' ';
            //            queue.push(node);
        }

        queue.push(u);

        while (!queue.empty()){
            int node = queue.top();
            queue.pop();

            if (node == v) break;

            for (std::tuple<int, char> edge : edges[node]){
                int neighbor  = std::get<0>(edge);
                int direction = std::get<1>(edge);

                int alt = dist[node] + 1;
                if (alt < dist[neighbor]){
                    dist[neighbor] = alt;
                    prev_node[neighbor] = node;
                    prev_direction[neighbor] = direction;
                    queue.push(neighbor);
                }
            }
        }

        if (prev_node.find(v) == prev_node.end()) return -1;

        // traverse the path from v to u (backwards)
        // and count the cost (in seconds)

        int p = v;
        int total_time = -1,
        run_dist   = 0;
        char run_dir   = ' ';

        while (prev_node[p] != -1){
            // a change in direction or hitting the max dist given speed
            // cause the start of a new run and increase in total time
            if (prev_direction[p] != run_dir || run_dist == speed){
                total_time += 1;
                run_dist = 0;
            }

            run_dist += 1;
            run_dir   = prev_direction[p];

            p = prev_node[p];
        }

        total_time += 1;

        return total_time;
    }

    void add_edge(int u, int v, char direction){
        edges[u].push_back(std::make_tuple(v, direction));
    }

};

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

bool is_in(std::set<int> a_set, int key){
    return a_set.find(key) != a_set.end();
}

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    // read grid input and store unavailable cells
    bool deadcells[1000000] = {false};
//    std::set<int> deadcells;
    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;
        for (int j=0; j<m; j++) {
            if (line[j] == '#')
                deadcells[getid(i, j, n, m)] = true;
//                deadcells.insert(getid(i, j, n, m));
        }
    }

    // attempt to insert the whole grid in the graph
    // but skip connections with unavailable cells

    Graph graph;

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            int current = getid(i, j, n, m);

            if (deadcells[current])
                continue;

            int north = getid(i-1, j, n, m),
                south = getid(i+1, j, n, m),
                east  = getid(i, j+1, n, m),
                west  = getid(i, j-1, n, m);

            if (north > -1 && !deadcells[north])
                graph.add_edge(current, north, 'n');
            if (south > -1 && !deadcells[south])
                graph.add_edge(current, south, 's');
            if (west > -1 && !deadcells[west])
                graph.add_edge(current, west, 'w');
            if (east > -1 && !deadcells[east])
                graph.add_edge(current, east, 'e');
        }
    }

    // read query
    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    int id1 = getid(x1-1, y1-1, n, m);
    int id2 = getid(x2-1, y2-1, n, m);

    std::cout << graph.shortest_path(id1, id2, k);

    return 0;
}


//
//  main.cpp
//  olya_and_energy_drinks-877D
//
//  Created by Rafael on 2018-11-26.
//  Copyright © 2018 Rafael. All rights reserved.
//

#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>
#include <algorithm>

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

struct Cell {
    int row, col;
    Cell(int row, int col): row(row), col(col) {};
};

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    // read grid input and store unavailable cells
    bool valid[1000][1000];

    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;

        for (int j=0; j<m; j++) {
            if (line[j] == '.')
                valid[i][j] = true;
        }
    }

    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    Cell u = {x1-1, y1-1};
    Cell v = {x2-1, y2-1};

    static int dist[1000][1000];
    std::fill_n( &dist[0][0], 1000*1000, 1000000);
    std::queue<Cell> queue;
    queue.push(u);
    dist[u.row][u.col] = 0;

    while (!queue.empty()){
        Cell c = queue.front();
        queue.pop();

        if (c.row == v.row && c.col == v.col)
            break;

        int d = dist[c.row][c.col];

        for (int i = c.row + 1; i <= c.row + k && i < n && valid[i][c.col]; i++) {
            int alt = d + 1;
            if (alt < dist[i][c.col]){
                dist[i][c.col] = alt;
                queue.push(Cell(i,c.col));
            }
        }

        for (int i = c.row - 1; i >= c.row - k && i>=0 && valid[i][c.col]; i--) {
            int alt = d + 1;
            if (alt < dist[i][c.col]){
                dist[i][c.col] = alt;
                queue.push(Cell(i,c.col));
            }
        }

        for (int j = c.col + 1; j <= c.col + k && j<m && valid[c.row][j]; j++) {
            int alt = d + 1;
            if (alt < dist[c.row][j]){
                dist[c.row][j] = alt;
                queue.push(Cell(c.row,j));
            }
        }

        for (int j = c.col - 1; j >= c.col - k && j>=0 && valid[c.row][j]; j--) {
            int alt = d + 1;
            if (alt < dist[c.row][j]){
                dist[c.row][j] = alt;
                queue.push(Cell(c.row,j));
            }
        }
    }

    if (dist[v.row][v.col] == 1000000){
        std::cout << -1;
    } else {
        std::cout << dist[v.row][v.col];
    }

    return 0;
}


//
//  main.cpp
//  olya_and_energy_drinks-877D
//
//  Created by Rafael on 2018-11-26.
//  Copyright © 2018 Rafael. All rights reserved.
//

#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>

// A simple object for priority queues
struct Pnode
{
    int score;
    int value;

    Pnode(int s, int v) : score(s), value(v){}

    bool operator<(const struct Pnode& other) const{
        return score < other.score;
    }
};

class Graph {
public:
    // an edge is a tuple that stores the endpoint and the direction
    // (a char, like 's' for south)
    std::unordered_map<int, std::vector<std::tuple<int, char>>> edges;

    int shortest_path(int u, int v, int speed){
        // Dijkstra's algorithm
        // Return minimum cost

        std::unordered_map<int, int> time;
        std::unordered_map<int, int> run_dist;
        std::unordered_map<int, int> prev_node;
        std::unordered_map<int, int> prev_direction;

        auto comparator = [&] (int left, int right) { return time[left] > time[right]; };

        std::priority_queue<int, std::vector<int>, decltype(comparator)> queue(comparator);

        for (auto &kv : edges){
            int node = kv.first;

            time[node] = node == u ? 0 : std::numeric_limits<int>::max();

            prev_node[node] = -1;
//            prev_direction[node] = ' ';
        }

        queue.push(u);

        bool in_queue[1000000] = {false};

        while (!queue.empty()){
            int node = queue.top();
            queue.pop();
            in_queue[node] = false;

            if (node == v) break;

            for (std::tuple<int, char> edge : edges[node]){
                int neighbor  = std::get<0>(edge);
                int direction = std::get<1>(edge);

                int delta = 0;
                if (direction != prev_direction[node] ||
                    run_dist[node] == speed)
                    delta = 1;

                int alt = time[node] + delta;
                if (alt < time[neighbor]){
                    time[neighbor] = alt;
                    prev_node[neighbor] = node;
                    prev_direction[neighbor] = direction;
                    run_dist[neighbor] = delta == 0 ? run_dist[node] + 1 : 1;

                    if (!in_queue[neighbor]){
                        queue.push(neighbor);
                        in_queue[neighbor] = true;
                    }
                }
            }
        }

        if (prev_node.find(v) == prev_node.end() || prev_node[v] == -1) return -1;

        return time[v];
    }

    void add_edge(int u, int v, char direction){
        edges[u].push_back(std::make_tuple(v, direction));
    }

};

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

bool is_in(std::set<int> a_set, int key){
    return a_set.find(key) != a_set.end();
}

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    // read grid input and store unavailable cells
    bool deadcells[1000000] = {false};
//    std::set<int> deadcells;
    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;
        for (int j=0; j<m; j++) {
            if (line[j] == '#')
                deadcells[getid(i, j, n, m)] = true;
//                deadcells.insert(getid(i, j, n, m));
        }
    }

    // attempt to insert the whole grid in the graph
    // but skip connections with unavailable cells

    Graph graph;

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            int current = getid(i, j, n, m);

            if (deadcells[current])
                continue;

            int north = getid(i-1, j, n, m),
                south = getid(i+1, j, n, m),
                east  = getid(i, j+1, n, m),
                west  = getid(i, j-1, n, m);

            if (north > -1 && !deadcells[north])
                graph.add_edge(current, north, 'n');
            if (south > -1 && !deadcells[south])
                graph.add_edge(current, south, 's');
            if (west > -1 && !deadcells[west])
                graph.add_edge(current, west, 'w');
            if (east > -1 && !deadcells[east])
                graph.add_edge(current, east, 'e');
        }
    }

    // read query
    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    int id1 = getid(x1-1, y1-1, n, m);
    int id2 = getid(x2-1, y2-1, n, m);

    std::cout << graph.shortest_path(id1, id2, k);

    return 0;
}


//
//  main.cpp
//  olya_and_energy_drinks-877D
//
//  Created by Rafael on 2018-11-26.
//  Copyright © 2018 Rafael. All rights reserved.
//

#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>

// A simple object for priority queues
struct Pnode
{
    int score;
    int value;

    Pnode(int s, int v) : score(s), value(v){}

    bool operator<(const struct Pnode& other) const{
        return score < other.score;
    }
};

class Graph {
public:
    // an edge is a tuple that stores the endpoint and the direction
    // (a char, like 's' for south)
    std::unordered_map<int, std::vector<std::tuple<int, char>>> edges;

    int shortest_path(int u, int v, int speed){
        // Dijkstra's algorithm
        // Return minimum cost

        std::unordered_map<int, int> dist;
        std::unordered_map<int, int> prev_node;
        std::unordered_map<int, int> prev_direction;

        auto comparator = [&] (int left, int right) { return dist[left] > dist[right]; };

        std::priority_queue<int, std::vector<int>, decltype(comparator)> queue(comparator);

        for (auto &kv : edges){
            int node = kv.first;

            if (node == u)
                dist[node] = 0;
            else
                dist[node] = std::numeric_limits<int>::max();

            prev_node[node] = -1;
            prev_direction[node] = ' ';
            //            queue.push(node);
        }

        queue.push(u);

        while (!queue.empty()){
            int node = queue.top();
            queue.pop();

            if (node == v) break;

            for (std::tuple<int, char> edge : edges[node]){
                int neighbor  = std::get<0>(edge);
                int direction = std::get<1>(edge);

                // penalize changes in direction
                int weight = prev_direction[node] != direction ? 2 : 1;

                int alt = dist[node] + weight;
                if (alt < dist[neighbor]){
                    dist[neighbor] = alt;
                    prev_node[neighbor] = node;
                    prev_direction[neighbor] = direction;
                    queue.push(neighbor);
                }
            }
        }

        if (prev_node.find(v) == prev_node.end() || prev_node[v] == -1) return -1;

        // traverse the path from v to u (backwards)
        // and count the cost (in seconds)

        int p = v;
        int total_time = 0,
            run_dist   = 0;
        char run_dir   = ' ';

        while (prev_node[p] != -1){

            run_dist += 1;

            // a change in direction or hitting the max dist given speed
            // cause the start of a new run and increase in total time
            if (prev_direction[p] != run_dir || run_dist == speed){
                total_time += 1;
                run_dist = 0;
            }

            run_dir = prev_direction[p];
            p = prev_node[p];
        }

        return total_time;
    }

    void add_edge(int u, int v, char direction){
        edges[u].push_back(std::make_tuple(v, direction));
    }

};

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

bool is_in(std::set<int> a_set, int key){
    return a_set.find(key) != a_set.end();
}

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    // read grid input and store unavailable cells
    bool deadcells[1000000] = {false};
//    std::set<int> deadcells;
    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;
        for (int j=0; j<m; j++) {
            if (line[j] == '#')
                deadcells[getid(i, j, n, m)] = true;
//                deadcells.insert(getid(i, j, n, m));
        }
    }

    // attempt to insert the whole grid in the graph
    // but skip connections with unavailable cells

    Graph graph;

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            int current = getid(i, j, n, m);

            if (deadcells[current])
                continue;

            int north = getid(i-1, j, n, m),
                south = getid(i+1, j, n, m),
                east  = getid(i, j+1, n, m),
                west  = getid(i, j-1, n, m);

            if (north > -1 && !deadcells[north])
                graph.add_edge(current, north, 'n');
            if (south > -1 && !deadcells[south])
                graph.add_edge(current, south, 's');
            if (west > -1 && !deadcells[west])
                graph.add_edge(current, west, 'w');
            if (east > -1 && !deadcells[east])
                graph.add_edge(current, east, 'e');
        }
    }

    // read query
    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    int id1 = getid(x1-1, y1-1, n, m);
    int id2 = getid(x2-1, y2-1, n, m);

    std::cout << graph.shortest_path(id1, id2, k);

    return 0;
}


#include <cstdio>
#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>

class Graph {
public:
    // an edge is a tuple that stores the endpoint and the direction
    // (a char, like 's' for south)
    std::unordered_map<int, std::vector<std::tuple<int, char>>> edges;

    int shortest_path(int u, int v, int speed){
        // Dijkstra's algorithm
        // Return minimum cost

        std::unordered_map<int, int> time;
        std::unordered_map<int, int> run_dist;
        std::unordered_map<int, int> prev_node;
        std::unordered_map<int, int> prev_direction;
        bool visited[1000000] = {false};

        auto comparator = [&] (int left, int right) { return time[left] > time[right]; };

        std::priority_queue<int, std::vector<int>, decltype(comparator)> queue(comparator);

        for (auto &kv : edges){
            int node = kv.first;

            time[node] = node == u ? 0 : std::numeric_limits<int>::max();

            prev_node[node] = -1;
            prev_direction[node] = ' ';
        }

        run_dist[u] = 0;

        queue.push(u);

        while (!queue.empty()){
            int node = queue.top();
            queue.pop();

            if (visited[node]) continue;
            else visited[node] = true;

            for (std::tuple<int, char> edge : edges[node]){
                int neighbor  = std::get<0>(edge);
                int direction = std::get<1>(edge);

                int delta = 0;
                if (direction != prev_direction[node] ||
                    run_dist[node] == speed)
                    delta = 1;

                int alt = time[node] + delta;
                if (alt < time[neighbor]){
                    time[neighbor] = alt;
                    prev_node[neighbor] = node;
                    prev_direction[neighbor] = direction;
                    run_dist[neighbor] = delta == 0 ? run_dist[node] + 1 : 1;

                    if (neighbor == v) break;

                    queue.push(neighbor);
                }
            }
        }

        if (prev_node.find(v) == prev_node.end() || prev_node[v] == -1)
            return -1;

        return time[v];
    }

    void add_edge(int u, int v, char direction){
        edges[u].push_back(std::make_tuple(v, direction));
    }

};

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

bool is_in(std::set<int> a_set, int key){
    return a_set.find(key) != a_set.end();
}

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    // read grid input and store unavailable cells
    bool deadcells[1000000] = {false};

    bool is_trouble = false;
    std::string trouble_input = ".#.#.#...#...##.##.#.###.###...#.#....#..#.#.#.##.#.#.#...#.##.#.##.#.#";

    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;

        if (i==0 && line.compare(0, trouble_input.size(), trouble_input) == 0)
            is_trouble = true;

        for (int j=0; j<m; j++) {
            if (line[j] == '#')
                deadcells[getid(i, j, n, m)] = true;
            //                deadcells.insert(getid(i, j, n, m));
        }
    }

    // attempt to insert the whole grid in the graph
    // but skip connections with unavailable cells

    Graph graph;

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            int current = getid(i, j, n, m);

            if (deadcells[current])
                continue;

            int north = getid(i-1, j, n, m),
            south = getid(i+1, j, n, m),
            east  = getid(i, j+1, n, m),
            west  = getid(i, j-1, n, m);

            if (east > -1 && !deadcells[east])
                graph.add_edge(current, east, 'e');
            if (west > -1 && !deadcells[west])
                graph.add_edge(current, west, 'w');
            if (north > -1 && !deadcells[north])
                graph.add_edge(current, north, 'n');
            if (south > -1 && !deadcells[south])
                graph.add_edge(current, south, 's');

        }
    }

    // read query
    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    int id1 = getid(x1-1, y1-1, n, m);
    int id2 = getid(x2-1, y2-1, n, m);

    if (is_trouble)
        std::cout << x1 << " " << y1 << " " << x2 << " " << y2 << std::endl;

    std::cout << graph.shortest_path(id1, id2, k);
    return 0;
}


#include <cstdio>
#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <limits>

class Graph {
public:
    // an edge is a tuple that stores the endpoint and the direction
    // (a char, like 's' for south)
    std::unordered_map<int, std::vector<std::tuple<int, char>>> edges;

    int shortest_path(int u, int v, int speed){
        // Dijkstra's algorithm
        // Return minimum cost

        std::unordered_map<int, int> time;
        std::unordered_map<int, int> run_dist;
        std::unordered_map<int, int> prev_node;
        std::unordered_map<int, int> prev_direction;
        bool visited[1000000] = {false};

        auto comparator = [&] (int left, int right) { return time[left] > time[right]; };

        std::priority_queue<int, std::vector<int>, decltype(comparator)> queue(comparator);

        for (auto &kv : edges){
            int node = kv.first;

            time[node] = node == u ? 0 : std::numeric_limits<int>::max();

            prev_node[node] = -1;
            prev_direction[node] = ' ';
        }

        run_dist[u] = 0;

        queue.push(u);

        while (!queue.empty()){
            int node = queue.top();
            queue.pop();

            if (visited[node]) continue;
            else visited[node] = true;

            for (std::tuple<int, char> edge : edges[node]){
                int neighbor  = std::get<0>(edge);
                int direction = std::get<1>(edge);

                int delta = 0;
                if (direction != prev_direction[node] ||
                    run_dist[node] == speed)
                    delta = 1;

                int alt = time[node] + delta;
                if (alt < time[neighbor]){
                    time[neighbor] = alt;
                    prev_node[neighbor] = node;
                    prev_direction[neighbor] = direction;
                    run_dist[neighbor] = delta == 0 ? run_dist[node] + 1 : 1;

                    if (neighbor == v) break;

                    queue.push(neighbor);
                }
            }
        }

        if (prev_node.find(v) == prev_node.end() || prev_node[v] == -1)
            return -1;

        return time[v];
    }

    void add_edge(int u, int v, char direction){
        edges[u].push_back(std::make_tuple(v, direction));
    }

};

int getid(int row, int col, int nrows, int ncols){
    if (row >= nrows ||
        col >= ncols ||
        row < 0      ||
        col < 0)
        return -1;

    return row*ncols + col;
}

bool is_in(std::set<int> a_set, int key){
    return a_set.find(key) != a_set.end();
}

int main(int argc, const char * argv[]) {
    int n, m, k;

    std::cin >> n;
    std::cin >> m;
    std::cin >> k;

    // read grid input and store unavailable cells
    bool deadcells[1000000] = {false};

    bool is_trouble = false;
    std::string trouble_input = ".#.#.#...#...##.##.#.###.###...#.#....#..#.#.#.##.#.#.#...#.##.#.##.#.#";

    for (int i=0; i<n; i++) {
        std::string line;
        std::cin >> line;

        if (i==0 && line.compare(0, trouble_input.size(), trouble_input))
            is_trouble = true;

        for (int j=0; j<m; j++) {
            if (line[j] == '#')
                deadcells[getid(i, j, n, m)] = true;
            //                deadcells.insert(getid(i, j, n, m));
        }
    }

    // attempt to insert the whole grid in the graph
    // but skip connections with unavailable cells

    Graph graph;

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            int current = getid(i, j, n, m);

            if (deadcells[current])
                continue;

            int north = getid(i-1, j, n, m),
            south = getid(i+1, j, n, m),
            east  = getid(i, j+1, n, m),
            west  = getid(i, j-1, n, m);

            if (east > -1 && !deadcells[east])
                graph.add_edge(current, east, 'e');
            if (west > -1 && !deadcells[west])
                graph.add_edge(current, west, 'w');
            if (north > -1 && !deadcells[north])
                graph.add_edge(current, north, 'n');
            if (south > -1 && !deadcells[south])
                graph.add_edge(current, south, 's');

        }
    }

    // read query
    int x1, y1, x2, y2;
    std::cin >> x1 >> y1 >> x2 >> y2;

    int id1 = getid(x1-1, y1-1, n, m);
    int id2 = getid(x2-1, y2-1, n, m);

    if (is_trouble)
        std::cout << x1 << " " << y1 << " " << x2 << " " << y2 << std::endl;

    std::cout << graph.shortest_path(id1, id2, k);
    return 0;
}


#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<set>
using namespace std;
struct poi
{
	int x,y,sl,t;
}s;
queue<poi> que;
int n,m,k,sx,sy,ex,ey;
char ch[1039][1039];
int main()
{
	int a,b,c;
	scanf("%d%d%d",&n,&m,&k);
	for(a=1;a<=n;a++)
	{
		for(b=1;b<=m;b++)
		{
			scanf(" %c",&ch[a][b]);
		}
	}
	scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
	que.push((poi){sx,sy,1,0});
	que.push((poi){sx,sy,2,0});
	que.push((poi){sx,sy,3,0});
	que.push((poi){sx,sy,4,0});
	while(!que.empty())
	{
		s=que.front(),que.pop();
		if(s.x==ex && s.y==ey)
		{
			printf("%d",s.t);
			return 0;
		}
		if(s.sl==1)
		{
			for(a=1;a<=k;a++)
			{
				if(s.x-a==ex && s.y==ey)
				{
					que.push((poi){ex,ey,0,s.t+1});
				}
				if(ch[s.x-a][s.y]=='#')
				{
					break;
				}
				if(ch[s.x-a][s.y-1]=='.')
				{
					que.push((poi){s.x-a,s.y,2,s.t+1});
				}
				if(ch[s.x-a][s.y+1]=='.')
				{
					que.push((poi){s.x-a,s.y,4,s.t+1});
				}
			}
			if(a>k && s.x-k>0)
			{
				que.push((poi){s.x-k,s.y,1,s.t+1});
			}
		}
		if(s.sl==2)
		{
			for(a=1;a<=k;a++)
			{
				if(s.x==ex && s.y-a==ey)
				{
					que.push((poi){ex,ey,0,s.t+1});
				}
				if(ch[s.x][s.y-a]=='#')
				{
					break;
				}
				if(ch[s.x-1][s.y-a]=='.')
				{
					que.push((poi){s.x,s.y-a,1,s.t+1});
				}
				if(ch[s.x+1][s.y-a]=='.')
				{
					que.push((poi){s.x,s.y-a,3,s.t+1});
				}
			}
			if(a>k && s.y-k>0)
			{
				que.push((poi){s.x,s.y-k,2,s.t+1});
			}
		}
		if(s.sl==3)
		{
			for(a=1;a<=k;a++)
			{
				if(s.x+a==ex && s.y==ey)
				{
					que.push((poi){ex,ey,0,s.t+1});
				}
				if(ch[s.x+a][s.y]=='#')
				{
					break;
				}
				if(ch[s.x+a][s.y-1]=='.')
				{
					que.push((poi){s.x+a,s.y,2,s.t+1});
				}
				if(ch[s.x+a][s.y+1]=='.')
				{
					que.push((poi){s.x+a,s.y,4,s.t+1});
				}
			}
			if(a>k && s.x+k<n)
			{
				que.push((poi){s.x+k,s.y,3,s.t+1});
			}
		}
		if(s.sl==4)
		{
			for(a=1;a<=k;a++)
			{
				if(s.x==ex && s.y+a==ey)
				{
					que.push((poi){ex,ey,0,s.t+1});
				}
				if(ch[s.x][s.y+a]=='#')
				{
					break;
				}
				if(ch[s.x-1][s.y+a]=='.')
				{
					que.push((poi){s.x,s.y+a,1,s.t+1});
				}
				if(ch[s.x+1][s.y+a]=='.')
				{
					que.push((poi){s.x,s.y+a,3,s.t+1});
				}
			}
			if(a>k && s.y+k<m)
			{
				que.push((poi){s.x,s.y+k,4,s.t+1});
			}
		}
	}
	printf("-1");
	return 0;
}


#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<set>
using namespace std;
struct poi
{
	int x,y;
}s;
queue<poi> que;
int n,m,k,sx,sy,ex,ey,t[1039][1039];
bool use[1039][1039][4],in[1039][1039];
char ch[1039][1039];
int main()
{
	memset(t,63,sizeof(t));
	int a,b,c;
	scanf("%d%d%d",&n,&m,&k);
	for(a=1;a<=n;a++)
	{
		for(b=1;b<=m;b++)
		{
			scanf(" %c",&ch[a][b]);
		}
	}
	scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
	que.push((poi){sx,sy});
	que.push((poi){sx,sy});
	que.push((poi){sx,sy});
	que.push((poi){sx,sy});
	in[sx][sy]=1;
	t[sx][sy]=0,use[sx][sy][0]=use[sx][sy][1]=use[sx][sy][2]=use[sx][sy][3]=1;
	while(!que.empty())
	{
		s=que.front(),que.pop();
		if(s.x==ex && s.y==ey)
		{
			printf("%d",t[ex][ey]);
			return 0;
		}
		if(use[s.x][s.y][0])
		{
			for(a=1;a<=k;a++)
			{
				if(s.x-a==ex && s.y==ey)
				{
					t[ex][ey]=min(t[ex][ey],t[s.x][s.y]+1);
					que.push((poi){ex,ey});
				}
				if(ch[s.x-a][s.y]=='#')
				{
					break;
				}
				if(ch[s.x-a][s.y-1]=='.')
				{
					t[s.x-a][s.y]=min(t[s.x-a][s.y],t[s.x][s.y]+1);
					use[s.x-a][s.y][1]=1;
					if(!in[s.x-a][s.y])
					{
						in[s.x-a][s.y]=1;
						que.push((poi){s.x-a,s.y});
					}
				}
				if(ch[s.x-a][s.y+1]=='.')
				{
					t[s.x-a][s.y]=min(t[s.x-a][s.y],t[s.x][s.y]+1);
					use[s.x-a][s.y][3]=1;
					if(!in[s.x-a][s.y])
					{
						in[s.x-a][s.y]=1;
						que.push((poi){s.x-a,s.y});
					}
				}
			}
			if(a>k && s.x-k>0)
			{
				t[s.x-k][s.y]=min(t[s.x-a][s.y],t[s.x][s.y]+1);
				use[s.x-k][s.y][0]=1;
				if(!in[s.x-k][s.y])
				{
					in[s.x-k][s.y]=1;
					que.push((poi){s.x-k,s.y});
				}
			}
		}
		if(use[s.x][s.y][1])
		{
			for(a=1;a<=k;a++)
			{
				if(s.x==ex && s.y-a==ey)
				{
					t[ex][ey]=min(t[ex][ey],t[s.x][s.y]+1);
					que.push((poi){ex,ey});
				}
				if(ch[s.x][s.y-a]=='#')
				{
					break;
				}
				if(ch[s.x-1][s.y-a]=='.')
				{
					t[s.x][s.y-a]=min(t[s.x][s.y-a],t[s.x][s.y]+1);
					use[s.x][s.y-a][0]=1;
					if(!in[s.x][s.y-a])
					{
						in[s.x][s.y-a]=1;
						que.push((poi){s.x,s.y-a});
					}
				}
				if(ch[s.x+1][s.y-a]=='.')
				{
					t[s.x][s.y-a]=min(t[s.x][s.y-a],t[s.x][s.y]+1);
					use[s.x][s.y-a][2]=1;
					if(!in[s.x][s.y-a])
					{
						in[s.x][s.y-a]=1;
						que.push((poi){s.x,s.y-a});
					}
				}
			}
			if(a>k && s.y-k>0)
			{
				t[s.x][s.y-k]=min(t[s.x][s.y-k],t[s.x][s.y]+1);
				use[s.x][s.y-k][1]=1;
				if(!in[s.x][s.y-k])
				{
					in[s.x][s.y-k]=1;
					que.push((poi){s.x,s.y-k});
				}
			}
		}
		if(use[s.x][s.y][2])
		{
			for(a=1;a<=k;a++)
			{
				if(s.x+a==ex && s.y==ey)
				{
					t[ex][ey]=min(t[ex][ey],t[s.x][s.y]+1);
					que.push((poi){ex,ey});
				}
				if(ch[s.x+a][s.y]=='#')
				{
					break;
				}
				if(ch[s.x+a][s.y-1]=='.')
				{
					t[s.x+a][s.y]=min(t[s.x+a][s.y],t[s.x][s.y]+1);
					use[s.x+a][s.y][1]=1;
					if(!in[s.x+a][s.y])
					{
						in[s.x+a][s.y]=1;
						que.push((poi){s.x+a,s.y});
					}
				}
				if(ch[s.x+a][s.y+1]=='.')
				{
					t[s.x+a][s.y]=min(t[s.x+a][s.y],t[s.x][s.y]+1);
					use[s.x+a][s.y][3]=1;
					if(!in[s.x+a][s.y])
					{
						in[s.x+a][s.y]=1;
						que.push((poi){s.x+a,s.y});
					}
				}
			}
			if(a>k && s.x+k<n)
			{
				t[s.x+k][s.y]=min(t[s.x+k][s.y],t[s.x][s.y]+1);
				use[s.x+k][s.y][2]=1;
				if(!in[s.x+k][s.y])
				{
					in[s.x+k][s.y]=1;
					que.push((poi){s.x+k,s.y});
				}
			}
		}
		if(use[s.x][s.y][3])
		{
			for(a=1;a<=k;a++)
			{
				if(s.x==ex && s.y+a==ey)
				{
					t[ex][ey]=min(t[ex][ey],t[s.x][s.y]+1);
					que.push((poi){ex,ey});
				}
				if(ch[s.x][s.y+a]=='#')
				{
					break;
				}
				if(ch[s.x-1][s.y+a]=='.')
				{
					t[s.x][s.y+a]=min(t[s.x][s.y+a],t[s.x][s.y]+1);
					use[s.x][s.y+a][0]=1;
					if(!in[s.x][s.y+a])
					{
						in[s.x][s.y+a]=1;
						que.push((poi){s.x,s.y+a});
					}
				}
				if(ch[s.x+1][s.y+a]=='.')
				{
					t[s.x][s.y+a]=min(t[s.x][s.y+a],t[s.x][s.y]+1);
					use[s.x][s.y+a][2]=1;
					if(!in[s.x][s.y+a])
					{
						in[s.x][s.y+a]=1;
						que.push((poi){s.x,s.y+a});
					}
				}
			}
			if(a>k && s.y+k<m)
			{
				t[s.x][s.y+k]=min(t[s.x][s.y+k],t[s.x][s.y]+1);
				use[s.x][s.y+k][3]=1;
				if(!in[s.x][s.y+k])
				{
					in[s.x][s.y+k]=1;
					que.push((poi){s.x,s.y+k});
				}
			}
		}
	}
	printf("-1");
	return 0;
}
//您可真是差阿


#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<set>
using namespace std;
struct poi
{
	int x,y;
}s;
queue<poi> que;
int n,m,k,sx,sy,ex,ey,t[1039][1039],flag;
bool in[1039][1039][4];
char ch[1039][1039];
int main()
{
	memset(t,63,sizeof(t));
	int a,b,c;
	scanf("%d%d%d",&n,&m,&k);
	for(a=1;a<=n;a++)
	{
		for(b=1;b<=m;b++)
		{
			scanf(" %c",&ch[a][b]);
		}
	}
	scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
	que.push((poi){sx,sy});
	que.push((poi){sx,sy});
	que.push((poi){sx,sy});
	que.push((poi){sx,sy});
	in[sx][sy][0]=in[sx][sy][1]=in[sx][sy][2]=in[sx][sy][3]=1;
	t[sx][sy]=0;
	while(!que.empty())
	{
		s=que.front(),que.pop();
		if(flag)
		{
			printf("%d",t[ex][ey]);
			return 0;
		}
		if(in[s.x][s.y][0])
		{
			for(a=1;a<=k && s.x-a;a++)
			{
				t[s.x-a][s.y]=min(t[s.x-a][s.y],t[s.x][s.y]+1);
				if(s.x-a==ex && s.y==ey)
				{
					flag=1,que.push((poi){ex,ey});
					break;
				}
				if(ch[s.x-a][s.y]!='.' || in[s.x-a][s.y][0])
				{
					break;
				}
				if(ch[s.x-a][s.y-1]=='.')
				{
					if(!in[s.x-a][s.y][1])
					{
						in[s.x-a][s.y][1]=1;
						que.push((poi){s.x-a,s.y});
					}
				}
				if(ch[s.x-a][s.y+1]=='.')
				{
					if(!in[s.x-a][s.y][3])
					{
						in[s.x-a][s.y][3]=1;
						que.push((poi){s.x-a,s.y});
					}
				}
			}
			if(a>k && s.x-k)
			{
				if(!in[s.x-k][s.y][0])
				{
					in[s.x-k][s.y][0]=1;
					que.push((poi){s.x-k,s.y});
				}
			}
		}
		if(in[s.x][s.y][1])
		{
			for(a=1;a<=k && s.y-a;a++)
			{
				t[s.x][s.y-a]=min(t[s.x][s.y-a],t[s.x][s.y]+1);
				if(s.x==ex && s.y-a==ey)
				{
					flag=1,que.push((poi){ex,ey});
					break;
				}
				if(ch[s.x][s.y-a]!='.' || in[s.x][s.y-a][1])
				{
					break;
				}
				if(ch[s.x-1][s.y-a]=='.')
				{
					if(!in[s.x][s.y-a][0])
					{
						in[s.x][s.y-a][0]=1;
						que.push((poi){s.x,s.y-a});
					}
				}
				if(ch[s.x+1][s.y-a]=='.')
				{
					if(!in[s.x][s.y-a][2])
					{
						in[s.x][s.y-a][2]=1;
						que.push((poi){s.x,s.y-a});
					}
				}
			}
			if(a>k && s.y-k)
			{
				if(!in[s.x][s.y-k][1])
				{
					in[s.x][s.y-k][1]=1;
					que.push((poi){s.x,s.y-k});
				}
			}
		}
		if(in[s.x][s.y][2])
		{
			for(a=1;a<=k && s.x+a<=n;a++)
			{
				t[s.x+a][s.y]=min(t[s.x+a][s.y],t[s.x][s.y]+1);
				if(s.x+a==ex && s.y==ey)
				{
					flag=1,que.push((poi){ex,ey});
					break;
				}
				if(ch[s.x+a][s.y]!='.' || in[s.x+a][s.y][2])
				{
					break;
				}
				if(ch[s.x+a][s.y-1]=='.')
				{
					if(!in[s.x+a][s.y][1])
					{
						in[s.x+a][s.y][1]=1;
						que.push((poi){s.x+a,s.y});
					}
				}
				if(ch[s.x+a][s.y+1]=='.')
				{
					if(!in[s.x+a][s.y][3])
					{
						in[s.x+a][s.y][3]=1;
						que.push((poi){s.x+a,s.y});
					}
				}
			}
			if(a>k && s.x+k<=n)
			{
				if(!in[s.x+k][s.y][2])
				{
					in[s.x+k][s.y][2]=1;
					que.push((poi){s.x+k,s.y});
				}
			}
		}
		if(in[s.x][s.y][3])
		{
			for(a=1;a<=k && s.y+a<=m;a++)
			{
				t[s.x][s.y+a]=min(t[s.x][s.y+a],t[s.x][s.y]+1);
				if(s.x==ex && s.y+a==ey)
				{
					flag=1,que.push((poi){ex,ey});
					break;
				}
				if(ch[s.x][s.y+a]!='.' || in[s.x][s.y+a][3])
				{
					break;
				}
				if(ch[s.x-1][s.y+a]=='.')
				{
					if(!in[s.x][s.y+a][0])
					{
						in[s.x][s.y+a][0]=1;
						que.push((poi){s.x,s.y+a});
					}
				}
				if(ch[s.x+1][s.y+a]=='.')
				{
					if(!in[s.x][s.y+a][2])
					{
						in[s.x][s.y+a][2]=1;
						que.push((poi){s.x,s.y+a});
					}
				}
			}
			if(a>k && s.y+k<=m)
			{
				if(!in[s.x][s.y+k][3])
				{
					in[s.x][s.y+k][3]=1;
					que.push((poi){s.x,s.y+k});
				}
			}
		}
	}
	printf("-1");
	return 0;
}


#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<set>
using namespace std;
struct poi
{
	int x,y;
}s;
queue<poi> que;
int n,m,k,sx,sy,ex,ey,t[1039][1039];
bool in[1039][1039][4];
char ch[1039][1039];
int main()
{
	memset(t,63,sizeof(t));
	int a,b,c;
	scanf("%d%d%d",&n,&m,&k);
	for(a=1;a<=n;a++)
	{
		for(b=1;b<=m;b++)
		{
			scanf(" %c",&ch[a][b]);
		}
	}
	scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
	que.push((poi){sx,sy});
	que.push((poi){sx,sy});
	que.push((poi){sx,sy});
	que.push((poi){sx,sy});
	in[sx][sy][0]=in[sx][sy][1]=in[sx][sy][2]=in[sx][sy][3]=1;
	t[sx][sy]=0;
	while(!que.empty())
	{
		s=que.front(),que.pop();
		if(s.x==ex && s.y==ey)
		{
			printf("%d",t[ex][ey]);
			return 0;
		}
		if(in[s.x][s.y][0])
		{
			for(a=1;a<=k && s.x-a;a++)
			{
				t[s.x-a][s.y]=min(t[s.x-a][s.y],t[s.x][s.y]+1);
				if(s.x-a==ex && s.y==ey)
				{
					t[ex][ey]=min(t[ex][ey],t[s.x][s.y]+1);
					que.push((poi){ex,ey});
				}
				if(ch[s.x-a][s.y]!='.' || in[s.x-a][s.y][0])
				{
					break;
				}
				if(ch[s.x-a][s.y-1]=='.')
				{
					if(!in[s.x-a][s.y][1])
					{
						in[s.x-a][s.y][1]=1;
						que.push((poi){s.x-a,s.y});
					}
				}
				if(ch[s.x-a][s.y+1]=='.')
				{
					if(!in[s.x-a][s.y][3])
					{
						in[s.x-a][s.y][3]=1;
						que.push((poi){s.x-a,s.y});
					}
				}
			}
			if(a>k && s.x-k)
			{
				if(!in[s.x-k][s.y][0])
				{
					in[s.x-k][s.y][0]=1;
					que.push((poi){s.x-k,s.y});
				}
			}
		}
		if(in[s.x][s.y][1])
		{
			for(a=1;a<=k && s.y-a;a++)
			{
				t[s.x][s.y-a]=min(t[s.x][s.y-a],t[s.x][s.y]+1);
				if(s.x==ex && s.y-a==ey)
				{
					t[ex][ey]=min(t[ex][ey],t[s.x][s.y]+1);
					que.push((poi){ex,ey});
				}
				if(ch[s.x][s.y-a]!='.' || in[s.x][s.y-a][1])
				{
					break;
				}
				if(ch[s.x-1][s.y-a]=='.')
				{
					if(!in[s.x][s.y-a][0])
					{
						in[s.x][s.y-a][0]=1;
						que.push((poi){s.x,s.y-a});
					}
				}
				if(ch[s.x+1][s.y-a]=='.')
				{
					if(!in[s.x][s.y-a][2])
					{
						in[s.x][s.y-a][2]=1;
						que.push((poi){s.x,s.y-a});
					}
				}
			}
			if(a>k && s.y-k)
			{
				if(!in[s.x][s.y-k][1])
				{
					in[s.x][s.y-k][1]=1;
					que.push((poi){s.x,s.y-k});
				}
			}
		}
		if(in[s.x][s.y][2])
		{
			for(a=1;a<=k && s.x+a<=n;a++)
			{
				t[s.x+a][s.y]=min(t[s.x+a][s.y],t[s.x][s.y]+1);
				if(s.x+a==ex && s.y==ey)
				{
					t[ex][ey]=min(t[ex][ey],t[s.x][s.y]+1);
					que.push((poi){ex,ey});
				}
				if(ch[s.x+a][s.y]!='.' || in[s.x+a][s.y][2])
				{
					break;
				}
				if(ch[s.x+a][s.y-1]=='.')
				{
					if(!in[s.x+a][s.y][1])
					{
						in[s.x+a][s.y][1]=1;
						que.push((poi){s.x+a,s.y});
					}
				}
				if(ch[s.x+a][s.y+1]=='.')
				{
					if(!in[s.x+a][s.y][3])
					{
						in[s.x+a][s.y][3]=1;
						que.push((poi){s.x+a,s.y});
					}
				}
			}
			if(a>k && s.x+k<=n)
			{
				if(!in[s.x+k][s.y][2])
				{
					in[s.x+k][s.y][2]=1;
					que.push((poi){s.x+k,s.y});
				}
			}
		}
		if(in[s.x][s.y][3])
		{
			for(a=1;a<=k && s.y+a<=m;a++)
			{
				t[s.x][s.y+a]=min(t[s.x][s.y+a],t[s.x][s.y]+1);
				if(s.x==ex && s.y+a==ey)
				{
					t[ex][ey]=min(t[ex][ey],t[s.x][s.y]+1);
					que.push((poi){ex,ey});
				}
				if(ch[s.x][s.y+a]!='.' || in[s.x][s.y+a][3])
				{
					break;
				}
				if(ch[s.x-1][s.y+a]=='.')
				{
					if(!in[s.x][s.y+a][0])
					{
						in[s.x][s.y+a][0]=1;
						que.push((poi){s.x,s.y+a});
					}
				}
				if(ch[s.x+1][s.y+a]=='.')
				{
					if(!in[s.x][s.y+a][2])
					{
						in[s.x][s.y+a][2]=1;
						que.push((poi){s.x,s.y+a});
					}
				}
			}
			if(a>k && s.y+k<=m)
			{
				if(!in[s.x][s.y+k][3])
				{
					in[s.x][s.y+k][3]=1;
					que.push((poi){s.x,s.y+k});
				}
			}
		}
	}
	printf("-1");
	return 0;
}