diff --git a/day11/day11.lisp b/day11/day11.lisp new file mode 100644 index 0000000..3448010 --- /dev/null +++ b/day11/day11.lisp @@ -0,0 +1,93 @@ +(ql:quickload :cl-ppcre) + +(defclass monkey () + ((items + :accessor items + :initarg :items + :type list) + (op + :accessor op + :initarg :op + :type function) + (test + :accessor test + :initarg :test + :type function) + (actions + :accessor actions + :initarg :actions + :type list) + (inspections + :accessor inspections + :initarg :inspections + :type number))) + +(defparameter *regexp* "Monkey (\\d+):\\n Starting items: ([0-9, ]+)\\n Operation: new = old ([\*\+]) (\\d+|\\w+)\\n Test: divisible by (\\d+)\\n If true: throw to monkey (\\d+)\\n If false: throw to monkey (\\d+)") + +(defun str-to-list (str) + "Parses comma-separated string of integers in STR into a list of +integers." + (loop :for item :in (ppcre:split ", " str) :collect (parse-integer item))) + +(defun make-op (operation operand) + "Returns a function matching the description given by STR." + (if (equal operand "old") + (if (equal operation "*") + (lambda (old) (* old old)) + (lambda (old) (+ old old))) + (if (equal operation "*") + (lambda (old) (* old (parse-integer operand))) + (lambda (old) (+ old (parse-integer operand)))))) + +(defun make-test (str) + "Returns a function testing for divisibility by the number given in +STR." + (lambda (level) (zerop (mod level (parse-integer str))))) + +(defun throw-item (monkeys src dest) + "Removes the first item held by the monkey at position SRC in MONKEYS +and adds it to the end of the items held by the monkey at position +DEST in MONKEYS." + (progn + (setf (items (nth dest monkeys)) + (append (items (nth dest monkeys)) (list (car (items (nth src monkeys)))))) + (setf (items (nth src monkeys)) + (cdr (items (nth src monkeys)))))) + +(defun parse-input (input) + "Parses INPUT into a list of monkey objects." + (loop :for monkey + :in (ppcre:split "\\n\\n" (uiop:read-file-string input)) + :collect + (ppcre:do-register-groups (id items operation operand test true false) (*regexp* monkey) + (return (make-instance 'monkey + :items (str-to-list items) + :op (make-op operation operand) + :test (make-test test) + :actions (list (parse-integer id) (parse-integer true) + (parse-integer id) (parse-integer false)) + :inspections 0))))) + +(defun run-round (monkeys div) + (let ((level 0)) + (loop :for monkey :in monkeys :do + (loop :for item :in (items monkey) :do + (progn + (setf (inspections monkey) (1+ (inspections monkey))) + (setq level (funcall (op monkey) item)) + (setq level (floor level div)) + (setf (items monkey) (cons level (cdr (items monkey)))) + (if (funcall (test monkey) level) + (throw-item monkeys (first (actions monkey)) (second (actions monkey))) + (throw-item monkeys (third (actions monkey)) (fourth (actions monkey))))))) + monkeys)) + +(defun solution (input div rounds) + "Run ROUNDS number of rounds on INPUT and use divisor DIV." + (let ((monkeys (parse-input input))) + (loop :for round :upto (1- rounds) :do + (run-round monkeys div)) + (reduce '* (subseq (sort (loop :for monkey :in monkeys :collect (inspections monkey)) '>) 0 2)))) + +(solution "./input" 3 20) +(solution "./input" 1 10000) diff --git a/day11/input b/day11/input new file mode 100644 index 0000000..58fdc75 --- /dev/null +++ b/day11/input @@ -0,0 +1,55 @@ +Monkey 0: + Starting items: 91, 58, 52, 69, 95, 54 + Operation: new = old * 13 + Test: divisible by 7 + If true: throw to monkey 1 + If false: throw to monkey 5 + +Monkey 1: + Starting items: 80, 80, 97, 84 + Operation: new = old * old + Test: divisible by 3 + If true: throw to monkey 3 + If false: throw to monkey 5 + +Monkey 2: + Starting items: 86, 92, 71 + Operation: new = old + 7 + Test: divisible by 2 + If true: throw to monkey 0 + If false: throw to monkey 4 + +Monkey 3: + Starting items: 96, 90, 99, 76, 79, 85, 98, 61 + Operation: new = old + 4 + Test: divisible by 11 + If true: throw to monkey 7 + If false: throw to monkey 6 + +Monkey 4: + Starting items: 60, 83, 68, 64, 73 + Operation: new = old * 19 + Test: divisible by 17 + If true: throw to monkey 1 + If false: throw to monkey 0 + +Monkey 5: + Starting items: 96, 52, 52, 94, 76, 51, 57 + Operation: new = old + 3 + Test: divisible by 5 + If true: throw to monkey 7 + If false: throw to monkey 3 + +Monkey 6: + Starting items: 75 + Operation: new = old + 5 + Test: divisible by 13 + If true: throw to monkey 4 + If false: throw to monkey 2 + +Monkey 7: + Starting items: 83, 75 + Operation: new = old + 1 + Test: divisible by 19 + If true: throw to monkey 2 + If false: throw to monkey 6 diff --git a/day11/input-test b/day11/input-test new file mode 100644 index 0000000..c04eddb --- /dev/null +++ b/day11/input-test @@ -0,0 +1,27 @@ +Monkey 0: + Starting items: 79, 98 + Operation: new = old * 19 + Test: divisible by 23 + If true: throw to monkey 2 + If false: throw to monkey 3 + +Monkey 1: + Starting items: 54, 65, 75, 74 + Operation: new = old + 6 + Test: divisible by 19 + If true: throw to monkey 2 + If false: throw to monkey 0 + +Monkey 2: + Starting items: 79, 60, 97 + Operation: new = old * old + Test: divisible by 13 + If true: throw to monkey 1 + If false: throw to monkey 3 + +Monkey 3: + Starting items: 74 + Operation: new = old + 3 + Test: divisible by 17 + If true: throw to monkey 0 + If false: throw to monkey 1 \ No newline at end of file