#include<bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>

#define int  long long
#define rep(i,begin,end) for(__typeof(end)i=(begin)-((begin)>(end));i!=(end)-((begin)>(end));i+=1-2*((begin)>(end)))
#define F first
#define S second
#define sz(x) ((int)x.size())
#define pb push_back
#define pf push_front
#define eb emplace_back 
#define all(v) (v).begin(), (v).end()
#define mod 1000000007
#define what_is(x) cerr << #x << " is " << x <<"\n";
#define sortA(v) sort(v.begin(), v.end())
#define sortD(v) sort(v.rbegin(), v.rend())
#define PI 3.14159265358979323846
#define vout(a) for(auto x:a) cout<<x<<" ";
#define INF 10000000000000000

// #define ordered_set tree<ll, null_type, less<ll>, rb_tree_tag, tree_order_statistics_node_update>


// using namespace __gnu_pbds;
using namespace std;

using ll  = long long;
using vi  = vector<int>;
using pii = pair<int,int>;
using vii = vector<pii>;
using mi  = multiset<int>;
using mii = multiset<pii>;

int lcm(int a,int b) {return (a*(b/__gcd(a,b)));}

int n,m;
char maze[50][50];
int vis[50][50],level1[50][50],level2[50][50];

bool ok(int i,int j)
{
    if(i>=0&&i<n&&j>=0&&j<m) return true;
    return false;
}

void dfs(int i,int j)
{
    vis[i][j]=true;
    // cout<<i<<" "<<j<<"\n";
    if(!vis[i+1][j]&&ok(i+1,j))
    {
        level1[i+1][j]=level1[i][j]+1;
        vis[i+1][j]=1;
        dfs(i+1,j);        
    }
    if(!vis[i-1][j]&&ok(i-1,j))
    {
        level1[i-1][j]=level1[i][j]+1;
        vis[i-1][j]=1;
        dfs(i-1,j);
    }
    if(!vis[i][j+1]&&ok(i,j+1))
    {
        level1[i][j+1]=level1[i][j]+1;
        vis[i][j+1]=1;
        dfs(i,j+1);
    }
    if(!vis[i][j-1]&&ok(i,j-1))
    {
        level1[i][j-1]=level1[i][j]+1;
        vis[i][j-1]=1;
        dfs(i,j-1);
    }
}

void dfs1(int i,int j)
{
    vis[i][j]=true;
    if(!vis[i+1][j]&&ok(i+1,j))
    {
        level2[i+1][j]=level2[i][j]+1;
        dfs1(i+1,j);
    }
    if(!vis[i-1][j]&&ok(i-1,j))
    {
        level2[i-1][j]=level2[i][j]+1;
        dfs1(i-1,j);
    }
    if(!vis[i][j+1]&&ok(i,j+1))
    {
        level2[i][j+1]=level2[i][j]+1;
        dfs1(i,j+1);
    }
    if(!vis[i][j-1]&&ok(i,j-1))
    {
        level2[i][j-1]=level2[i][j]+1;
        dfs1(i,j-1);
    }
}

void solve()
{
    int t,i,k,r,l,u,v,w,j,s,sum=0,pos,flag=0,count=0;
    string S,T,U;
    // int x;
    cin>>n>>m;
    rep(i,0,n)
    {
        rep(j,0,m) 
        {
            cin>>maze[i][j];
            vis[i][j]=0;
            if(maze[i][j]=='#')
            {
                vis[i][j]=1;
                level1[i][j]=-1;
                level2[i][j]=-1;
            }
            else 
            {
                u=i;
                v=j;
            }
        }
    }
    level1[u][v]=0;
    vis[u][v]=1;
    queue<pii> q;
    q.push({u,v});
    while(!q.empty())
    {
        pii tmp=q.front();
        q.pop();
        i=tmp.F;
        j=tmp.S;
        // cout<<u<<" "<<v;
        vis[i][j]=1;
        if(!vis[i+1][j]&&ok(i+1,j))
        {
            level1[i+1][j]=level1[i][j]+1;
            vis[i+1][j]=1;
            q.push({i+1,j});        
        }
        if(!vis[i-1][j]&&ok(i-1,j))
        {
            level1[i-1][j]=level1[i][j]+1;
            vis[i-1][j]=1;
            q.push({i-1,j});
        }
        if(!vis[i][j+1]&&ok(i,j+1))
        {
            level1[i][j+1]=level1[i][j]+1;
            vis[i][j+1]=1;
            q.push({i,j+1});
        }
        if(!vis[i][j-1]&&ok(i,j-1))
        {
            level1[i][j-1]=level1[i][j]+1;
            vis[i][j-1]=1;
            q.push({i,j-1});
        }
    }
    // dfs(u,v);
    int mx=0;
    rep(i,0,n)
    {
        rep(j,0,m) 
        {
            vis[i][j]=0;
            if(mx<level1[i][j])
            {
                mx=level1[i][j];
                u=i;
                v=j;
            }
            if(maze[i][j]=='#') vis[i][j]=1;
        }
    }
    // cout<<mx<<"\n";
    level2[u][v]=0;
    vis[u][v]=1;
    queue<pii> q2;
    q2.push({u,v});
    while(!q2.empty())
    {
        pii tmp=q2.front();
        q2.pop();
        i=tmp.F;
        j=tmp.S;
        // cout<<i<<" "<<j<<"\n";
        vis[i][j]=1;
        if(!vis[i+1][j]&&ok(i+1,j))
        {
            level2[i+1][j]=level2[i][j]+1;
            vis[i+1][j]=1;
            q2.push({i+1,j});        
        }
        if(!vis[i-1][j]&&ok(i-1,j))
        {
            level2[i-1][j]=level2[i][j]+1;
            vis[i-1][j]=1;
            q2.push({i-1,j});
        }
        if(!vis[i][j+1]&&ok(i,j+1))
        {
            level2[i][j+1]=level2[i][j]+1;
            vis[i][j+1]=1;
            q2.push({i,j+1});
        }
        if(!vis[i][j-1]&&ok(i,j-1))
        {
            level2[i][j-1]=level2[i][j]+1;
            vis[i][j-1]=1;
            q2.push({i,j-1});
        }
    }
    // dfs1(u,v);
    mx=0;
    rep(i,0,n)
    {
        rep(j,0,m)
        {
            mx=max(mx,level2[i][j]);
        }
    }
    cout<<mx;
}


signed main()
{

    ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int t=1;
    // cin>>t;
    while(t--)
    {
        solve();
        if(t)cout<<"\n";
    }
    return 0;
}
