(declaim (optimize (speed 3) (safety 0) (debug 0)))

(defconstant +loop-count+ 1000000)
(defconstant +expected-checksum+ 3500013)

(defstruct (packet (:constructor %make-packet (digits))) digits)
(defstruct (packet-state (:constructor %make-packet-state (tag payload))) tag payload)

(declaim (ftype (function () fixnum) configured-loop-count))
(defun configured-loop-count ()
  (handler-case
      (let ((line (read-line *standard-input* nil nil)))
        (if line
            (let ((value (parse-integer line :junk-allowed t)))
              (if (> value 0) value +loop-count+))
            +loop-count+))
    (error () +loop-count+)))

(declaim (ftype (function () packet-state) live-state))
(defun live-state ()
  (%make-packet-state :live (%make-packet #(2 7 1 8 2 8 1 8))))

(declaim (ftype (function () packet-state) cached-state))
(defun cached-state ()
  (%make-packet-state :cached (%make-packet #(1 6 1 8 0 3 4 5))))

(declaim (ftype (function (fixnum packet-state packet-state) packet-state) select-state))
(defun select-state (i live cached)
  (declare (type fixnum i))
  (if (zerop (rem i 2))
      live
      cached))

(declaim (ftype (function (packet-state fixnum) fixnum) state-digit))
(defun state-digit (state index)
  (declare (type packet-state state)
           (type fixnum index))
  (let* ((payload (packet-state-payload state))
         (digits (packet-digits payload))
         (value (svref digits index)))
    (declare (type simple-vector digits)
             (type fixnum value))
    (case (packet-state-tag state)
      (:missing 0)
      (otherwise value))))

(declaim (ftype (function (fixnum) fixnum) enum-struct-payload-loop))
(defun enum-struct-payload-loop (limit)
  (declare (type fixnum limit))
  (loop with i of-type fixnum = 0
        with acc of-type fixnum = 13
        with live of-type packet-state = (live-state)
        with cached of-type packet-state = (cached-state)
        while (< i limit)
        do (let* ((next (+ acc (state-digit (select-state i live cached) (rem i 8))))
                  (bounded (if (> next 1000000000)
                               (- next 1000000000)
                               next)))
             (declare (type fixnum next bounded))
             (setf acc bounded
                   i (+ i 1)))
        finally (return acc)))

(let ((result (enum-struct-payload-loop (configured-loop-count))))
  (format t "~D~%" result)
  (sb-ext:exit :code (if (= result +expected-checksum+) 0 1)))
