aboutsummaryrefslogtreecommitdiff
path: root/2022/Day11/part-two.cl
blob: 362be8bd2be218d32db7be8616d6f6f0a2531343 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
;;; https://gitlab.com/Syndamia/senzill
(require :senzill)
(use-package :senzill.math)
(use-package :senzill.collections)
(use-package :senzill.io)

(defparameter +rounds+ 10000)

(defclass monkey ()
  ((items :initarg :items
          :accessor monkey-items)
   (inspections :initarg :inspections
                :accessor monkey-inspections)
   (operation :initarg :operation
              :reader monkey-operation)
   (test :initarg :test
         :reader monkey-test)
   (throw-true :initarg :throw-true
               :reader monkey-throw-true)
   (throw-false :initarg :throw-false
                :reader monkey-throw-false))
  (:default-initargs
    :items '()
    :inspections 0
    :operation (lambda (old) old)
    :test (lambda (worry-level) worry-level)
    :throw-true 0
    :throw-false 0))

(defmethod inspect-and-throw ((m monkey) (monkey-true monkey) (monkey-false monkey) (modder integer))
  (setf (first (monkey-items m))
        (% (funcall (monkey-operation m) (first (monkey-items m))) modder))
  (++1 (monkey-inspections m))
  (if (funcall (monkey-test m) (first (monkey-items m)))
    (push-back (pop (monkey-items m)) (monkey-items monkey-true))
    (push-back (pop (monkey-items m)) (monkey-items monkey-false))))



(ask-for-stream (prog-input)
  (let ((monkeys '()) (modder 1) (buffer-items '()) (buffer-operation NIL) (buffer-test NIL) (buffer-throw-t -1) (buffer-throw-f -1))
  (flet ((create-operation-function (inpt)
           (eval `(lambda (old) (funcall ,(if (char= (char inpt 23) #\*) #'* #'+) ; In the input, there is only * and +
                                         old
                                         ,(if (char= (char inpt 25) #\o)
                                            'old
                                            (parse-integer inpt :start 25))))))
         (create-test-function (inpt)
           (eval `(lambda (worry-level)
                    (zerop (% worry-level ,(parse-integer inpt :start 21))))))) ; In the input we only test for divisibility


    (doread-lines (inpt :read-line-options (prog-input NIL))
                  (cond ((zerop (length inpt))) ; Do nothing on empty lines
                        ((char= (char inpt 0) #\M) ; Monkey #:
                         (push-back (make-instance 'monkey :items buffer-items
                                                           :operation buffer-operation
                                                           :test buffer-test
                                                           :throw-true buffer-throw-t
                                                           :throw-false buffer-throw-f)
                                    monkeys))
                        ((char= (char inpt 2) #\S) ;   Starting items:
                         (setf buffer-items (loop for itms = (subseq inpt 18) then (subseq itms (+ 2 (position #\, itms)))
                                                  collect (parse-integer itms :junk-allowed T)
                                                  while (position #\, itms))))
                        ((char= (char inpt 2) #\O) ;   Operation:
                         (setf buffer-operation (create-operation-function inpt)))
                        ((char= (char inpt 2) #\T) ;   Test:
                         ;; If we had one monkey, we could just mod the worry level, this way we
                         ;; reduce the number by not changing the outcome of the Test
                         ;; For two or more monkeys, we want this property to hold, so we need
                         ;; our number to be divisible by all the Test values, hence we mod
                         ;; by a number, divisible by all of those values.
                         ;; The smallest such number is the multiplication of all of those values.
                         ;; I was 99.99% there on figuring it out, but I still needed to look.
                         ;; Thanks https://github.com/arcogelderblom/AdventOfCode2022/
                         (*= modder (parse-integer inpt :start 21))
                         (setf buffer-test (create-test-function inpt)))
                        ((char= (char inpt 7) #\t) ;     If true:
                         (setf buffer-throw-t (parse-integer inpt :start 29)))
                        ((char= (char inpt 7) #\f) ;     If false:
                         (setf buffer-throw-f (parse-integer inpt :start 30)))))
    ;; On very first line we add a monkey with default buffer values
    (pop monkeys)
    ;; The loop doesn't add the last monkey, since there is no new "Monkey #:" line
    (push-back (make-instance 'monkey :items buffer-items
                                      :operation buffer-operation
                                      :test buffer-test
                                      :throw-true buffer-throw-t
                                      :throw-false buffer-throw-f)
               monkeys)

    (dotimes (r +rounds+)
      (loop for m in monkeys
            do (loop for item in (monkey-items m)
                     do (inspect-and-throw m
                                           (nth (monkey-throw-true m) monkeys)
                                           (nth (monkey-throw-false m) monkeys)
                                           modder))))

    (loop for m in monkeys
          maximize (monkey-inspections m) into biggest
          finally
            ;;; This loop is unnecessary, inefficient and stupid, but I'm extra lazy today
            (loop for m in monkeys
                  if (< (monkey-inspections m) biggest)
                    maximize (monkey-inspections m) into second-biggest
                  finally
                    (print (* biggest second-biggest)))))))