src/2016/days/day-10.lisp @ 81b47667837b

2019/10
author Steve Losh <steve@stevelosh.com>
date Sat, 14 Dec 2019 20:00:14 -0500
parents (none)
children 182bdd87fd9e
(advent:defpackage* :advent/2016/09)
(in-package :advent/2016/09)


(defun parse-line (line)
  (or (ppcre:register-groups-bind
          ((#'parse-integer value bot))
          ("value (\\d+) goes to bot (\\d+)" line)
        `(input ,value (:bot . ,bot)))
      (ppcre:register-groups-bind
          ((#'parse-integer sender)
           (#'ensure-keyword lo-type) (#'parse-integer lo)
           (#'ensure-keyword hi-type) (#'parse-integer hi))
          ("bot (\\d+) gives low to (bot|output) (\\d+) and high to (bot|output) (\\d+)" line)
        `(send ,sender (,lo-type . ,lo) (,hi-type . ,hi)))
      (error "Bad line: ~S" line)))

(defun make-buckets (instructions type)
  (make-array (_ instructions
                (tree-collect (lambda (node)
                                (and (consp node) (eql (car node) type)))
                              _)
                (extremum _ #'> :key #'cdr)
                (1+ (cdr _)))
    :initial-element nil))

(defun filter-instructions (instructions type)
  (_ instructions
    (remove type _ :test-not #'eql :key #'car)
    (mapcar #'rest _)))

(define-condition* bot-comparison () (actor lo hi))

(defun run-bots (instructions)
  (let ((bots (make-buckets instructions :bot))
        (outputs (make-buckets instructions :output))
        (input-instructions (filter-instructions instructions 'input))
        (send-instructions (alexandria:alist-hash-table
                             (filter-instructions instructions 'send))))
    (flet ((dest (type)
             (ecase type
               (:bot bots)
               (:output outputs))))
      (iterate
        (for (value (nil . id)) :in input-instructions)
        (push value (aref bots id)))
      (iterate
        (for ready = (positions 2 bots :key #'length))
        (while ready)
        (iterate
          (for id :in ready)
          (for ((lo-type . lo-id) (hi-type . hi-id)) = (gethash id send-instructions))
          (for (a b) = (aref bots id))
          (for lo = (min a b))
          (for hi = (max a b))
          (signal 'bot-comparison :actor id :lo lo :hi hi)
          (push lo (aref (dest lo-type) lo-id))
          (push hi (aref (dest hi-type) hi-id))
          (setf (aref bots id) nil))))
    outputs))

(define-problem (2016 10) (data read-lines) (157 1085)
  (let ((part1 nil))
    (handler-bind ((bot-comparison
                     (lambda (c)
                       (when (and (= (lo c) 17)
                                  (= (hi c) 61))
                         (setf part1 (actor c))))))
      (let ((outputs (run-bots (mapcar #'parse-line data))))
        (values part1
                (* (first (aref outputs 0))
                   (first (aref outputs 1))
                   (first (aref outputs 2))))))))


#; Scratch --------------------------------------------------------------------

(run '(
       "value 5 goes to bot 2"
       "bot 2 gives low to bot 1 and high to bot 0"
       "value 3 goes to bot 1"
       "bot 1 gives low to output 1 and high to bot 0"
       "bot 0 gives low to output 2 and high to output 0"
       "value 2 goes to bot 2"
       ))