use std::{io, iter, cmp::min};
use std::collections::{HashMap, HashSet, VecDeque};
use std::time::{SystemTime, UNIX_EPOCH};
type NodeID = (usize, usize);
fn main() {
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed to read input");
let startdata: Vec<usize> = input.split_whitespace().map(|e| e.parse::<usize>().unwrap()).collect();
let mut grid: Vec<Vec<bool>> = vec!();
let mut nodeset: Vec<NodeID> = Vec::new();
for row in 0..startdata[0] {
let mut newrow: Vec<bool> = vec!();
let mut rowinput = String::new();
io::stdin().read_line(&mut rowinput).expect("Failed to read input");
let bytes = rowinput.as_bytes();
for c in 0..rowinput.len() {
if bytes[c] == 46 {
newrow.push(true);
nodeset.push((row, c));
} else {
newrow.push(false);
}
}
/*for c in rowinput.into_bytes().into_iter() {
if c == 46 {
newrow.push(true);
nodeset.push((row, ))
} else {
newrow.push(false);
}
} */
grid.push(newrow);
}
let mut distancehash: HashMap<(NodeID, NodeID), isize> = HashMap::new();
for node1 in nodeset.iter() {
for node2 in nodeset.iter() {
if node1 == node2 {
distancehash.insert((*node1, *node2), 0);
} else if node1.1 == node2.1 || node1.0 == node2.0 {
distancehash.insert((*node1, *node2), 1);
} else {
distancehash.insert((*node1, *node2), 1000000);
}
}
}
for node1 in nodeset.iter() {
for node2 in nodeset.iter() {
for node3 in nodeset.iter() {
let val1 = distancehash[&(*node2, *node3)];
let val2 = distancehash[&(*node2, *node1)]+distancehash[&(*node1, *node3)];
distancehash.insert((*node2, *node3), min(val1, val2));
}
}
}
for _q in 0..startdata[2] {
let mut questioninput = String::new();
io::stdin().read_line(&mut questioninput).expect("Failed to read input");
let questiondata: Vec<usize> = questioninput.split_whitespace().map(|e| e.parse::<usize>().unwrap()-1).collect();
let source = (questiondata[0], questiondata[1]);
let destination = (questiondata[2], questiondata[3]);
let dist = distancehash[&(source, destination)];
if dist != 1000000 {
println!("{}", dist);
} else {
println!("-1");
}
}
}