#include <cstdio>
#include <string.h>
#include <list>

int makeXY(int x, int y)
{
    return y * 100 + x;
};


int check(int H, int W, const char maze[22][22], int maze2[22][22], int& startX, int& startY, int* mazeP)
{
    std::list<int> open;

    bool search = startX < 0;

    int sX = 0;
    int sY = 0;

    for (int y = 0; y <= H + 1; ++y)
    {
        for (int x = 0; x <= W + 1; ++x)
        {
            if (maze[y][x] == '#')
            {
                maze2[y][x] = 200000000;
            }
            else
            {
                sX = x; sY = y;
                maze2[y][x] = 100000000;
            }
        }
    }

    if (search == false)
    {
        // スタート地点は指定
        sX = startX;
        sY = startY;
    }

    // スタート
    maze2[sY][sX] = 0;

    open.push_back(makeXY(sX, sY));

    auto update = [&maze2](int x, int y, int length)
    {
        if (maze2[y][x] == 200000000)
        {
            // 入れない
        }
        else if (maze2[y][x] > length) {
            // 遠いので上書き
            maze2[y][x] = length;
            return true;
        }
        return false;
    };

    // 距離
    int maxLength = 0;
    while (open.size() > 0)
    {
        std::list<int> nextOpen;

        for (auto it : open)
        {
            int x = it % 100;
            int y = it / 100;
            int length = maze2[y][x] + 1;

            if (update(x, y - 1, length)) nextOpen.push_back(makeXY(x, y - 1)); if (maxLength < maze2[y][x]) maxLength = maze2[y][x];
            if (update(x, y + 1, length)) nextOpen.push_back(makeXY(x, y + 1)); if (maxLength < maze2[y][x]) maxLength = maze2[y][x];
            if (update(x - 1, y, length)) nextOpen.push_back(makeXY(x - 1, y)); if (maxLength < maze2[y][x]) maxLength = maze2[y][x];
            if (update(x + 1, y, length)) nextOpen.push_back(makeXY(x + 1, y)); if (maxLength < maze2[y][x]) maxLength = maze2[y][x];
        }

        open = std::move(nextOpen);
    }

    memcpy(maze2, mazeP, sizeof(int) * 22 * 22);
    return maxLength;
}

int main()
{
    int H, W;
    scanf("%d %d", &H, &W);

    char maze[22][22] = { 0 };

    memset(maze, '#', 22);
    memset(maze[H + 1], '#', 22);

    for (int i = 0; i < H; ++i)
    {
        maze[i + 1][0] = '#';
        scanf("%s", &maze[i + 1][1]);
        maze[i + 1][W + 1] = '#';
    }

    int maze2[22][22] = { 0 };
    int maxLenght = 0;
    int maxPos = 0;

    for (int y = 1; y <= H; ++y)
    {
        for (int x = 1; x <= W; ++x)
        {
            if (maze2[y][x] == 200000000)
            {
                // 入れない場所
                continue;
            }

            int length = check(H, W, maze, maze2, x, y, &maze2[0][0]);
            if (maxLenght < length)
            {
                // 遠い
                maxLenght = length;
                maxPos = makeXY(x, y);
            }
        }
    }

#if 0
    check(H, W, maze, maze2, sX, sY, &maze2[0][0]);

    // 一番遠い点を探す
    int maxPos = 0;
    int maxLenght = 0;
    for (int i = 1; i <= H; ++i)
    {
        for (int j = 1; j <= W; ++j)
        {
            if (maze2[i][j] == 200000000)
            {
                // 入れない場所
                continue;
            }

            if (maxLenght < maze2[i][j])
            {
                // 遠い
                maxLenght = maze2[i][j];
                maxPos = makeXY(j, i);
            }
        }
    }

    // 遠い場所から再検索
    int maze3[22][22] = { 0 };
    int nX = maxPos % 100;
    int nY = maxPos / 100;
    check(H, W, maze, maze3, nX, nY, &maze3[0][0]);

    // 遠い点を探す
    maxPos = 0;
    maxLenght = 0;
    for (int i = 1; i <= H; ++i)
    {
        for (int j = 1; j <= W; ++j)
        {
            if (maze3[i][j] == 200000000)
            {
                // 入れない場所
                continue;
            }

            if (maxLenght < maze3[i][j])
            {
                // 遠い
                maxLenght = maze3[i][j];
                maxPos = makeXY(j, i);
            }
        }
    }
#endif
    printf("%d", maxLenght);
}


Measured memory_bytes: 256