use std::io;
use std::collections::{HashMap, HashSet, VecDeque};
//use rand::{random, random_bool, random_range};
use std::time::{SystemTime, UNIX_EPOCH};
use rand::random_bool;
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 rowgrid: Vec<Vec<NodeID>> = vec!();
let mut colgrid: Vec<Vec<NodeID>> = vec!();
let mut boolgrid: Vec<Vec<bool>> = vec!();
let mut val = 0;
for row in 0..startdata[0] {
rowgrid.push(Vec::new());
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..startdata[1] {
if row == 0 {
colgrid.push(Vec::new());
}
if bytes[c] == 46 {
rowgrid[row].push((row, c));
colgrid[c].push((row, c));
}
}
}
let mut dist2cols: Vec<Vec<NodeID>> = vec!();
for col in 0..startdata[1] {
dist2cols.push(Vec::new());
for cell in colgrid[col].iter() {
for neighbor in rowgrid[cell.0].iter() {
if neighbor != cell {
dist2cols[col].push(*neighbor);
}
}
}
}
let mut dist2rows: Vec<Vec<NodeID>> = vec!();
for row in 0..startdata[0] {
dist2rows.push(Vec::new());
for cell in rowgrid[row].iter() {
for neighbor in colgrid[cell.1].iter() {
if neighbor != cell {
dist2rows[row].push(*neighbor);
}
}
}
}
//dbg!(&grid);
let mut distancehash: HashMap<(NodeID, NodeID), usize> = HashMap::new();
'question: 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: NodeID = (questiondata[0], questiondata[1]);
let dest: NodeID = (questiondata[2], questiondata[3]);
distancehash.insert((source, source), 0);
match distancehash.get(&(source, dest)) {
Some(dist) => {println!("{}", dist); continue;}
None => {}
}
let mut queue: VecDeque<NodeID> = VecDeque::new();
queue.push_front(source);
let mut possibilities: Vec<usize> = vec!();
let mut searchdist: usize = 0;
'bfs: while queue.len() != 0 {
let node = queue.pop_back().unwrap();
let dist = *distancehash.get(&(source, node)).unwrap();
if dist > searchdist {
if possibilities.len() != 0 {
println!("{}", possibilities.iter().min().unwrap());
continue 'question;
}
searchdist += 2;
}
if node.0 == dest.0 || node.1 == dest.1 {
println!("{}", dist+1);
continue 'question;
}
for neighbor in rowgrid[node.0].iter() {
if *neighbor != node {
distancehash.entry((source, *neighbor)).or_insert(dist+1);
distancehash.entry((source, *neighbor)).or_insert(dist+1);
}
}
for neighbor in colgrid[node.1].iter() {
if *neighbor != node {
distancehash.entry((source, *neighbor)).or_insert(dist+1);
distancehash.entry((source, *neighbor)).or_insert(dist+1);
}
}
for neighbor in dist2cols[node.1].iter() {
if node.0 != neighbor.0 {
let neighbordist = match distancehash.get(&(source, *neighbor)) {
Some(d) => *d,
None => 1000000
};
if neighbordist > dist {
distancehash.insert((source, *neighbor), dist+2);
distancehash.insert((*neighbor, source), dist+2);
queue.push_front(*neighbor);
}
if *neighbor == dest {
possibilities.push(neighbordist);
continue 'bfs;
}
}
}
for neighbor in dist2rows[node.0].iter() {
if node.1 != neighbor.1 {
let neighbordist = match distancehash.get(&(source, *neighbor)) {
Some(d) => *d,
None => 1000000
};
if neighbordist > dist {
distancehash.insert((source, *neighbor), dist+2);
distancehash.insert((*neighbor, source), dist+2);
queue.push_front(*neighbor);
}
if *neighbor == dest {
possibilities.push(neighbordist);
continue 'bfs;
}
}
}
}
match distancehash.get(&(source, dest)) {
Some(d) => println!("{}", d),
None => println!("-1")
}
}
}