;; -*- coding: utf-8 -*-
(eval-when (:compile-toplevel :load-toplevel :execute)
  (defparameter OPT
    #+swank '(optimize (speed 3) (safety 2))
    #-swank '(optimize (speed 3) (safety 0) (debug 0)))
  #+swank (progn (ql:quickload '(:cl-debug-print :fiveam))))
#+swank (cl-syntax:use-syntax cl-debug-print:debug-print-syntax)

;; BEGIN_INSERTED_CONTENTS
(defmacro buffered-read-line (&optional (buffer-size 30) (in '*standard-input*) (term-char #\Space))
  "Reads ASCII inputs and returns two values: the string and the end
position. Note that the returned string will be reused if this form is executed
more than once.

This macro calls READ-BYTE to read characters though it calls READ-CHAR instead
on SLIME because SLIME's IO is not bivalent."
  (let ((buffer (gensym))
        (character (gensym))
        (idx (gensym))
        (stream (gensym)))
    `(let* ((,stream ,in)
            (,buffer (load-time-value (make-string ,buffer-size :element-type 'base-char))))
       (declare (simple-base-string ,buffer)
                (inline read-byte)
                #+swank (sb-kernel:ansi-stream ,stream))
       (loop for ,character of-type base-char =
                ,(if (member :swank *features*)
                     `(read-char ,stream nil #\Newline) ; on SLIME
                     `(code-char (read-byte ,stream nil #.(char-code #\Newline))))
             for ,idx from 0
             until (char= ,character #\Newline)
             do (setf (schar ,buffer ,idx) ,character)
             finally (when (< ,idx ,buffer-size)
                       (setf (schar ,buffer ,idx) ,term-char))
                     (return (values ,buffer ,idx))))))

(defstruct (queue (:constructor make-queue
                    (&optional list &aux (tail (last list)))))
  (list nil :type list)
  (tail nil :type (or null (cons t null))))

(declaim (inline enqueue))
(defun enqueue (obj queue)
  (symbol-macrolet ((list (queue-list queue))
                    (tail (queue-tail queue)))
    (if (null list)
        (setf tail (list obj)
              list tail)
        (setf (cdr tail) (list obj)
              tail (cdr tail))))
  queue)

(declaim (inline dequeue))
(defun dequeue (queue)
  (pop (queue-list queue)))

(declaim (inline queue-empty-p))
(defun queue-empty-p (queue)
  (null (queue-list queue)))

(defmacro dbg (&rest forms)
  #+swank
  (if (= (length forms) 1)
      `(format *error-output* "~A => ~A~%" ',(car forms) ,(car forms))
      `(format *error-output* "~A => ~A~%" ',forms `(,,@forms)))
  #-swank (declare (ignore forms)))

(defmacro define-int-types (&rest bits)
  `(progn
     ,@(mapcar (lambda (b) `(deftype ,(intern (format nil "UINT~A" b)) () '(unsigned-byte ,b))) bits)
     ,@(mapcar (lambda (b) `(deftype ,(intern (format nil "INT~A" b)) () '(signed-byte ,b))) bits)))
(define-int-types 2 4 7 8 15 16 31 32 62 63 64)

(declaim (inline println))
(defun println (obj &optional (stream *standard-output*))
  (let ((*read-default-float-format* 'double-float))
    (prog1 (princ obj stream) (terpri stream))))

(defconstant +mod+ 1000000007)

;; Body

(declaim (inline encode))
(defun encode (i j)
  (dpb j (byte 16 16) i))

(defun main ()
  (declare #.OPT)
  (let* ((h (read))
         (w (read))
         (plan (make-array (list h w) :element-type 'uint16 :initial-element #xffff))
         ;; i|j|dist
         (q (make-queue)))
    (declare (uint32 h w))
    (dotimes (i h)
      (let ((line (buffered-read-line 1000)))
        (dotimes (j w)
          (when (char= #\# (aref line j))
            (setf (aref plan i j) 0)
            (enqueue (encode i j) q)))))
    (labels ((frob (next-d next-i next-j)
               (declare (fixnum next-d next-i next-j))
               (when (= #xffff (aref plan next-i next-j))
                 (enqueue (encode next-i next-j) q)
                 (setf (aref plan next-i next-j) next-d))))
      (declare (inline frob))
      (loop until (queue-empty-p q)
            for node of-type uint32 = (dequeue q)
            for i = (ldb (byte 16 0) node)
            for j = (ldb (byte 16 16) node)
            for d = (aref plan i j)
            do (when (< 0 i)
                 (frob (+ 1 d) (- i 1) j))
               (when (< i (- h 1))
                 (frob (+ 1 d) (+ i 1) j))
               (when (< 0 j)
                 (frob (+ 1 d) i (- j 1)))
               (when (< j (- w 1))
                 (frob (+ 1 d) i (+ j 1)))))
    (println (reduce #'max (array-storage-vector plan)))))

#-swank(main)


Measured memory_bytes: 48484