#include<bits/stdc++.h>
 #include <ext/pb_ds/tree_policy.hpp>
 #include <ext/pb_ds/assoc_container.hpp>
 #include<chrono>
 using namespace std;
 using namespace std::chrono;      
 using namespace __gnu_pbds; 
 #define fastio     ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)
 #define fi         first
 #define se         second
#define int         long long 
 #define pb         push_back
 #define emp        emplace_back
 #define vv(x)      vector<x>
 #define mp(x,y)    map<x,y>
 #define dq(x)      deque<x>
 #define pql(x)     priority_queue<x>
 #define pqs(x)     priority_queue<x,vv(x),greater<x> >
 #define M          1000000007
 #define forf(i,a,b) for(int i=a;i<b;i++)
 #define it(x)      x::iterator
 #define ll         long long 
 #define debug(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
 #define time__(d)  for(long blockTime = 0; (blockTime == 0 ? (blockTime=clock()) != 0 : false); debug("%s time : %.4fs", d, (double)(clock() - blockTime) / CLOCKS_PER_SEC))
 #define vii        vector<int>
 #define big        1e18
 #define sm         -1e18
 #define mkr        make_pair
 #define vpi        vector<pair<int,int> >
 #define pii        pair<int,int>
 #define rng        500005
 #define sz(x)      (int)x.size()
 #define rv(x)      reverse(x.begin(),x.end())
 #define out(x)     cout<<x.fi<<" "<<x.se<<endl;

//#define ordered_set tree<pii, null_type,less<pii>, rb_tree_tag,tree_order_statistics_node_update> 
  
void pr_init()
{
   
    #ifndef ONLINE_JUDGE
    freopen("gin.txt", "r", stdin);
    freopen("gout.txt", "w", stdout);
   
    #endif
}


char mat[21][21];
int dis[21][21],h,w;

int min_dis(int x1,int y1,int x2,int y2)
{

  forf(i,0,21)
  {
    forf(j,0,21) dis[i][j] = big;
  }

  queue<pii>nd;

  nd.push({x1,y1});
  dis[x1][y1] = 0;

  while(sz(nd))
  {
    pii cur = nd.front();
    nd.pop();
    if(cur.fi + 1 < h && mat[cur.fi+1][cur.se]!='#' &&dis[cur.fi+1][cur.se] > dis[cur.fi][cur.se]+1) nd.push({cur.fi+1,cur.se}) , dis[cur.fi+1][cur.se] = dis[cur.fi][cur.se]+1;
    if(cur.fi - 1 >= 0 && mat[cur.fi-1][cur.se]!='#'&&dis[cur.fi-1][cur.se] > dis[cur.fi][cur.se]+1) nd.push({cur.fi-1,cur.se}) , dis[cur.fi-1][cur.se] = dis[cur.fi][cur.se]+1;
    if(cur.se + 1 < w && mat[cur.fi][cur.se+1]!='#'&&dis[cur.fi][cur.se+1] > dis[cur.fi][cur.se]+1) nd.push({cur.fi,cur.se+1}) , dis[cur.fi][cur.se+1] = dis[cur.fi][cur.se]+1;
    if(cur.se - 1 >= 0 && mat[cur.fi][cur.se-1]!='#'&&dis[cur.fi][cur.se-1] > dis[cur.fi][cur.se]+1) nd.push({cur.fi,cur.se-1}) , dis[cur.fi][cur.se-1] = dis[cur.fi][cur.se]+1;
  }



  if(dis[x2][y2] >= big) return -1;

  return dis[x2][y2];

}
void solve()
{
 
  cin >> h >> w;
  
  forf(i,0,h) forf(j,0,w)
  {
    cin >> mat[i][j];
  }
  
  int an = -1;
  forf(i,0,h)
  {
    forf(j,0,w)
    {
      forf(x,0,h)
      {
        forf(y,0,w)
        if((i!=x || j!=y) && mat[i][j]!='#' && mat[x][y]!='#')
        {
          //cout<<i<<" "<<j<<" "<<x<<" "<<y<<" "<<min_dis(i,j,x,y)<<endl;
          an = max(an,min_dis(i,j,x,y));
        }
      }
    }
  }

  cout << an <<"\n";
}


int32_t main()
{
  pr_init();
  fastio;
  
  auto start = high_resolution_clock::now(); 
 
  solve();
  auto stop = high_resolution_clock::now();
  auto duration = duration_cast<microseconds>(stop - start); 
   // cout << "Time taken by function: "
   //       << duration.count() << " microseconds" << endl; 

 }
      
      

Measured memory_bytes: 3628