module m_deque
  ! 双端キュー. リングバッファ実装.
  implicit none

  private
  public :: itemtype, dequetype
  integer, parameter :: MINSIZE = 4

  type itemtype
    integer :: x(3)
  end type itemtype

  type dequetype
    integer :: n = 0, st = 1, memsize = 0
    type(itemtype), allocatable :: ary(:)
  contains
    procedure :: push_left, push_right, pop_left, pop_right, slice, dump
  end type dequetype

  contains

  subroutine resize_up(dq)
    ! 初めの要素追加または n == memsize で呼ばれる
    type(dequetype), intent(inout) :: dq
    type(itemtype), allocatable :: tmp(:)
    if (dq%memsize == 0) then
      dq%memsize = MINSIZE
      allocate (dq%ary(dq%memsize))
      dq%n = 0
      dq%st = max(1, dq%memsize / 8)
    else
      if (dq%n /= dq%memsize) stop 2
      allocate (tmp(dq%n))
      tmp(:) = slice(dq, 1, dq%n)
      dq%memsize = dq%memsize * 2
      deallocate (dq%ary)
      allocate (dq%ary(dq%memsize))
      dq%st = max(1, dq%memsize / 8)
      dq%ary(dq%st:dq%st + dq%n - 1) = tmp(:)
      deallocate (tmp)
    end if
  end subroutine resize_up

  subroutine may_resize_down(dq)
    ! 必要なら小さい配列に移し替える
    type(dequetype), intent(inout) :: dq
    type(itemtype), allocatable :: tmp(:)
    if (dq%memsize <= MINSIZE) return
    if (mod(dq%memsize, 2) /= 0) stop 1
    if (dq%n * 4 > dq%memsize) return

    allocate (tmp(dq%n))
    tmp(:) = slice(dq, 1, dq%n)
    dq%memsize = dq%memsize / 2
    deallocate (dq%ary)
    allocate (dq%ary(dq%memsize))
    dq%st = max(1, dq%memsize / 8)
    dq%ary(dq%st:dq%st + dq%n - 1) = tmp(:)
    deallocate (tmp)
  end subroutine may_resize_down

  subroutine push_left(dq, x)
    class(dequetype), intent(inout) :: dq
    type(itemtype), intent(in) :: x

    if (dq%n == dq%memsize) call resize_up(dq)
    dq%n = dq%n + 1
    dq%st = imod(dq%st - 1, dq%memsize)
    dq%ary(dq%st) = x
  end subroutine push_left

  subroutine push_right(dq, x)
    class(dequetype), intent(inout) :: dq
    type(itemtype), intent(in) :: x
    integer :: idx

    if (dq%n == dq%memsize) call resize_up(dq)
    dq%n = dq%n + 1
    idx = dq%st + dq%n - 1
    idx = imod(idx, dq%memsize)
    dq%ary(idx) = x
  end subroutine push_right

  type(itemtype) function pop_left(dq)
    class(dequetype), intent(inout) :: dq
    if (dq%n == 0) stop 1
    pop_left = dq%ary(dq%st)
    dq%n = dq%n - 1
    dq%st = imod(dq%st + 1, dq%memsize)
    call may_resize_down(dq)
  end function pop_left

  type(itemtype) function pop_right(dq)
    class(dequetype), intent(inout) :: dq
    if (dq%n == 0) stop 1
    pop_right = dq%ary(imod(dq%st + dq%n - 1, dq%memsize))
    dq%n = dq%n - 1
    call may_resize_down(dq)
  end function pop_right

  function slice(dq, istart, iend)
    ! 実データの [istart:iend] の範囲を切り出す
    class(dequetype), intent(in) :: dq
    type(itemtype), allocatable :: slice(:)
    integer, intent(in) :: istart, iend  ! 実データ内のインデックス
    integer :: dstart, dend
    if (istart < 1) stop 1
    if (iend < istart) stop 1
    if (iend > dq%n) stop 1

    dstart = imod(istart + dq%st - 1, dq%memsize)
    dend = imod(dstart + (iend - istart), dq%memsize)

    allocate (slice(iend - istart + 1))
    if (dend < dstart) then
      slice(1:dq%memsize - dstart + 1) = dq%ary(dstart:dq%memsize)
      slice(dq%memsize - dstart + 2:iend - istart + 1) = dq%ary(1:dend)
    else
      slice(:) = dq%ary(dstart:dend)
    end if
  end function slice

  subroutine dump(dq)
    class(dequetype), intent(in) :: dq
    print *, "Data count:               ", dq%n
    print *, "Physical starting index:  ", dq%st
    print *, "Physical memory allocated:", dq%memsize
    print *, slice(dq, 1, dq%n)
  end subroutine dump

  pure integer function imod(idx, ms)
    ! メモリサイズ ms でインデックスを丸める
    ! [1 - ms <= idx <= ms + ms] を仮定
    integer, intent(in) :: idx, ms
    imod = idx
    if (imod > ms) then
      imod = imod - ms
    else if (imod < 1) then
      imod = imod + ms
    end if
  end function imod
end module m_deque

program main
  use m_deque, only: dequetype, itemtype
  implicit none
  integer :: h, w, i, j, res, di
  character(20) :: s(20)
  read *, h, w
  do i = 1, h
    read *, s(i)
  end do
  res = 0
  do i = 1, h
    do j = 1, w
      di = maxdistfrom(s, i, j)
      res = max(res, di)
    end do
  end do
  print "(i0)", res

  contains

  integer function maxdistfrom(s, i, j)
    integer, intent(in) :: i, j
    character(20), intent(in) :: s(20)
    logical :: queued(20, 20)
    type(dequetype) :: dq
    type(itemtype) :: triple
    integer :: k, l, d, k2, l2, p, xs(4), ys(4)

    if (s(i)(j:j) == "#") then
      maxdistfrom = 0
      return
    end if

    queued(:, :) = .false.
    call dq%push_right(itemtype((/i, j, 0/)))
    queued(i, j) = .true.
    maxdistfrom = 0
    do while (dq%n > 0)
      triple = dq%pop_left()
      k = triple%x(1)
      l = triple%x(2)
      d = triple%x(3)
      res = max(res, d)
      ys = (/-1, 1, 0, 0/)
      xs = (/0, 0, -1, 1/)
      do p = 1, 4
        k2 = k + ys(p)
        l2 = l + xs(p)
        if (k2 < 1) cycle
        if (k2 > h) cycle
        if (l2 < 1) cycle
        if (l2 > w) cycle
        if (s(k2)(l2:l2) == "#") cycle
        if (queued(k2, l2)) cycle
        call dq%push_right(itemtype((/k2, l2, d + 1/)))
        queued(k2, l2) = .true.
      end do
    end do
  end function maxdistfrom
end program main


Measured memory_bytes: 256