src/2018/day-04.lisp @ 429ed81c46c2

Finish the stupid goddamn pots
author Steve Losh <steve@stevelosh.com>
date Sun, 16 Dec 2018 19:28:52 -0500
parents a19c9e1fd077
children 5b5c61ad8d2b
(defpackage :advent/2018/04 #.cl-user::*advent-use*)
(in-package :advent/2018/04)
(named-readtables:in-readtable :interpol-syntax)

;; This problem gets much easier after you've unlocked the second question and
;; realize you can solve everything by building histograms of each guard's
;; sleeping minutes.

(defun parse-line (line)
  "Parse `line` into `(minute :event id?)`"
  (ppcre:register-groups-bind
      ((#'parse-integer minute) event)
      (#?r"\[\d+-\d+-\d+ \d+:(\d+)\] (.*)" line)
    (list* minute
           (cond
             ((string= "falls asleep" event) (list :sleep nil))
             ((string= "wakes up" event) (list :wake nil))
             (t (ppcre:register-groups-bind
                    ((#'parse-integer id))
                    (#?r"Guard #(\d+) begins shift" event)
                  (list :guard id)))))))

(defun sleep-intervals (events &aux start guard)
  "Transform `events` into a list of `(guard-id start end)`"
  (iterate
    (for (minute event id?) :in events)
    (ecase event
      (:guard (setf guard id?))
      (:wake (collect (list guard start minute)))
      (:sleep (setf start minute)))))

(defun guard-histograms (intervals)
  "Return a hash-table of histograms of the guards' sleeping minutes."
  (iterate
    (with result = (make-hash-table))
    (for (guard start end) :in intervals)
    (for histogram = (ensure-gethash guard result
                                     (make-array 60 :initial-element 0)))
    (do-range ((minute start end))
      (incf (aref histogram minute)))
    (finally (return result))))


(define-problem (2018 4) (data read-lines)
  (let ((guard-histograms (-<> data
                            (sort <> #'string<)
                            (mapcar #'parse-line <>)
                            sleep-intervals
                            guard-histograms)))
    (nest
      (destructuring-bind
          (sleepy-guard sleepy-guard-preferred-minute)
          (iterate
            (for (guard histogram) :in-hashtable guard-histograms)
            (finding (list guard
                           (nth-value 1 (extremum+ histogram #'>)))
                     :maximizing (summation histogram))))
      (destructuring-bind
          (predictable-guard predictable-guard-time)
          (iterate
            (for (guard histogram) :in-hashtable guard-histograms)
            (for (values time preferred-minute) = (extremum+ histogram #'>))
            (finding (list guard preferred-minute) :maximizing time)))
      (values (* sleepy-guard
                 sleepy-guard-preferred-minute)
              (* predictable-guard
                 predictable-guard-time)))))

(1am:test test-2018/04
  (multiple-value-bind (part1 part2) (run)
    (1am:is (= 143415 part1))
    (1am:is (= 49944 part2))))