import numpy as np

from scipy.sparse import csgraph

H, W = list(map(int, input().split()))

maze = "".join(eval(input()) for _ in range(H))

array = np.zeros((H * W, H * W), dtype=np.bool)

for n in range(H * W):

    if maze[n] == "#":

        continue

    r, c = divmod(n, W)

    if c and maze[n - 1] == ".":

        array[n][n - 1] = 1

        array[n - 1][n] = 1

    if r and maze[n - W] == ".":

        array[n][n - W] = 1

        array[n - W][n] = 1

dist = csgraph.shortest_path(array)

print((int(dist[dist < 401].max())))

import numpy as np

from scipy.sparse import csgraph

H, W = list(map(int, input().split()))#縦と横の大きさを入力から得る

maze = "".join(eval(input()) for _ in range(H))#入力を全行数分取得

#配列を生成する。np.zeros()は全てを0に初期化する関数

#第１引数は H*W,H*Wの２次元配列、第２引数はbool型を意味する

array = np.zeros((H * W, H * W), dtype=np.bool)



for n in range(H * W):

    if maze[n] == "#":

        continue

    r, c = divmod(n, W)#divmod()は商と余りを求める関数。（r:商　c:余り）



    if c and maze[n - 1] == ".":

        array[n][n - 1] = 1

        array[n - 1][n] = 1

    if r and maze[n - W] == ".":

        array[n][n - W] = 1

        array[n - W][n] = 1

dist = csgraph.shortest_path(array)

print((int(dist[dist < 401].max())))

    
import numpy as np
from scipy.sparse import csgraph

H, W = list(map(int, input().split()))
maze = "".join(eval(input()) for _ in range(H))
array = np.zeros((H * W, H * W), dtype=np.bool)
for n in range(H * W):
    if maze[n] == "#":
        continue
    r, c = divmod(n, W)
    if c and maze[n - 1] == ".":
        array[n][n - 1] = 1
        array[n - 1][n] = 1
    if r and maze[n - W] == ".":
        array[n][n - W] = 1
        array[n - W][n] = 1
dist = csgraph.shortest_path(array)
print((int(dist[dist < 401].max())))

import numpy as np
from scipy.sparse import csgraph

H, W = list(map(int, input().split()))  # 縦と横の大きさを入力から得る
maze = "".join(eval(input()) for _ in range(H))  # 入力を全行数分取得
# 配列を生成する。np.zeros()は全てを0に初期化する関数
# 第１引数は H*W,H*Wの２次元配列、第２引数はbool型を意味する
array = np.zeros((H * W, H * W), dtype=np.bool)
for n in range(H * W):
    if maze[n] == "#":
        continue
    r, c = divmod(n, W)  # divmod()は商と余りを求める関数。（r:商　c:余り）
    if c and maze[n - 1] == ".":
        array[n][n - 1] = 1
        array[n - 1][n] = 1
    if r and maze[n - W] == ".":
        array[n][n - W] = 1
        array[n - W][n] = 1
dist = csgraph.shortest_path(array)
print((int(dist[dist < 401].max())))

-H, W = list(map(int, input().split())) -maze = "".join(eval(input()) for _ in range(H)) +H, W = list(map(int, input().split()))  # 縦と横の大きさを入力から得る +maze = "".join(eval(input()) for _ in range(H))  # 入力を全行数分取得 +# 配列を生成する。np.zeros()は全てを0に初期化する関数 +# 第１引数は H*W,H*Wの２次元配列、第２引数はbool型を意味する -    r, c = divmod(n, W) +    r, c = divmod(n, W)  # divmod()は商と余りを求める関数。（r:商　c:余り）