{-# LANGUAGE ViewPatterns #-}

import           Data.Array.IArray
import           Data.Bifunctor
import qualified Data.ByteString.Char8 as BS
import           Data.List
import qualified Data.Map              as M
import           Data.Maybe
import           Data.Sequence         (ViewL (..), (<|), (|>))
import qualified Data.Sequence         as Q

combinations :: Int -> [a] -> [[a]]
combinations 0 _  = [[]]
combinations n xs = [ y:ys | y:xs' <- tails xs
                    , ys <- combinations (n-1) xs' ]

bfsMaze :: (Int,Int) -> (Int,Int) -> Array (Int,Int) Char -> Maybe Int
bfsMaze s g a
  | a!s == '#' || a!g == '#' = Nothing
  | otherwise = go (M.insert s 0 M.empty) (s <| Q.empty)
  where
    ((ly,lx),(hy,hx)) = bounds a
    go :: M.Map (Int,Int) Int -> Q.Seq (Int,Int) -> Maybe Int
    go _ (Q.viewl -> EmptyL) = Nothing
    go m (Q.viewl -> (p :< q))
      | p == g    = Just (m M.! p)
      | otherwise =
          case next p of
              [] -> go m q
              ns -> let (q',m') = foldl' f (q,m) ns
                     in go m' q'
      where
        {-# INLINE f #-}
        f a n = bimap (|> n) (M.insert n (succ (m M.! p))) a
        {-# INLINE next #-}
        next (y,x) = [ (ny,nx) | (ny,nx) <- [(y+1,x), (y,x+1), (y-1,x), (y,x-1)]
                     ,  ly <= ny && lx <= nx && ny <= hy && nx <= hx
                     && a!(ny,nx) /= '#' && (ny,nx) `M.notMember` m ]

solve a = maximum . catMaybes $ map bfs cmb
  where
    cmb = combinations 2 . range $ bounds a
    bfs [s,g] = bfsMaze s g a

main = do
    [h,w] <- map read . words <$> getLine :: IO [Int]
    a <- listArray ((1,1),(h,w))
       . concatMap BS.unpack . BS.lines
     <$> BS.getContents :: IO (Array (Int,Int) Char)
    print $ solve a