--import Debug.Trace
import qualified Data.Vector as V
-- import qualified Data.Vector.Unboxed as U
import qualified Data.ByteString.Char8 as C
import Data.List
import Control.Monad
import qualified Data.Array.IO as A

type ArrayToday = A.IOArray (Int,Int) (Maybe Int)
{-
grou :: Int -> [a] -> [[a]]
grou n [] = []
grou n xs = take n xs:grou n (drop n xs) 

printArr :: ArrayToday -> IO ()
printArr arr = do
    (_,(_,w)) <- A.getBounds arr
    elems <- map show' <$> A.getElems arr :: IO [String]
    let x = grou w elems :: [[String]]
    let y = map unwords x :: [String]
    putStrLn $ (unlines y)
        where
            show' Nothing = "N"
            show' (Just n) = show n
-}

r :: Int -> IO (V.Vector (Maybe Int))
r n = V.unfoldrN n (readColorBS . C.dropWhile (==' ')) <$> C.getLine

r' :: IO [Int]
r' = unfoldr (C.readInt . C.dropWhile (==' ')) <$> C.getLine


data Col = B | W deriving Eq

readColor :: Char -> Maybe Int
readColor '#' = Just 0
readColor '.' = Nothing

readColorBS :: C.ByteString -> Maybe (Maybe Int, C.ByteString)
readColorBS str
    | C.null str = Nothing
    | otherwise = Just (readColor (C.head str), C.tail str)

min' a Nothing = a
min' Nothing b = b
min' a b = min a b

minimum' = V.foldr min' Nothing

readColumn :: ArrayToday -> Int -> Int -> IO ()
readColumn arr col w = do
    xs <- r w :: IO (V.Vector (Maybe Int))
    V.zipWithM_ (\x y -> A.writeArray arr (col,x) y) (V.generate w succ) xs

main = do
    [h,w] <- map read . words <$> getLine :: IO [Int]
    arr <- A.newArray ((1,1),(h,w)) Nothing :: IO ArrayToday
    V.mapM_ (\col -> readColumn arr col w) (V.generate h succ)
    res <- solve arr 0
    print res

solve :: ArrayToday -> Int -> IO Int
solve arr n = do
    narrElems <- A.getElems arr
    case find (== Nothing) narrElems of
        Nothing -> return n
        _       -> do
            narr <- iteration arr
            solve narr (n+1)

iteration :: ArrayToday -> IO ArrayToday
iteration arr = do
    bounds <- A.getBounds arr
    nextArr <- A.newArray bounds Nothing :: IO ArrayToday
    forM_ (A.range bounds) (\c -> cell arr nextArr c bounds)
    return nextArr

cell :: ArrayToday -> ArrayToday -> (Int,Int) -> ((Int,Int),(Int,Int)) -> IO ()
cell arr1 arr2 coord bounds = do
    current <- A.readArray arr1 coord
    next <- case current of
        Nothing -> do
            nNum <- V.mapM (A.readArray arr1) (neighbours coord bounds) :: IO (V.Vector (Maybe Int))
            return (minimum' nNum)
        j -> return j
    A.writeArray arr2 coord next


neighbours :: (Int,Int) -> ((Int,Int),(Int,Int)) -> V.Vector (Int,Int)
neighbours (x,y) ((x1,y1),(x2,y2)) =
    let a = if x > x1 then (V.cons (x-1,y)) else id
        b = if y > y1 then (V.cons (x,y-1)) else id
        c = if x < x2 then (V.cons (x+1,y)) else id
        d = if y < y2 then (V.cons (x,y+1)) else id
    in (a.b.c.d) V.empty
