macro_rules! scan_sub {
    ( $itr:ident, $t:ty ) => {
        let mut buf = String::new();
        let $itr = {
            while buf.trim().len() == 0 {
                buf = String::new();
                std::io::stdin().read_line(&mut buf).unwrap();
            }
            buf.split_whitespace().map(|n| n.parse::<$t>().unwrap())
        };
    };
}

macro_rules! scan {
    ( $x:ident; Vec<$t:ty> ) => {
        scan_sub!(itr, $t);
        let $x = itr.collect::<Vec<_>>();
    };
    ( $( $x:ident ),*; $t:ty ) => {
        scan_sub!(itr, $t);
        let mut itr = itr;
        $(
            let $x = itr.next().unwrap();
        )*
    };
}

enum Node {
    // nd is next doors
    Movable {nd: Vec<(usize, usize)>},
    Block,
}

use Node::*;

fn dist(a: (usize, usize), b: (usize, usize)) -> f64 {
    let x = a.0 as i64 - b.0 as i64;
    let y = a.1 as i64 - b.1 as i64;

    ((x * x + y * y) as f64).sqrt()
}

fn dfs(maze: &Vec<Vec<Node>>,
       pos: (usize, usize),
       depth: usize,
       visited: &Vec<bool>,
       height: usize,
       // width: usize,
       start: (usize, usize),
       most_far: &mut (usize, (usize, usize)))
{
    if most_far.0 < depth {
        *most_far = (depth, pos);
    } else if most_far.0 == depth {
        if dist(most_far.1, start) < dist(pos, start) {
            *most_far = (depth, pos);
        }
    }

    let mut new_visited = visited.to_vec();
    new_visited[pos.0 * height + pos.1] = true;

    let vec;
    match maze[pos.0][pos.1] {
        Movable {ref nd} => { vec = nd; },
        Block => return,
    }

    for &p in vec.iter() {
        if new_visited[p.0 * height + p.1] {
            continue;
        }
        dfs(maze, p, depth+1, &new_visited, height, start, most_far);
    }
}

use std::collections::VecDeque;

fn main() {
    scan!(h, w; usize);
    let mut maze = (0..h).map(|_| {
        (0..w).map(|_| Movable {nd: Vec::with_capacity(4)}).collect::<Vec<_>>()
    }).collect::<Vec<_>>();

    let mut maze_bool = vec![vec![true; w]; h];

    for i in 0..h {
        scan!(line; String);
        for (j, c) in line.chars().enumerate() {
            if c == '#' {
                maze[i][j] = Block;
                maze_bool[i][j] = false;
            }
        }
    }

    for i in 0..h {
        for j in 0..w {
            match maze[i][j] {
                Movable {ref mut nd} => {
                    let vec = nd;
                    let four = vec![
                                  (-1,  0),
                        ( 0, -1),           ( 0,  1),
                                  ( 1,  0),
                    ];

                    let (t, u) = (i as i64, j as i64);

                    for (x, y) in four {
                        let (p, q) = (t+x, u+y);
                        if p < 0 || h as i64 <= p || q < 0 || w as i64 <= q {
                            continue;
                        }
                        let (p, q) = (p as usize, q as usize);
                        if maze_bool[p][q] {
                            vec.push((p, q));
                        }
                    }
                },
                Block => (),
            }
        }
    }

    let mut s = (0, 0);
    'find: for i in 0..h {
        for j in 0..w {
            if let Movable{nd: _} = maze[i][j] {
                s = (i, j);
                break 'find;
            }
        }
    }

    let mut start = (0, s);
    let visited = vec![false; h*w];
    dfs(&maze, s, 0, &visited, h, s, &mut start);
    let mut goal = (0, start.1);
    dfs(&maze, start.1, 0, &visited, h, start.1, &mut goal);

    let mut que = VecDeque::new();
    que.push_front((0, start.1));
    let mut visited = vec![vec![false; w]; h];
    let mut ans = 0;

    while !que.is_empty() {
        let p = que.pop_back().unwrap();

        if p.1 == goal.1 {
            ans = p.0;
            break;
        }

        let (x, y) = p.1;
        visited[x][y] = true;

        match maze[x][y] {
            Movable {ref nd} => {
                for &(t, u) in nd.iter() {
                    if visited[t][u] { continue; }

                    que.push_front((p.0+1, (t, u)));
                }
            },
            Block => (),
        }
    }

    println!("{}", ans);
}
