{-# LANGUAGE BangPatterns #-}

import           Control.Monad
import           Control.Monad.ST
import           Data.Array.ST
import           Data.Array.Unboxed
import qualified Data.ByteString.Char8 as BS
import           Data.Maybe
import           Data.Sequence         (Seq, ViewL (..), ViewR (..), (<|), (><),
                                        (|>))
import qualified Data.Sequence         as S
readInt = fst . fromJust . BS.readInt
readIntList = map readInt . BS.words
getIntList = readIntList <$> BS.getLine
type Pos = (Int,Int)
main = do
    [h,w] <- getIntList
    a <- map (/= '#') . concatMap BS.unpack <$> replicateM h BS.getLine
    let grid = listArray ((0,0),(h-1,w-1)) a
        init = S.fromList $ zip [(y,x) | x <- [0..w-1],y <- [0..h-1],not $ grid ! (y,x)] (repeat 0)
    print $ bfs (h-1,w-1) grid init
    return()

next :: STUArray s Pos Bool -> Pos -> Pos -> ST s (Seq Pos)
next g (h',w') (y,x) = do
    let list = [(ny,nx) | (dy,dx) <- zip [0,1,0,-1] [1,0,-1,0],let ny=y+dy,let nx=x+dx,0 <= ny && ny <= h' && 0 <= nx && nx <= w']
    vals <- zip list <$> mapM (readArray g) list
    let list' = [p | (p,v) <- vals,v]
    return $ S.fromList list'

bfs :: Pos -> UArray Pos Bool -> Seq (Pos,Int) -> Int
bfs s grid init = runST $ do
    g <- thaw grid :: ST s (STUArray s Pos Bool)
    f g init
    where   f :: STUArray s Pos Bool -> Seq (Pos,Int) -> ST s Int
            f !g !seq = case S.viewl seq of
                S.EmptyL  -> return 0
                ((p,d) :< ps) ->
                    do
                        !ne <- next g s p
                        let !ne' = S.zip ne (S.replicate 4 (d+1))
                        forM_ ne $ \(ny,nx) -> writeArray g (ny,nx) False
                        !v <- f g (ps><ne')
                        return $ max d v
