import Control.Monad
import Data.Maybe
import Data.List
import qualified Data.Array as A
import qualified Data.Vector as V

import qualified Data.ByteString.Char8 as BS

tuplify2 :: [b] -> (b, b)
tuplify2 (x:y:_) = (x,y)
tuplify2 _ = undefined
readInt :: BS.ByteString -> Integer
readInt = fst . fromJust . BS.readInteger
readIntTuple :: BS.ByteString -> (Integer, Integer)
readIntTuple = tuplify2 . map readInt . BS.words
readIntList :: BS.ByteString -> [Integer]
readIntList = map readInt . BS.words


getInt :: IO Integer
getInt = readInt <$> BS.getLine
getIntList :: IO [Integer]
getIntList = readIntList <$> BS.getLine
getIntNList :: Integral a => a -> IO [[Integer]]
getIntNList n = map readIntList <$> replicateM (fromIntegral n) BS.getLine
getIntMatrix :: IO [[Integer]]
getIntMatrix = map readIntList . BS.lines <$> BS.getContents
getIntTuple :: IO (Integer, Integer)
getIntTuple = readIntTuple <$> BS.getLine
getIntNTuples :: Integral a => a -> IO [(Integer, Integer)]
getIntNTuples n = map readIntTuple <$> replicateM (fromIntegral n) BS.getLine
getIntTuples :: IO [(Integer, Integer)]
getIntTuples = map readIntTuple . BS.lines <$> BS.getContents

getString :: IO String
getString = BS.unpack <$> BS.getLine

getByteStringNList :: (Integral a) => a -> IO [BS.ByteString]
getByteStringNList n = replicateM (fromIntegral n) BS.getLine

zipper :: (a -> b) -> [a] -> [(b,a)]
zipper f list = zip (map f list) list
sepDigit :: Integer -> [Integer]
sepDigit = sepDigitBase 10
sepDigitBase :: Integer -> Integer -> [Integer]
sepDigitBase m n = reverse . helper $ n
  where helper n
          | n < m = [n]
          | otherwise = (mod n m): (helper (div n m))
conDigit :: [Integer] -> Integer
conDigit = conDigitBase 10
conDigitBase :: Integer -> [Integer] -> Integer
conDigitBase m [] = 0
conDigitBase m [x] = x
conDigitBase m list = (last list) + (m * conDigitBase m (init list))

type Point = (Integer, Integer)
type Block = A.Array Point Bool
toBlock :: Integer -> Integer -> [Bool] -> Block
toBlock h w = A.array ((1,1), (w,h)) . zip [(m, n) | n <- [1..h], m <- [1..w]]

main = do
    (h, w) <- getIntTuple
    wall <- concatMap ((map (=='#')) . BS.unpack) <$> getByteStringNList h
    let block = toBlock h w wall
    print . solve block $ findWall block 

solve :: Block -> [Point] -> Integer
solve block ps
  | isAllWall block = 0
  | otherwise = 1 + solve nextB nextP
      where (nextB, nextP) = nextBlock block ps

nextBlock :: Block -> [Point] -> (Block, [Point])
nextBlock block ps = ((A.//) block [(p, True) | p <- nextPs], nextPs)
  where nextPs = filter ((not.id).((A.!) block)) . filter (A.inRange (A.bounds block)) . concatMap walk $ ps

walk :: Point -> [Point]
walk (px, py) = [(px+dx, py+dy) | (dx,dy) <- [(1,0),(0,1),(-1,0),(0,-1)]]

findWall :: Block -> [Point]
findWall = map fst . filter snd . A.assocs

isAllWall :: Block -> Bool
isAllWall = all id