CodeEff/ECCO huggingface dataset:
# Original solution
import sys

stdin = sys.stdin
inf = 1 << 60
mod = 1000000007

ni      = lambda: int(ns())
nin     = lambda y: [ni() for _ in range(y)]
na      = lambda: list(map(int, stdin.readline().split()))
nan     = lambda y: [na() for _ in range(y)]
nf      = lambda: float(ns())
nfn     = lambda y: [nf() for _ in range(y)]
nfa     = lambda: list(map(float, stdin.readline().split()))
nfan    = lambda y: [nfa() for _ in range(y)]
ns      = lambda: stdin.readline().rstrip()
nsn     = lambda y: [ns() for _ in range(y)]
ncl     = lambda y: [list(ns()) for _ in range(y)]
nas     = lambda: stdin.readline().split()

from collections import deque

h, w = na()
maze = nsn(h)

def bfs(sx, sy):
    q = deque()
    q.append((sx, sy))
    dist = [[inf] * w for _ in range(h)]
    dist[sy][sx] = 0
    dx, dy = [1, 0, 0, -1], [0, 1, -1, 0]
    res = 0
    while len(q):
        p = q.popleft()
        cx, cy = p
        for i in range(4):
            nx, ny = cx + dx[i], cy + dy[i]
            if nx < 0 or nx >= w:
                continue
            if ny < 0 or ny >= h:
                continue
            if dist[ny][nx] != inf:
                continue
            if maze[ny][nx] == '#':
                continue
            update = dist[cy][cx] + 1
            dist[ny][nx] = update
            res = max(res, update)
            q.append((nx, ny))
    
    return res

ans = 0

for y in range(h):
    for x in range(w):
        if maze[y][x] == '#':
            continue
        ans = max(ans, bfs(x, y))

print(ans)

# Optimized solution
import sys

stdin = sys.stdin
inf = 1 << 60
mod = 1000000007

ni      = lambda: int(ns())
nin     = lambda y: [ni() for _ in range(y)]
na      = lambda: list(map(int, stdin.readline().split()))
nan     = lambda y: [na() for _ in range(y)]
nf      = lambda: float(ns())
nfn     = lambda y: [nf() for _ in range(y)]
nfa     = lambda: list(map(float, stdin.readline().split()))
nfan    = lambda y: [nfa() for _ in range(y)]
ns      = lambda: stdin.readline().rstrip()
nsn     = lambda y: [ns() for _ in range(y)]
ncl     = lambda y: [list(ns()) for _ in range(y)]
nas     = lambda: stdin.readline().split()

from collections import deque

h, w = na()
maze = nsn(h)

def bfs(sx, sy):
    q = deque()
    q.append((sx, sy))
    dist = [[inf] * w for _ in range(h)]
    dist[sy][sx] = 0
    dx, dy = [1, 0, 0, -1], [0, 1, -1, 0]
    res = 0
    while len(q):
        p = q.popleft()
        cx, cy = p
        for i in range(4):
            nx, ny = cx + dx[i], cy + dy[i]
            if nx < 0 or nx >= w:
                continue
            if ny < 0 or ny >= h:
                continue
            if dist[ny][nx] != inf:
                continue
            if maze[ny][nx] == '#':
                continue
            update = dist[cy][cx] + 1
            dist[ny][nx] = update
            res = max(res, update)
            q.append((nx, ny))
    
    return res

def main():
    ans = 0

    for y in range(h):
        for x in range(w):
            if maze[y][x] == '#':
                continue
            ans = max(ans, bfs(x, y))

    print(ans)

if __name__ == '__main__':
    main()
# Original solution
h, w = list(map(int, input().split()))
maze = [list(input()) for i in range(h)]

INF = 10 ** 10
my = [-1, 0, 1, 0]
mx = [0, -1, 0, 1]
def bfs(sy, sx, ey, ex):
    q = [(sy, sx)]
    dp = [ [INF for j in range(w)] for i in range(h) ]
    dp[sy][sx] = 0
    while q:
        (y, x) = q.pop(0)
        if (y, x) == (ey, ex):
            break
        for (dy, dx) in zip(my, mx):
            ny = y + dy
            nx = x + dx
            if ny < 0 or nx < 0 or ny >= h or nx >= w:
                continue
            if maze[ny][nx] == '#':
                continue
            if dp[ny][nx] != INF:
                continue
            dp[ny][nx] = dp[y][x] + 1
            q.append((ny, nx))
    res = dp[ey][ex]
    assert res < INF
    return res

res = 0
for sy in range(h):
    for sx in range(w):
        if maze[sy][sx] == '#':
            continue
        for ey in range(h):
            for ex in range(w):
                if maze[ey][ex] == '#':
                    continue
                res = max(res, bfs(sy, sx, ey, ex))
print(res)


# Optimized solution
h, w = list(map(int, input().split()))
maze = [list(input()) for i in range(h)]

INF = 10 ** 10
my = [-1, 0, 1, 0]
mx = [0, -1, 0, 1]
def bfs(sy, sx):
    q = [(sy, sx)]
    dp = [ [INF for j in range(w)] for i in range(h) ]
    dp[sy][sx] = 0
    while q:
        (y, x) = q.pop(0)
        for (dy, dx) in zip(my, mx):
            ny = y + dy
            nx = x + dx
            if ny < 0 or nx < 0 or ny >= h or nx >= w:
                continue
            if maze[ny][nx] == '#':
                continue
            if dp[ny][nx] != INF:
                continue
            dp[ny][nx] = dp[y][x] + 1
            q.append((ny, nx))
    res = 0
    for i in range(h):
        for j in range(w):
            if maze[i][j] != '#':
                res = max(res, dp[i][j])
    return res

res = 0
for sy in range(h):
    for sx in range(w):
        if maze[sy][sx] == '#':
            continue
        res = max(res, bfs(sy, sx))
print(res)
# Original solution
h,w=list(map(int,input().split()))
s = [[0]*w for _ in range(h)]
for i in range(h):
    s[i] = list(*input().split())

def cango(now,h,w):
    ans = []
    if now[0]>0:
        ans.append( (now[0]-1,now[1]) )
    if now[0]<h-1:
        ans.append( (now[0]+1,now[1]) )
    if now[1]>0:
        ans.append( (now[0],now[1]-1) )
    if now[1]<w-1:
        ans.append( (now[0],now[1]+1) )
    return ans

from collections import deque

ans=0
for hh in range(h):
    for ww in range(w):
        if s[hh][ww]==".":
            start = (hh,ww)
            q = deque( [] )
            q.append( ((-1,-1),start,0) )
            visit = [[0]*w for _ in range(h)]
            while q:
                old,now,dist = q.popleft()
                visit[now[0]][now[1]] = 1
#                 print(old,now,dist)
                if ans<dist:
                    ans=dist
                for new in cango(now,h,w):
                    if s[new[0]][new[1]]=="." and visit[new[0]][new[1]]==0:
                        q.append( (now,new,dist+1) )
print(ans )
    

# Optimized solution
h,w=list(map(int,input().split()))
s = [[0]*w for _ in range(h)]
for i in range(h):
    s[i] = list(*input().split())

def cango(now,h,w):
    ans = []
    if now[0]>0:
        ans.append( (now[0]-1,now[1]) )
    if now[0]<h-1:
        ans.append( (now[0]+1,now[1]) )
    if now[1]>0:
        ans.append( (now[0],now[1]-1) )
    if now[1]<w-1:
        ans.append( (now[0],now[1]+1) )
    return ans

from collections import deque

ans=0
for hh in range(h):
    for ww in range(w):
        if s[hh][ww]==".":
            start = (hh,ww)
            q = deque( [] )
            q.append( ((-1,-1),start,0) )
            visit = [[0]*w for _ in range(h)]
            visit[hh][ww]=1
            while q:
                old,now,dist = q.popleft()
#                 print(old,now,dist)
                if ans<dist:
                    ans=dist
                for new in cango(now,h,w):
                    if s[new[0]][new[1]]=="." and visit[new[0]][new[1]]==0:
                        q.append( (now,new,dist+1) )
                        visit[new[0]][new[1]] = 1
print(ans )
# Original solution
# -*- coding: utf-8 -*-
import sys
from collections import deque
from collections import defaultdict
 
H,W=list(map(int, sys.stdin.readline().split()))
S=[ sys.stdin.readline().strip() for _ in range(H) ]
 
D=[(1,0),(-1,0),(0,1),(0,-1)]
 
def bfs(start):
    Visit={}
    q=deque()
    q.append(start)
    L=defaultdict(lambda: float("inf")) 
    L[start]=0
 
    while q:
        fro_x,fro_y=q.popleft()
        for dx,dy in D:
            to_x=fro_x+dx
            to_y=fro_y+dy
            alt=L[(fro_x,fro_y)]+1
            if 0<=to_x<H and 0<=to_y<W:
                if S[to_x][to_y]=="." and alt<L[(to_x,to_y)]:
                    L[(to_x,to_y)]=alt
                    q.append((to_x,to_y))
    return max(L.values())
 
ans=0
for h in range(H):
    for w in range(W):
        if S[h][w]==".":
            ans=max(ans,bfs((h,w)))
print(ans)


# Optimized solution
# -*- coding: utf-8 -*-
import sys
from collections import deque
from collections import defaultdict
 
H,W=list(map(int, sys.stdin.readline().split()))
S=[ sys.stdin.readline().strip() for _ in range(H) ]
 
D=[(1,0),(-1,0),(0,1),(0,-1)]
 
def bfs(start):
    Visit={}
    q=deque()
    q.append(start)
    Visit[start]=1
    L=defaultdict(lambda: float("inf"))    #距離
    L[start]=0
 
    while q:
        fro_x,fro_y=q.popleft()
        for dx,dy in D:
            to_x=fro_x+dx
            to_y=fro_y+dy
            if 0<=to_x<H and 0<=to_y<W:
                if S[to_x][to_y]=="." and (to_x,to_y) not in Visit:
                    Visit[to_x,to_y]=1
                    L[(to_x,to_y)]=min(L[(to_x,to_y)],L[(fro_x,fro_y)]+1)
                    q.append((to_x,to_y))
    if len(list(L.values()))==0:
        return 0
    else:
        return max(L.values())
 
ans=0
for h in range(H):
    for w in range(W):
        if S[h][w]==".":
            ans=max(ans,bfs((h,w)))
 
print(ans)
# Original solution
# -*- coding: utf-8 -*-
import sys
from collections import deque
from collections import defaultdict
 
H,W=list(map(int, sys.stdin.readline().split()))
S=[ sys.stdin.readline().strip() for _ in range(H) ]
 
D=[(1,0),(-1,0),(0,1),(0,-1)]
 
def bfs(start):
    Visit={}
    q=deque()
    q.append(start)
    Visit[start]=1
    L=defaultdict(lambda: float("inf"))    #距離
    L[start]=0
 
    while q:
        fro_x,fro_y=q.popleft()
        for dx,dy in D:
            to_x=fro_x+dx
            to_y=fro_y+dy
            if 0<=to_x<H and 0<=to_y<W:
                if S[to_x][to_y]=="." and (to_x,to_y) not in Visit:
                    Visit[to_x,to_y]=1
                    L[(to_x,to_y)]=min(L[(to_x,to_y)],L[(fro_x,fro_y)]+1)
                    q.append((to_x,to_y))
    if len(list(L.values()))==0:
        return 0
    else:
        return max(L.values())
 
ans=0
for h in range(H):
    for w in range(W):
        if S[h][w]==".":
            ans=max(ans,bfs((h,w)))
 
print(ans)

# Optimized solution
# -*- coding: utf-8 -*-
import sys
from collections import deque
from collections import defaultdict

H,W=list(map(int, sys.stdin.readline().split()))
S=[ sys.stdin.readline().strip() for _ in range(H) ]

D=[(1,0),(-1,0),(0,1),(0,-1)]

def bfs(start):
    Visit={}
    q=deque()
    q.append(start)
    Visit[start]=1
    L=defaultdict(lambda: 0)    #距離

    while q:
        fro_x,fro_y=q.popleft()
        for dx,dy in D:
            to_x=fro_x+dx
            to_y=fro_y+dy
            if 0<=to_x<H and 0<=to_y<W:
                if S[to_x][to_y]=="." and (to_x,to_y) not in Visit:
                    Visit[to_x,to_y]=1
                    L[(to_x,to_y)]=L[(fro_x,fro_y)]+1
                    q.append((to_x,to_y))

    return max(L.values())

ans=0
for h in range(H):
    for w in range(W):
        if S[h][w]==".":
            ans=max(ans,bfs((h,w)))

print(ans)
# Original solution
from collections import deque
import sys
read = sys.stdin.read
readline = sys.stdin.readline
readlines = sys.stdin.readlines

def bfs(field, sx, sy, gx, gy, seen):
    queue = deque([(sx, sy)])
    seen[sx][sy] += 1
    
    while queue:
        x, y = queue.popleft()
        if (x, y) == (gx, gy):
            return seen[x][y]

        for dx, dy in [(-1, 0), (0, 1), (1, 0), (0, -1)]:
            nx = x + dx
            ny = y + dy
            
            if seen[nx][ny] == -1 and field[nx][ny] != "#":
                seen[nx][ny] = seen[x][y] + 1
                queue.append((nx, ny))


def main():
    H,W = list(map(int, readline().split()))
    c = ["#" * (W + 2)]
    for _ in range(H):
        c.append("#" + readline().strip() + "#")
    c.append("#" * (W + 2))

    ans = 0
    for sx in range(1,H+1):
        for sy in range(1,W+1):
            if c[sx][sy] == "#":
                continue
            for gx in range(sx,H+1):
                for gy in range(1,W+1):
                    if c[gx][gy] == "#":
                        continue
                    seen = [[-1] * (W + 2) for i in range(H+2)]
                    dist = bfs(c, sx, sy, gx, gy, seen)
                    ans = max(ans, dist)

    print(ans)


if __name__ == "__main__":
    main()


# Optimized solution
from collections import deque
import sys
read = sys.stdin.read
readline = sys.stdin.readline
readlines = sys.stdin.readlines

def bfs(field, sx, sy, seen):
    queue = deque([(sx, sy)])
    seen[sx][sy] += 1
    
    while queue:
        x, y = queue.popleft()

        for dx, dy in [(-1, 0), (0, 1), (1, 0), (0, -1)]:
            nx = x + dx
            ny = y + dy
            
            if seen[nx][ny] == -1 and field[nx][ny] != "#":
                seen[nx][ny] = seen[x][y] + 1
                queue.append((nx, ny))

    return seen[x][y]


def main():
    H,W = list(map(int, readline().split()))
    c = ["#" * (W + 2)]
    for _ in range(H):
        c.append("#" + readline().strip() + "#")
    c.append("#" * (W + 2))

    ans = 0
    for sx in range(1,H+1):
        for sy in range(1,W+1):
            if c[sx][sy] == ".":
                seen = [[-1] * (W + 2) for i in range(H+2)]
                dist = bfs(c, sx, sy, seen)
                ans = max(ans, dist)

    print(ans)


if __name__ == "__main__":
    main()
# Original solution
from collections import deque
h,w = list(map(int, input().split()))
grid = []
for i in range(h):
    s = list(input().rstrip())
    grid.append(s)
dxdy = [[0, 1], [1,0], [-1, 0], [0, -1]]
visited = [[0]*w for _ in range(h)]
dist = [[0]*w for _ in range(h)]
for i in range(h):
    for j in range(w):
        if grid[i][j]==".":
            y = i
            x = j
            break

que=deque()
que.append([x,y])
while que:
    v=que.popleft()
    x = v[0]
    y = v[1]
    visited[y][x]=1
    for i in dxdy:
        dx = i[0]
        dy = i[1]
        if((x+dx<w and y+dy<h) and ((x+dx)>-1)and(y+dy)>-1) and not visited[y+dy][x+dx]:
            dist[y+dy][x+dx]=dist[y][x]+1
            que.append([x+dx, y+dy])
max_dist = [0, []]
def max1(a,b):
    if a[0]>b[0]:
        return a
    else:
        return b
for i in range(h):
    for j in range(w):
        max_dist = max1(max_dist, [dist[i][j], i,j])
visited = [[0]*w for _ in range(h)]
dist = [[0]*w for _ in range(h)]

que2 = deque()
que2.append([max_dist[2], max_dist[1]])
while que2:
    v=que2.popleft()
    x = v[0]
    y = v[1]
    visited[y][x]=1
    for i in dxdy:
        dx = i[0]
        dy = i[1]
        if((x+dx<w and y+dy<h) and ((x+dx)>-1)and(y+dy)>-1) and not visited[y+dy][x+dx] and grid[y+dy][x+dx]==".":
            dist[y+dy][x+dx]=dist[y][x]+1
            que2.append([x+dx, y+dy])
for i in range(h):
    for j in range(w):
        max_dist = max1(max_dist, [dist[i][j], i,j])
print((max_dist[0]))


# Optimized solution
from collections import deque

h,w = list(map(int, input().split()))
grid = []
for i in range(h):
    s = list(input().rstrip())
    grid.append(s)
dydx = [[0, 1], [1,0], [-1, 0], [0, -1]]

def find_longest_path(xy):
    visited = [[0]*w for _ in range(h)]
    dist = [[0]*w for _ in range(h)]
    visited[xy[1]][xy[0]]=1
    que = deque()
    que.append(xy)
    while que:
        v = que.popleft()
        x,y = v[0],v[1]
        for i in dydx:
            dx = i[0]
            dy = i[1]
            if ((x+dx<w and y+dy<h) and ((x+dx)>-1)and(y+dy)>-1) and not visited[y+dy][x+dx]:
                if(grid[y+dy][x+dx]=="."):
                    que.append([x+dx, y+dy])
                    visited[y+dy][x+dx]=1
                    dist[y+dy][x+dx]=dist[y][x]+1
                    u,k = x+dx, y+dy
                    r = dist[y+dy][x+dx]

    return r

def main():
    k=0
    for i in range(h):
        for j in range(w):
            if grid[i][j]==".":
                k = max(k, find_longest_path([j,i]))
    print(k)

if __name__ == '__main__':
    main()
# Original solution
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
sys.setrecursionlimit(10 ** 7)

from copy import deepcopy

h, w = list(map(int, readline().split()))
s = [readline().rstrip().decode() for _ in range(h)]
move = [(0, 1), (0, -1), (1, 0), (-1, 0)]
sg = []
memo = [[False] * w for _ in range(h)]
for i in range(h):
    for j in range(w):
        if s[i][j] == '.':
            sg.append((i, j))
        else:
            memo[i][j] = True
ans = 0
for ss in sg:
    for g in sg:
        if ss == g:
            continue
        q = [ss]
        cnt = 0
        dist = deepcopy(memo)
        dist[ss[0]][ss[1]] = True
        while q:
            cnt += 1
            qq = []
            for y, x in q:
                for dy, dx in move:
                    xx, yy = x + dx, y + dy
                    if xx < 0 or yy > h - 1 or yy < 0 or xx > w - 1:
                        continue
                    if dist[yy][xx]:
                        continue
                    dist[yy][xx] = True
                    qq.append((yy, xx))
            q = qq
            if g in q:
                ans = max(ans, cnt)
                break
print(ans)


# Optimized solution
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
sys.setrecursionlimit(10 ** 7)

from copy import deepcopy

h, w = list(map(int, readline().split()))
s = [readline().rstrip().decode() for _ in range(h)]
move = [(0, 1), (0, -1), (1, 0), (-1, 0)]
sg = []
memo = [[False] * w for _ in range(h)]
for i in range(h):
    for j in range(w):
        if s[i][j] == '.':
            sg.append((i, j))
        else:
            memo[i][j] = True
ans = 0
for ss in sg:
    q = [ss]
    cnt = 0
    dist = deepcopy(memo)
    dist[ss[0]][ss[1]] = True
    while q:
        cnt += 1
        qq = []
        for y, x in q:
            for dy, dx in move:
                xx, yy = x + dx, y + dy
                if xx < 0 or yy > h - 1 or yy < 0 or xx > w - 1:
                    continue
                if dist[yy][xx]:
                    continue
                dist[yy][xx] = True
                qq.append((yy, xx))
        q = qq
    ans = max(ans, cnt - 1)
print(ans)
# Original solution
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
from collections import deque 
INF = 100000
dir = ((1, 0), (-1, 0), (0, 1), (0, -1)) 
def main():
    H, W = list(map(int, readline().split()))
    maze = []
    for _ in range(H):
        s = readline().rstrip().decode()
        maze.append(s) 
    
    
    def bfs(si, sj):
        dq = deque()
        dq.append((si, sj))        
        dist = [[INF for _ in range(W)] for _ in range(H)]
        dist[si][sj] = 0
        while len(dq)>0:
            i, j = dq.popleft()
            for di, dj in dir:
                nxi = i+di
                nxj = j+dj
                if (nxi<0) or (nxj<0) or (nxi>=H) or (nxj>=W):
                    continue
                if maze[nxi][nxj] == '#':
                    continue
                if dist[nxi][nxj] != INF:
                    continue
                dist[nxi][nxj] = dist[i][j]+1
                dq.append((nxi, nxj))
        res = 0
        for i in range(H):
            for j in range(W):
                if dist[i][j] == INF:
                    continue
                res = max(dist[i][j], res)        
        return res

    ans = 0
    for si in range(H):
        for sj in range(W):
            if maze[si][sj] == '#':
                continue
            ans = max(bfs(si, sj), ans)

    print(ans)

if __name__ == '__main__':
    main()


# Optimized solution
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines

from collections import deque 
dir = ((-1, 0), (1, 0), (0, -1), (0, 1))
def main():
    h, w = list(map(int, readline().split()))
    grid = []
    for _ in range(h):
        grid.append(readline().rstrip().decode())

    INF = int(1e9)
    mx = 0
    for si in range(h):
        for sj in range(w):
            if grid[si][sj] == '#':
                continue            
            dq = deque()
            dq.append((si, sj))
            dist = [[-1 for _ in range(w)] for _ in range(h)]
            dist[si][sj] = 0
            while len(dq) > 0:
                ni, nj = dq.popleft()
                for d in dir:
                    x, y = ni+d[0], nj+d[1]
                    if (x < 0) or (y < 0) or (x >= h) or (y >= w):
                        continue
                    if grid[x][y] == '#':
                        continue
                    if dist[x][y] != -1:
                        continue 
                    dist[x][y] = dist[ni][nj]+1 
                    dq.append((x, y))

            for i in range(h):
                for j in range(w):
                    if dist[i][j] == -1: 
                        continue
                    mx = max(mx, dist[i][j])
    print(mx)
if __name__ == '__main__':
    main()
# Original solution
import copy
from collections import deque
 
H, W = list(map(int, input().split()))
field_s = []
 
# フィールドを作る
for h in range(H + 2):
    field_s.append(["#"] * (W + 2))
    if 1 <= h <= (H):
        field_s[h][1:-1] = list(map(str, input().rstrip()))
 
# 動き方のセットを準備
moves = [[1, 0], [-1, 0], [0, 1], [0, -1]]
 
# スタートとゴールの座標の組み合わせを作成
sg = []
for y in range(H + 2):
    for x in range(W + 2):
        if field_s[y][x] == ".":
            sg.append([y, x])
 
# 答え
ans = 0
 
# スタートとゴールの座標を組み合わせてぐるぐる
for s in sg:
    for g in sg:
 
        # startとgoalの座標が同じならスキップ
        if s == g:
            continue
 
        # fieldの初期化
        field = copy.deepcopy(field_s)
 
        # startをキューに追加
        que = deque([s])
 
        # startの距離は0に
        field[s[0]][s[1]] = 0
 
        # キューに何かがある限り探索を続ける
        while que:
            c = que.popleft()
 
            # 今の距離
            dist = field[c[0]][c[1]]
 
            # 動いた先が「.」なら、距離を記録してキューに追加
            for m in moves:
                my = c[0] + m[0]
                mx = c[1] + m[1]
 
                if field[my][mx] == ".":
                    field[my][mx] = dist + 1
                    que.append([my, mx])
                else:
                    continue
 
                # もしゴールに到達していたらansを差し替えてbreak
                if [my, mx] == g:
                    ans = max(ans, field[my][mx])
                    break
 
print(ans)

# Optimized solution
import copy
from collections import deque

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

# フィールドを作る
for h in range(H + 2):
    field_s.append(["#"] * (W + 2))
    if 1 <= h <= (H):
        field_s[h][1:-1] = list(map(str, input().rstrip()))

#　動き方のセットを準備
moves = [[1, 0], [-1, 0], [0, 1], [0, -1]]

# スタート座標を取得
start = []
for y in range(1, H + 1):
    for x in range(1, W + 1):
        if field_s[y][x] == ".":
            start.append([y, x])

# 答え
ans = 0

for s in start:

    # fieldの初期化
    field = copy.deepcopy(field_s)

    # startをキューに追加
    que = deque([s])

    # startの距離は0に
    field[s[0]][s[1]] = 0

    # キューに何かがある限り探索を続ける
    while que:
        c = que.popleft()

        # 今の距離
        dist = field[c[0]][c[1]]

        # 動いた先が「.」なら、距離を記録してキューに追加
        for m in moves:
            my = c[0] + m[0]
            mx = c[1] + m[1]

            if field[my][mx] == ".":
                field[my][mx] = dist + 1
                que.append([my, mx])
            else:
                continue
    
    # キューを消化したら最大値を取り出す
    field = sum(field, [])
    ans = max(ans, max([x for x in field if type(x)==int]))

print(ans)