adventofcode2022

My solutions for Advent of Code 2022
Log | Files | Refs

day11.lisp (3705B)


      1 (defpackage #:adventofcode2022/day11
      2   (:use #:cl #:adventofcode2022))
      3 (in-package #:adventofcode2022/day11)
      4 
      5 (defclass monkey ()
      6   ((items :initform nil
      7           :accessor items)
      8    (operation-fun :accessor operation-fun)
      9    (test-value :accessor test-value)
     10    (test-fun :accessor test-fun)
     11    (inspection-count :initform 0
     12                      :accessor inspection-count)))
     13 
     14 (defun parse-monkeys (inputs)
     15   (loop with monkeys = nil
     16         with current-monkey = nil
     17         with test-if-true = nil
     18         for input in inputs
     19         do (cond
     20              ((str:starts-with-p "Monkey " input)
     21               (setf current-monkey (make-instance 'monkey))
     22               (push current-monkey monkeys))
     23              ((str:starts-with-p "  Starting items:" input)
     24               (setf (items current-monkey)
     25                     (mapcar #'parse-integer
     26                             (str:split ", " (subseq input 18)))))
     27              ((str:starts-with-p "  Operation:" input)
     28               (setf (operation-fun current-monkey)
     29                     (eval (read-from-string
     30                            (format nil "(lambda (old) (~A old))" (subseq input 23))))))
     31              ((str:starts-with-p "  Test: divisible by" input)
     32               (setf (test-value current-monkey) (parse-integer (subseq input 21))))
     33              ((str:starts-with-p "    If true: throw to monkey" input)
     34               (setf test-if-true (parse-integer (subseq input 29))))
     35              ((str:starts-with-p "    If false: throw to monkey" input)
     36               (setf (test-fun current-monkey)
     37                     (eval `(lambda (item)
     38                              (if (= (mod item ,(test-value current-monkey)) 0)
     39                                  ,test-if-true
     40                                  ,(parse-integer (subseq input 29))))))))
     41         finally (return (coerce (reverse monkeys) 'vector))))
     42 
     43 (defun let-monkeys-play (monkeys rounds &optional do-not-manage-worry-level?)
     44   (loop
     45     with test-value-product = (if do-not-manage-worry-level?
     46                                   (apply #'* (map 'list #'test-value monkeys))
     47                                   0)
     48     repeat rounds
     49     do (loop for monkey across monkeys
     50              do (loop with operation-fun = (operation-fun monkey)
     51                       with test-fun = (test-fun monkey)
     52                       for item in (items monkey)
     53                       for new-item = (let ((new-value (funcall operation-fun item)))
     54                                        (if do-not-manage-worry-level?
     55                                            (mod new-value test-value-product)
     56                                            (floor (/ new-value 3))))
     57                       for next-monkey-index = (funcall test-fun new-item)
     58                       for next-monkey = (aref monkeys next-monkey-index)
     59                       do (incf (inspection-count monkey))
     60                       do (setf (items next-monkey)
     61                                (append (items next-monkey) (list new-item))))
     62              do (setf (items monkey) nil))))
     63 
     64 (defun get-monkey-business (monkeys)
     65   (apply #'*
     66          (map 'list
     67               #'inspection-count
     68               (subseq (sort monkeys
     69                             (lambda (monkey-1 monkey-2)
     70                               (> (inspection-count monkey-1)
     71                                  (inspection-count monkey-2))))
     72                       0 2))))
     73 
     74 (defun task1 (inputs)
     75   (let ((monkeys (parse-monkeys inputs)))
     76     (let-monkeys-play monkeys 20)
     77     (get-monkey-business monkeys)))
     78 
     79 (defun task2 (inputs)
     80   (let ((monkeys (parse-monkeys inputs)))
     81     (let-monkeys-play monkeys 10000 t)
     82     (get-monkey-business monkeys)))
     83 
     84 (define-day 11
     85     ()
     86   #'task1
     87   #'task2)