#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <queue>
#include <cmath>
#include <algorithm>
#include <random>
#include <chrono>
#include <iomanip>
#define lint unsigned long long int
#define FOR(x, to) for(int x=0; x<(int)(to); x++)
#define DUMP(ar) for(auto itd=begin(ar); itd != end(ar); itd++) cout << "["s << itd - begin(ar) << "]:"s << *itd << endl
#define DUMPL(ar) for(auto itd=begin(ar); itd != end(ar); itd++) { cout << *itd; if(end(ar)-itd > 1) cout << ' '; } cout << endl
#define COUT(x) cout << (x) << endl
#define VCIN(ar) for(auto &vcin: (ar)) cin >> vcin
#define ALL(ar) ar.begin(), ar.end()
#define LOOPD(i) cout << "ループ["s << i << "]回目---------------"s << endl
using namespace std;
// lint:64ビット 10^19

struct point{
    int x;
    int y;
};

void check(vector<vector<int>> &ans, vector<vector<char>> &c, point target){
    vector<point> pnts;
    vector<point> tmp;
    pnts.push_back(target);
    int now_num = 0;
    while(pnts.size() > 0){
        tmp.clear();
        for(int i=0; i<(int)pnts.size(); i++){
            int xx = pnts[i].x;
            int yy = pnts[i].y;
            ans[yy][xx] = now_num;
            if(yy != 0 && c[yy-1][xx] != '#' && ans[yy-1][xx] == -1){
                tmp.push_back({xx, yy-1});
            }
            if(yy != (int)c.size()-1 && c[yy+1][xx] != '#' && ans[yy+1][xx] == -1){
                tmp.push_back({xx, yy+1});
            }
            if(xx != 0 && c[yy][xx-1] != '#' && ans[yy][xx-1] == -1){
                tmp.push_back({xx-1, yy});
            }
            if(xx != (int)c[0].size()-1 && c[yy][xx+1] != '#' && ans[yy][xx+1] == -1){
                tmp.push_back({xx+1, yy});
            }
        }
        now_num++;
        pnts = tmp;
    }
}

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);

    int h, w;
    cin >> h >> w;
    vector<vector<char>> c(h, vector<char>(w));
    for(int i=0; i<h; i++){
        for(int j=0; j<w; j++){
            cin >> c[i][j];
        }
    }

    point target;
    bool flag = false;
    for(int i=0; i<h; i++){
        for(int j=0; j<w; j++){
            if(c[i][j] != '#'){
                target = {j, i};
                flag = true;
                break;
            }
        }
        if(flag) break;
    }

    vector<vector<bool>> attack(h, vector<bool>(w, false));
    for(int i=0; i<h; i++){
        for(int j=0; j<w; j++){
            if(c[i][j] == '#') attack[i][j] = true;
        }
    }

    queue<point> pnts;
    pnts.push(target);
    while(pnts.size() > 0){
        int xx = pnts.front().x;
        int yy = pnts.front().y;
        
        if(yy != 0 && !attack[yy-1][xx] ){
            pnts.push({xx, yy-1});
            attack[yy-1][xx] = true;
        }
        if(yy != (int)c.size()-1 && !attack[yy+1][xx] ){
            pnts.push({xx, yy+1});
            attack[yy+1][xx] = true;
        }
        if(xx != 0 && !attack[yy][xx-1] ){
            pnts.push({xx-1, yy});
            attack[yy][xx-1] = true;
        }
        if(xx != (int)c[0].size()-1 && !attack[yy][xx+1] ){
            pnts.push({xx+1, yy});
            attack[yy][xx+1] = true;
        }

        if(pnts.size() == 1){
            target = pnts.front();
        }
        pnts.pop();
    }

    vector<vector<int>> ans(h, vector<int>(w, -1));
    check(ans, c, target);
    
    // for(int i=0; i<h; i++){
    //     DUMPL(ans[i]);
    // }
    
    int mmax = 0;
    for(int i=0; i<h; i++){
        for(int j=0; j<w; j++){
            if(ans[i][j] > mmax){
                mmax = ans[i][j];
            }
        }
    }

    COUT(mmax);

    return 0;
}