#include "bits/stdc++.h"
using namespace std;
#ifdef LOCAL
#define debug(x)   cerr<<#x<<" = "<<x<<endl
#else
#define debug(x) 
#endif
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define input_from_file freopen("input.txt","r",stdin)
#define output_to_file freopen("output.txt" , "w",stdout)
#define pii pair<int,int>
#define endl '\n'
#define pb push_back
#define fi first
#define se second 
#define mp make_pair
#define int long long
const int inf = 1e18 + 5;
struct Point 
{ 
    int x; 
    int y; 
}; 
int ROW,COL;
  char mat[21][21];
// A Data Structure for queue used in BFS 
struct queueNode 
{ 
    Point pt;  // The cordinates of a cell 
    int dist;  // cell's distance of from the source 
}; 
  
// check whether given cell (row, col) is a valid 
// cell or not. 
bool isValid(int row, int col) 
{ 
    // return true if row number and column number 
    // is in range 
    return (row >= 0) && (row < ROW) && 
           (col >= 0) && (col < COL); 
} 
  
// These arrays are used to get row and column 
// numbers of 4 neighbours of a given cell 
int rowNum[] = {-1, 0, 0, 1}; 
int colNum[] = {0, -1, 1, 0}; 
  
// function to find the shortest path between 
// a given source cell to a destination cell. 
int BFS(Point src, Point dest) 
{ 
    // check source and destination cell 
    // of the matrix have value 1 
    if (mat[src.x][src.y] == '#' || mat[dest.x][dest.y] == '#') 
        return -1; 
  
    bool visited[ROW][COL]; 
    memset(visited, false, sizeof visited); 
      
    // Mark the source cell as visited 
    visited[src.x][src.y] = true; 
  
    // Create a queue for BFS 
    queue<queueNode> q; 
      
    // Distance of source cell is 0 
    queueNode s = {src, 0}; 
    q.push(s);  // Enqueue source cell 
  
    // Do a BFS starting from source cell 
    while (!q.empty()) 
    { 
        queueNode curr = q.front(); 
        Point pt = curr.pt; 
  
        // If we have reached the destination cell, 
        // we are done 
        if (pt.x == dest.x && pt.y == dest.y) 
            return curr.dist; 
  
        // Otherwise dequeue the front cell in the queue 
        // and enqueue its adjacent cells 
        q.pop(); 
  
        for (int i = 0; i < 4; i++) 
        { 
            int row = pt.x + rowNum[i]; 
            int col = pt.y + colNum[i]; 
              
            // if adjacent cell is valid, has path and 
            // not visited yet, enqueue it. 
            if (isValid(row, col) && mat[row][col] == '.' &&  
               !visited[row][col]) 
            { 
                // mark cell as visited and enqueue it 
                visited[row][col] = true; 
                queueNode Adjcell = { {row, col}, 
                                      curr.dist + 1 }; 
                q.push(Adjcell); 
            } 
        } 
    } 
  
    // Return -1 if destination cannot be reached 
    return -1; 
} 
signed main()
{
    #ifdef LOCAL
        input_from_file;
        output_to_file;
    #endif 
    IOS
    cin>>ROW>>COL;
    int n = ROW,m = COL;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++) cin>>mat[i][j];
    int ans = 0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            Point src = {i,j};
            for(int id = 0;id<n;id++)
            {
                for(int jd = 0;jd<m;jd++)
                {
                    Point des = {id,jd};
                    int dist = BFS( src, des); 
                    if(dist != INT_MAX) ans = max(ans,dist);
                }
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

Measured memory_bytes: 384