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