Buggy python submission (verdict: Time Limit Exceeded):
h,w=map(int,input().split())
s=[list(input()) for i in range(h)]
inf=1000000000
wf=[[inf]*(h*w) for i in range(h*w)]
for i in range(h*w):
    k,l=i//w,i%w
    #print(l)
    if s[k][l]=="#":
        continue
    if k!=0:
        if s[k-1][l]==".":
            wf[i][i-w]=1
    if k!=h-1:
        if s[k+1][l]==".":
            wf[i][i+w]=1
    if l!=0:
        if s[k][l-1]==".":
            wf[i][i-1]=1
    if l!=w-1:
        if s[k][l+1]==".":
            wf[i][i+1]=1
    wf[i][i]=0
for i in range(h*w):
    for j in range(h*w):
        for k in range(h*w):
            wf[j][k]=min(wf[j][k],wf[j][i]+wf[i][k])
ans=0
for i in range(h*w):
    for j in range(h*w):
        if wf[i][j]!=inf:
            ans=max(ans,wf[i][j])
print(ans)

Fixed submission:
import queue
h,w=map(int,input().split())
s=[list(input()) for i in range(h)]

inf=100000000
ma=[]
for i in range(h):
    for j in range(w):
        if s[i][j]==".":
            x=[[inf for i_sub in range(w)] for j_sub in range(h)]
            #いまみているグリッド
            q=queue.Queue()
            d=0
            #初めのグリッド
            q.put([i,j])
            x[i][j]=0
            #次々にグリッドを辿って全部のグリッド辿ったら終わり
            while q.qsize()!=0:
                #距離を加算
                d+=1
                l=q.qsize()
                #今いるグリッドの数は数えておく
                for t in range(l):
                    I,J=q.get()
                    #今いるグリッドから次のグリッドへ
                    #その判定は"そこにグリッドがあるか","そこが辿れるのか","すでに辿っているのか"の三つです。
                    if I-1>=0 and s[I-1][J]=="." and x[I-1][J]==inf:
                        q.put([I-1,J])
                        #この更新をif文内で行わないと余計にグリッドを調べてしまう
                        x[I-1][J]=d
                    if I+1<=h-1 and s[I+1][J]=="." and x[I+1][J]==inf:
                        q.put([I+1,J])
                        x[I+1][J]=d
                    if J-1>=0 and s[I][J-1]=="." and x[I][J-1]==inf:
                        q.put([I,J-1])
                        x[I][J-1]=d
                    if J+1<=w-1 and s[I][J+1]=="." and x[I][J+1]==inf:
                        q.put([I,J+1])
                        x[I][J+1]=d
            ma_sub=0
            for k in range(h):
                for l in range(w):
                    if x[k][l]!=inf:
                        ma_sub=max(ma_sub,x[k][l])
            ma.append(ma_sub)

print(max(ma))

Buggy python submission (verdict: Time Limit Exceeded):
import queue
import sys
def input():
    return sys.stdin.readline()[:]
h, w = map(int, input().split())
bigger = h if h > w else w
dfs = [[0]*bigger]*bigger
q = queue.Queue
d = []
for i in range(h):
  s = [j for j in input()]
  d.append(s)

def find_possible(i, j, ng):
  if i >= h-1:
    iaround = [i, i-1]
  elif i<=0:
    iaround = [i, i+1]
  else:
    iaround = [i, i-1, i+1]
  if j >= w-1:
    jaround = [j, j-1]
  elif j<=0:
    jaround = [j, j+1]
  else:
    jaround = [j, j-1, j+1]
  retv = []
  for a1 in iaround:
    for a2 in jaround:
      if [a1, a2] in ng or abs(a1-i) == abs(a2-j):
        continue
      elif d[a1][a2] == '.':
        retv.append([a1, a2])
  #print(i,j,retv)
  return retv

def bfs(qu):
  #includes points=[y][x], distance, parents=[[y][x]]
  used = [[-1 for _ in range(w)] for _ in range(h)]
  m = 0
  while not qu.empty():
    current = qu.get()
    row = current[0][0]
    column = current[0][1]
#    print(row, column, used[row][column])
    if used[row][column] > current[1] or used[row][column]<0:
      used[row][column] = current[1]
#      print(used)
#      print('update:', current[1])
      for a in find_possible(row, column, current[2]):
#          print('extend:',a,current[1]+1, tmp)          
        qu.put([a,current[1]+1, current[2] + [[row, column]]])
   #       if current[1]+1 > m:
   #         m = current[1]+1
#    print()
  m = 0
#  for i in used:
#    for j in i:
#      if m < j:
#        m = j
#  return m
  return used
m = 0
cans = []
for i in range(h):
  for j in range(w):
    if d[i][j] == '#':
      continue
    q = queue.Queue()
    q.put([[i,j], 0, []])
    t = bfs(q)
    cans.append(t)
import numpy as np
m = np.array(cans)

print(np.max(m))
#print(max(cans))    

Fixed submission:
import queue
h,w=map(int,input().split())
s=[list(input()) for i in range(h)]

inf=100000000
ma=[]
for i in range(h):
    for j in range(w):
        if s[i][j]==".":
            x=[[inf for i_sub in range(w)] for j_sub in range(h)]
            #いまみているグリッド
            q=queue.Queue()
            d=0
            #初めのグリッド
            q.put([i,j])
            x[i][j]=0
            #次々にグリッドを辿って全部のグリッド辿ったら終わり
            while q.qsize()!=0:
                #距離を加算
                d+=1
                l=q.qsize()
                #今いるグリッドの数は数えておく
                for t in range(l):
                    I,J=q.get()
                    #今いるグリッドから次のグリッドへ
                    #その判定は"そこにグリッドがあるか","そこが辿れるのか","すでに辿っているのか"の三つです。
                    if I-1>=0 and s[I-1][J]=="." and x[I-1][J]==inf:
                        q.put([I-1,J])
                        #この更新をif文内で行わないと余計にグリッドを調べてしまう
                        x[I-1][J]=d
                    if I+1<=h-1 and s[I+1][J]=="." and x[I+1][J]==inf:
                        q.put([I+1,J])
                        x[I+1][J]=d
                    if J-1>=0 and s[I][J-1]=="." and x[I][J-1]==inf:
                        q.put([I,J-1])
                        x[I][J-1]=d
                    if J+1<=w-1 and s[I][J+1]=="." and x[I][J+1]==inf:
                        q.put([I,J+1])
                        x[I][J+1]=d
            ma_sub=0
            for k in range(h):
                for l in range(w):
                    if x[k][l]!=inf:
                        ma_sub=max(ma_sub,x[k][l])
            ma.append(ma_sub)

print(max(ma))

Buggy python submission (verdict: Time Limit Exceeded):
import queue
import sys
def input():
    return sys.stdin.readline()[:]
h, w = map(int, input().split())
bigger = h if h > w else w
dfs = [[0]*bigger]*bigger
q = queue.Queue
d = []
for i in range(h):
  s = [j for j in input()]
  d.append(s)

def find_possible(i, j, ng):
  if i >= h-1:
    iaround = [i, i-1]
  elif i<=0:
    iaround = [i, i+1]
  else:
    iaround = [i, i-1, i+1]
  if j >= w-1:
    jaround = [j, j-1]
  elif j<=0:
    jaround = [j, j+1]
  else:
    jaround = [j, j-1, j+1]
  retv = []
  for a1 in iaround:
    for a2 in jaround:
      if [a1, a2] in ng or abs(a1-i) == abs(a2-j):
        continue
      elif d[a1][a2] == '.':
        retv.append([a1, a2])
  #print(i,j,retv)
  return retv

def bfs(qu):
  #includes points=[y][x], distance, parents=[[y][x]]
  used = [[-1 for _ in range(w)] for _ in range(h)]
  m = 0
  while not qu.empty():
    current = qu.get()
    row = current[0][0]
    column = current[0][1]
#    print(row, column, used[row][column])
    if used[row][column] > current[1] or used[row][column]<0:
      used[row][column] = current[1]
#      print(used)
#      print('update:', current[1])
      for a in find_possible(row, column, current[2]):
#          print('extend:',a,current[1]+1, tmp)          
        qu.put([a,current[1]+1, current[2] + [[row, column]]])
   #       if current[1]+1 > m:
   #         m = current[1]+1
#    print()
  m = 0
  for i in used:
    for j in i:
      if m < j:
        m = j
  return m
m = 0
cans = []
for i in range(h):
  for j in range(w):
    if d[i][j] == '#':
      continue
    q = queue.Queue()
    q.put([[i,j], 0, []])
    t = bfs(q)
    cans.append(t)
#import numpy as np
#m = np.array(cans)

#print(np.max(m))
print(max(cans))    

Fixed submission:
import queue
h,w=map(int,input().split())
s=[list(input()) for i in range(h)]

inf=100000000
ma=[]
for i in range(h):
    for j in range(w):
        if s[i][j]==".":
            x=[[inf for i_sub in range(w)] for j_sub in range(h)]
            #いまみているグリッド
            q=queue.Queue()
            d=0
            #初めのグリッド
            q.put([i,j])
            x[i][j]=0
            #次々にグリッドを辿って全部のグリッド辿ったら終わり
            while q.qsize()!=0:
                #距離を加算
                d+=1
                l=q.qsize()
                #今いるグリッドの数は数えておく
                for t in range(l):
                    I,J=q.get()
                    #今いるグリッドから次のグリッドへ
                    #その判定は"そこにグリッドがあるか","そこが辿れるのか","すでに辿っているのか"の三つです。
                    if I-1>=0 and s[I-1][J]=="." and x[I-1][J]==inf:
                        q.put([I-1,J])
                        #この更新をif文内で行わないと余計にグリッドを調べてしまう
                        x[I-1][J]=d
                    if I+1<=h-1 and s[I+1][J]=="." and x[I+1][J]==inf:
                        q.put([I+1,J])
                        x[I+1][J]=d
                    if J-1>=0 and s[I][J-1]=="." and x[I][J-1]==inf:
                        q.put([I,J-1])
                        x[I][J-1]=d
                    if J+1<=w-1 and s[I][J+1]=="." and x[I][J+1]==inf:
                        q.put([I,J+1])
                        x[I][J+1]=d
            ma_sub=0
            for k in range(h):
                for l in range(w):
                    if x[k][l]!=inf:
                        ma_sub=max(ma_sub,x[k][l])
            ma.append(ma_sub)

print(max(ma))

Buggy python submission (verdict: Time Limit Exceeded):
import queue
h, w = map(int, input().split())
bigger = h if h > w else w
dfs = [[0]*bigger]*bigger
q = queue.Queue
d = []
for i in range(h):
  s = [j for j in input()]
  d.append(s)
def find_possible(i, j, ng):
  if i >= h-1:
    iaround = [i, i-1]
  elif i<=0:
    iaround = [i, i+1]
  else:
    iaround = [i, i-1, i+1]
  if j >= w-1:
    jaround = [j, j-1]
  elif j<=0:
    jaround = [j, j+1]
  else:
    jaround = [j, j-1, j+1]
  retv = []
  for a1 in iaround:
    for a2 in jaround:
      if [a1, a2] in ng or abs(a1-i) == abs(a2-j):
        continue
      elif d[a1][a2] == '.':
        retv.append([a1, a2])
  #print(i,j,retv)
  return retv

def bfs(qu):
  #includes points=[y][x], distance, parents=[[y][x]]
  used = [[-1 for _ in range(w)] for _ in range(h)]
  m = 0
  while not qu.empty():
    current = qu.get()
    row = current[0][0]
    column = current[0][1]
#    print(row, column, used[row][column])
    if used[row][column] > current[1] or used[row][column]<0:
      used[row][column] = current[1]
#      print(used)
#      print('update:', current[1])
      for a in find_possible(row, column, current[2]):
#          print('extend:',a,current[1]+1, tmp)          
        qu.put([a,current[1]+1, current[2] + [[row, column]]])
   #       if current[1]+1 > m:
   #         m = current[1]+1
#    print()
  m = 0
  for i in used:
    for j in i:
      if m < j:
        m = j
  return m
m = 0
cans = []
for i in range(h):
  for j in range(w):
    if d[i][j] == '#':
      continue
    q = queue.Queue()
    q.put([[i,j], 0, []])
    t = bfs(q)
    cans.append(t)
#import numpy as np
#m = np.array(cans)

#print(np.max(m))
print(max(cans))    

Fixed submission:
import queue
h,w=map(int,input().split())
s=[list(input()) for i in range(h)]

inf=100000000
ma=[]
for i in range(h):
    for j in range(w):
        if s[i][j]==".":
            x=[[inf for i_sub in range(w)] for j_sub in range(h)]
            #いまみているグリッド
            q=queue.Queue()
            d=0
            #初めのグリッド
            q.put([i,j])
            x[i][j]=0
            #次々にグリッドを辿って全部のグリッド辿ったら終わり
            while q.qsize()!=0:
                #距離を加算
                d+=1
                l=q.qsize()
                #今いるグリッドの数は数えておく
                for t in range(l):
                    I,J=q.get()
                    #今いるグリッドから次のグリッドへ
                    #その判定は"そこにグリッドがあるか","そこが辿れるのか","すでに辿っているのか"の三つです。
                    if I-1>=0 and s[I-1][J]=="." and x[I-1][J]==inf:
                        q.put([I-1,J])
                        #この更新をif文内で行わないと余計にグリッドを調べてしまう
                        x[I-1][J]=d
                    if I+1<=h-1 and s[I+1][J]=="." and x[I+1][J]==inf:
                        q.put([I+1,J])
                        x[I+1][J]=d
                    if J-1>=0 and s[I][J-1]=="." and x[I][J-1]==inf:
                        q.put([I,J-1])
                        x[I][J-1]=d
                    if J+1<=w-1 and s[I][J+1]=="." and x[I][J+1]==inf:
                        q.put([I,J+1])
                        x[I][J+1]=d
            ma_sub=0
            for k in range(h):
                for l in range(w):
                    if x[k][l]!=inf:
                        ma_sub=max(ma_sub,x[k][l])
            ma.append(ma_sub)

print(max(ma))

Buggy python submission (verdict: Runtime Error):
import queue
h, w = map(int, input().split())
bigger = h if h > w else w
dfs = [[0]*bigger]*bigger
q = queue.Queue
d = []
for i in range(h):
  s = [j for j in input()]
  d.append(s)
from collections import defaultdict
def find_possible(i, j, ng):
  if i >= h-1:
    iaround = [i, i-1]
  elif i<=0:
    iaround = [i, i+1]
  else:
    iaround = [i, i-1, i+1]
  if j >= w-1:
    jaround = [j, j-1]
  elif j<=0:
    jaround = [j, j+1]
  else:
    jaround = [j, j-1, j+1]
  retv = []
  for a1 in iaround:
    for a2 in jaround:
      if [a1, a2] in ng or abs(a1-i) == abs(a2-j):
        continue
      elif d[a1][a2] == '.':
        retv.append([a1, a2])
  #print(i,j,retv)
  return retv

def bfs(s):
  qu = queue.Queue()
  qu.put([s, 0, []])
  #includes points=[y][x], distance, parents=[[y][x]]
  used = [[-1 for _ in range(w)] for _ in range(h)]
  m = 0
  while not qu.empty():
    current = qu.get()
    row = current[0][0]
    column = current[0][1]
#    print(row, column, used[row][column])
    if used[row][column] > current[1] or used[row][column]<0:
      used[row][column] = current[1]
#      print(used)
#      print('update:', current[1])
      for a in find_possible(row, column, current[2]):
#          print('extend:',a,current[1]+1, tmp)          
        qu.put([a,current[1]+1, current[2] + [[row, column]]])
   #       if current[1]+1 > m:
   #         m = current[1]+1
#    print()
  m = 0
  return used
m = 0
cans = []
for i in range(h):
  for j in range(w):
    if d[i][j] == '#':
      continue
    t = bfs([i,j])
    cans.append(t)
import numpy as np
m = np.array(cans)

print(np.max(m))
    

Fixed submission:
import queue
h,w=map(int,input().split())
s=[list(input()) for i in range(h)]

inf=100000000
ma=[]
for i in range(h):
    for j in range(w):
        if s[i][j]==".":
            x=[[inf for i_sub in range(w)] for j_sub in range(h)]
            #いまみているグリッド
            q=queue.Queue()
            d=0
            #初めのグリッド
            q.put([i,j])
            x[i][j]=0
            #次々にグリッドを辿って全部のグリッド辿ったら終わり
            while q.qsize()!=0:
                #距離を加算
                d+=1
                l=q.qsize()
                #今いるグリッドの数は数えておく
                for t in range(l):
                    I,J=q.get()
                    #今いるグリッドから次のグリッドへ
                    #その判定は"そこにグリッドがあるか","そこが辿れるのか","すでに辿っているのか"の三つです。
                    if I-1>=0 and s[I-1][J]=="." and x[I-1][J]==inf:
                        q.put([I-1,J])
                        #この更新をif文内で行わないと余計にグリッドを調べてしまう
                        x[I-1][J]=d
                    if I+1<=h-1 and s[I+1][J]=="." and x[I+1][J]==inf:
                        q.put([I+1,J])
                        x[I+1][J]=d
                    if J-1>=0 and s[I][J-1]=="." and x[I][J-1]==inf:
                        q.put([I,J-1])
                        x[I][J-1]=d
                    if J+1<=w-1 and s[I][J+1]=="." and x[I][J+1]==inf:
                        q.put([I,J+1])
                        x[I][J+1]=d
            ma_sub=0
            for k in range(h):
                for l in range(w):
                    if x[k][l]!=inf:
                        ma_sub=max(ma_sub,x[k][l])
            ma.append(ma_sub)

print(max(ma))

Buggy python submission (verdict: Time Limit Exceeded):
import queue
h, w = map(int, input().split())
bigger = h if h > w else w
dfs = [[0]*bigger]*bigger
q = queue.Queue
d = []
for i in range(h):
  s = [j for j in input()]
  d.append(s)
from collections import defaultdict
def find_possible(i, j, ng):
  if i >= h-1:
    iaround = [i, i-1]
  elif i<=0:
    iaround = [i, i+1]
  else:
    iaround = [i, i-1, i+1]
  if j >= w-1:
    jaround = [j, j-1]
  elif j<=0:
    jaround = [j, j+1]
  else:
    jaround = [j, j-1, j+1]
  retv = []
  for a1 in iaround:
    for a2 in jaround:
      if [a1, a2] in ng or abs(a1-i) == abs(a2-j):
        continue
      elif d[a1][a2] == '.':
        retv.append([a1, a2])
  #print(i,j,retv)
  return retv

def bfs(s):
  qu = queue.Queue()
  qu.put([s, 0, []])
  #includes points=[y][x], distance, parents=[[y][x]]
  used = [[-1 for _ in range(w)] for _ in range(h)]
  m = 0
  while not qu.empty():
    current = qu.get()
    row = current[0][0]
    column = current[0][1]
#    print(row, column, used[row][column])
    if used[row][column] > current[1] or used[row][column]<0:
      used[row][column] = current[1]
#      print(used)
#      print('update:', current[1])
      for a in find_possible(row, column, current[2]):
#          print('extend:',a,current[1]+1, tmp)          
        qu.put([a,current[1]+1, current[2] + [[row, column]]])
   #       if current[1]+1 > m:
   #         m = current[1]+1
#    print()
  m = 0
  return used
m = 0
cans = []
for i in range(h):
  for j in range(w):
    if d[i][j] == '#':
      continue
    t = bfs([i,j])
    cans.append(t)
import numpy as np
m = np.array(cans)

print(np.max(m))
    

Fixed submission:
import queue
h,w=map(int,input().split())
s=[list(input()) for i in range(h)]

inf=100000000
ma=[]
for i in range(h):
    for j in range(w):
        if s[i][j]==".":
            x=[[inf for i_sub in range(w)] for j_sub in range(h)]
            #いまみているグリッド
            q=queue.Queue()
            d=0
            #初めのグリッド
            q.put([i,j])
            x[i][j]=0
            #次々にグリッドを辿って全部のグリッド辿ったら終わり
            while q.qsize()!=0:
                #距離を加算
                d+=1
                l=q.qsize()
                #今いるグリッドの数は数えておく
                for t in range(l):
                    I,J=q.get()
                    #今いるグリッドから次のグリッドへ
                    #その判定は"そこにグリッドがあるか","そこが辿れるのか","すでに辿っているのか"の三つです。
                    if I-1>=0 and s[I-1][J]=="." and x[I-1][J]==inf:
                        q.put([I-1,J])
                        #この更新をif文内で行わないと余計にグリッドを調べてしまう
                        x[I-1][J]=d
                    if I+1<=h-1 and s[I+1][J]=="." and x[I+1][J]==inf:
                        q.put([I+1,J])
                        x[I+1][J]=d
                    if J-1>=0 and s[I][J-1]=="." and x[I][J-1]==inf:
                        q.put([I,J-1])
                        x[I][J-1]=d
                    if J+1<=w-1 and s[I][J+1]=="." and x[I][J+1]==inf:
                        q.put([I,J+1])
                        x[I][J+1]=d
            ma_sub=0
            for k in range(h):
                for l in range(w):
                    if x[k][l]!=inf:
                        ma_sub=max(ma_sub,x[k][l])
            ma.append(ma_sub)

print(max(ma))

Buggy python submission (verdict: Time Limit Exceeded):
import queue
h, w = map(int, input().split())
bigger = h if h > w else w
dfs = [[0]*bigger]*bigger
q = queue.Queue
d = []
for i in range(h):
  s = [j for j in input()]
  d.append(s)
from collections import defaultdict
def find_possible(i, j, ng):
  if i >= h-1:
    iaround = [i, i-1]
  elif i<=0:
    iaround = [i, i+1]
  else:
    iaround = [i, i-1, i+1]
  if j >= w-1:
    jaround = [j, j-1]
  elif j<=0:
    jaround = [j, j+1]
  else:
    jaround = [j, j-1, j+1]
  retv = []
  for a1 in iaround:
    for a2 in jaround:
      if [a1, a2] in ng or abs(a1-i) == abs(a2-j):
        continue
      elif d[a1][a2] == '.':
        retv.append([a1, a2])
  #print(i,j,retv)
  return retv

def bfs(qu):
  #includes points=[y][x], distance, parents=[[y][x]]
  used = [[-1 for _ in range(w)] for _ in range(h)]
  m = 0
  while not qu.empty():
    current = qu.get()
    row = current[0][0]
    column = current[0][1]
#    print(row, column, used[row][column])
    if used[row][column] > current[1] or used[row][column]<0:
      used[row][column] = current[1]
#      print(used)
#      print('update:', current[1])
      for a in find_possible(row, column, current[2]):
#          print('extend:',a,current[1]+1, tmp)          
        qu.put([a,current[1]+1, current[2] + [[row, column]]])
   #       if current[1]+1 > m:
   #         m = current[1]+1
#    print()
  m = 0
  return used
m = 0
cans = []
for i in range(h):
  for j in range(w):
    if d[i][j] == '#':
      continue
    q = queue.Queue()
    q.put([[i,j], 0, []])
    t = bfs(q)
    cans.append(t)
import numpy as np
m = np.array(cans)

print(np.max(m))
    

Fixed submission:
import queue
h,w=map(int,input().split())
s=[list(input()) for i in range(h)]

inf=100000000
ma=[]
for i in range(h):
    for j in range(w):
        if s[i][j]==".":
            x=[[inf for i_sub in range(w)] for j_sub in range(h)]
            #いまみているグリッド
            q=queue.Queue()
            d=0
            #初めのグリッド
            q.put([i,j])
            x[i][j]=0
            #次々にグリッドを辿って全部のグリッド辿ったら終わり
            while q.qsize()!=0:
                #距離を加算
                d+=1
                l=q.qsize()
                #今いるグリッドの数は数えておく
                for t in range(l):
                    I,J=q.get()
                    #今いるグリッドから次のグリッドへ
                    #その判定は"そこにグリッドがあるか","そこが辿れるのか","すでに辿っているのか"の三つです。
                    if I-1>=0 and s[I-1][J]=="." and x[I-1][J]==inf:
                        q.put([I-1,J])
                        #この更新をif文内で行わないと余計にグリッドを調べてしまう
                        x[I-1][J]=d
                    if I+1<=h-1 and s[I+1][J]=="." and x[I+1][J]==inf:
                        q.put([I+1,J])
                        x[I+1][J]=d
                    if J-1>=0 and s[I][J-1]=="." and x[I][J-1]==inf:
                        q.put([I,J-1])
                        x[I][J-1]=d
                    if J+1<=w-1 and s[I][J+1]=="." and x[I][J+1]==inf:
                        q.put([I,J+1])
                        x[I][J+1]=d
            ma_sub=0
            for k in range(h):
                for l in range(w):
                    if x[k][l]!=inf:
                        ma_sub=max(ma_sub,x[k][l])
            ma.append(ma_sub)

print(max(ma))

Buggy python submission (verdict: Time Limit Exceeded):
import queue
h, w = map(int, input().split())
bigger = h if h > w else w
dfs = [[0]*bigger]*bigger
q = queue.Queue
d = []
for i in range(h):
  s = [j for j in input()]
  d.append(s)
from collections import defaultdict
def find_possible(i, j):
  if i >= h-1:
    iaround = [i, i-1]
  elif i<=0:
    iaround = [i, i+1]
  else:
    iaround = [i, i-1, i+1]
  if j >= w-1:
    jaround = [j, j-1]
  elif j<=0:
    jaround = [j, j+1]
  else:
    jaround = [j, j-1, j+1]
  retv = []
  for a1 in iaround:
    for a2 in jaround:
      if abs(a1-i) == abs(a2-j):
        continue
      elif d[a1][a2] == '.':
        retv.append([a1, a2])
  #print(i,j,retv)
  return retv

def bfs(qu):
  #includes points=[y][x], distance, parents=[[y][x]]
  used = [[-1 for _ in range(w)] for _ in range(h)]
  m = 0
  while not qu.empty():
    current = qu.get()
    row = current[0][0]
    column = current[0][1]
#    print(row, column, used[row][column])
    if used[row][column] > current[1] or used[row][column]<0:
      used[row][column] = current[1]
#      print(used)
#      print('update:', current[1])
      for a in find_possible(row, column):
        if (a not in current[2]) and (a != [row, column]):
          tmp = current[2] + [[row, column]]
#          print('extend:',a,current[1]+1, tmp)          
          qu.put([a,current[1]+1, tmp])
   #       if current[1]+1 > m:
   #         m = current[1]+1
#    print()
  m = 0
  return used
m = 0
cans = []
for i in range(h):
  for j in range(w):
    if d[i][j] == '#':
      continue
    q = queue.Queue()
    q.put([[i,j], 0, []])
    t = bfs(q)
    cans.append(t)
import numpy as np
m = np.array(cans)

print(np.max(m))

Fixed submission:
import queue
h,w=map(int,input().split())
s=[list(input()) for i in range(h)]

inf=100000000
ma=[]
for i in range(h):
    for j in range(w):
        if s[i][j]==".":
            x=[[inf for i_sub in range(w)] for j_sub in range(h)]
            #いまみているグリッド
            q=queue.Queue()
            d=0
            #初めのグリッド
            q.put([i,j])
            x[i][j]=0
            #次々にグリッドを辿って全部のグリッド辿ったら終わり
            while q.qsize()!=0:
                #距離を加算
                d+=1
                l=q.qsize()
                #今いるグリッドの数は数えておく
                for t in range(l):
                    I,J=q.get()
                    #今いるグリッドから次のグリッドへ
                    #その判定は"そこにグリッドがあるか","そこが辿れるのか","すでに辿っているのか"の三つです。
                    if I-1>=0 and s[I-1][J]=="." and x[I-1][J]==inf:
                        q.put([I-1,J])
                        #この更新をif文内で行わないと余計にグリッドを調べてしまう
                        x[I-1][J]=d
                    if I+1<=h-1 and s[I+1][J]=="." and x[I+1][J]==inf:
                        q.put([I+1,J])
                        x[I+1][J]=d
                    if J-1>=0 and s[I][J-1]=="." and x[I][J-1]==inf:
                        q.put([I,J-1])
                        x[I][J-1]=d
                    if J+1<=w-1 and s[I][J+1]=="." and x[I][J+1]==inf:
                        q.put([I,J+1])
                        x[I][J+1]=d
            ma_sub=0
            for k in range(h):
                for l in range(w):
                    if x[k][l]!=inf:
                        ma_sub=max(ma_sub,x[k][l])
            ma.append(ma_sub)

print(max(ma))

Buggy python submission (verdict: Time Limit Exceeded):
import queue
h, w = map(int, input().split())
bigger = h if h > w else w
dfs = [[0]*bigger]*bigger
used_dfs = [[[]]*bigger]*bigger
q = queue.Queue
d = []
for i in range(h):
  s = [j for j in input()]
  d.append(s)
from collections import defaultdict
def find_possible(i, j):
  if i >= h-1:
    iaround = [i, i-1]
  elif i<=0:
    iaround = [i, i+1]
  else:
    iaround = [i, i-1, i+1]
  if j >= w-1:
    jaround = [j, j-1]
  elif j<=0:
    jaround = [j, j+1]
  else:
    jaround = [j, j-1, j+1]
  retv = []
  for a1 in iaround:
    for a2 in jaround:
      if abs(a1-i) == abs(a2-j):
        continue
      elif d[a1][a2] == '.':
        retv.append([a1, a2])
  #print(i,j,retv)
  return retv

def bfs(qu):
  #includes points=[y][x], distance, parents=[[y][x]]
  used = [[-1 for _ in range(w)] for _ in range(h)]
  m = 0
  while not qu.empty():
    current = qu.get()
    row = current[0][0]
    column = current[0][1]
#    print(row, column, used[row][column])
    if used[row][column] > current[1] or used[row][column]<0:
      used[row][column] = current[1]
#      print(used)
#      print('update:', current[1])
      for a in find_possible(row, column):
        if (a not in current[2]) and (a != [row, column]):
          tmp = current[2] + [[row, column]]
#          print('extend:',a,current[1]+1, tmp)          
          qu.put([a,current[1]+1, tmp])
   #       if current[1]+1 > m:
   #         m = current[1]+1
#    print()
  m = 0
  for row in used:
    for column in row:
      if column == -1:
        continue
      elif m < column:
        m = column
  return m
m = 0
for i in range(h):
  for j in range(w):
    if d[i][j] == '#':
      continue
    q = queue.Queue()
    q.put([[i,j], 0, []])
    t = bfs(q)
    if m < t:
      m = t
print(m)
    

Fixed submission:
import queue
h,w=map(int,input().split())
s=[list(input()) for i in range(h)]

inf=100000000
ma=[]
for i in range(h):
    for j in range(w):
        if s[i][j]==".":
            x=[[inf for i_sub in range(w)] for j_sub in range(h)]
            #いまみているグリッド
            q=queue.Queue()
            d=0
            #初めのグリッド
            q.put([i,j])
            x[i][j]=0
            #次々にグリッドを辿って全部のグリッド辿ったら終わり
            while q.qsize()!=0:
                #距離を加算
                d+=1
                l=q.qsize()
                #今いるグリッドの数は数えておく
                for t in range(l):
                    I,J=q.get()
                    #今いるグリッドから次のグリッドへ
                    #その判定は"そこにグリッドがあるか","そこが辿れるのか","すでに辿っているのか"の三つです。
                    if I-1>=0 and s[I-1][J]=="." and x[I-1][J]==inf:
                        q.put([I-1,J])
                        #この更新をif文内で行わないと余計にグリッドを調べてしまう
                        x[I-1][J]=d
                    if I+1<=h-1 and s[I+1][J]=="." and x[I+1][J]==inf:
                        q.put([I+1,J])
                        x[I+1][J]=d
                    if J-1>=0 and s[I][J-1]=="." and x[I][J-1]==inf:
                        q.put([I,J-1])
                        x[I][J-1]=d
                    if J+1<=w-1 and s[I][J+1]=="." and x[I][J+1]==inf:
                        q.put([I,J+1])
                        x[I][J+1]=d
            ma_sub=0
            for k in range(h):
                for l in range(w):
                    if x[k][l]!=inf:
                        ma_sub=max(ma_sub,x[k][l])
            ma.append(ma_sub)

print(max(ma))