aboutsummaryrefslogtreecommitdiff
path: root/2022/Day11/part-one.cl
blob: 29f5b93dedd51cf4a7a2711a5613abcb282bb2a1 (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
;;; https://gitlab.com/Syndamia/senzill
(require :senzill)
(use-package :senzill.math)
(use-package :senzill.collections)
(use-package :senzill.io)

(defparameter +rounds+ 20)

(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))
  (setf (first (monkey-items m))
        (floor (/ (funcall (monkey-operation m) (first (monkey-items m))) 3)))
  (++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))))

(defun 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))))))

(defun create-test-function (inpt)
  (eval `(lambda (worry-level)
           (zerop (% worry-level ,(parse-integer inpt :start 21)))))) ; In the input we only test for divisibility

(ask-for-stream (prog-input)
  (let ((monkeys '()) (buffer-items '()) (buffer-operation NIL) (buffer-test NIL) (buffer-throw-t -1) (buffer-throw-f -1))


    (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:
                         (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)))))

    (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))))))