aboutsummaryrefslogtreecommitdiffstats
path: root/AoC2022/11/solver.el
blob: 397b911b8fa9cc4748b4d395865b47b29badb0d3 (plain)
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
;;; solver.el --- Day 11 -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2022 Óscar Nájera
;;
;; Author: Óscar Nájera <hi@oscarnajera.com>
;; Maintainer: Óscar Nájera <hi@oscarnajera.com>
;; Created: December 11, 2022
;; Modified: December 11, 2022
;;
;; This file is not part of GNU Emacs.
;;
;;; Commentary:
;;
;;  Day 11
;;
;;; Code:

(require 'subr-x)
(require 'cl-lib)

(cl-defstruct (monkey (:constructor monkey--create)
                      (:copier nil))
  "Monkey container"
  id
  items
  worry-level
  throw-to)

(defun solver-monkey-make (id items operation divisor true-target false-target)
  (let ((op (if (string-prefix-p "*" operation) #'* #'+))
        (operand (unless (string-suffix-p "old" operation)
                   (string-to-number (substring operation 1))))
        (div (string-to-number divisor))
        (true (string-to-number true-target))
        (false (string-to-number false-target)))
    (monkey--create
     :id (string-to-number id)
     :items (nreverse (mapcar #'string-to-number (split-string items  ", ")))
     :worry-level (lambda (item)
                    (thread-first
                      (funcall op item (or operand item)) ;; value item
                      (floor 3)))                         ;; loose interest

     :throw-to (lambda (item)
                 (thread-first item
                               (mod  div) ;; throw input
                               (=  0)     ;; divisble
                               (if true false))))))

(defun solver-parse-monkey-entry ()
  (when
      (re-search-forward (rx bol "Monkey " (group digit) ":" (+ space)
                             "Starting items: " (group (+ (1+ digit) (? ", "))) (+ space)
                             "Operation: new = old " (group (1+ any)) (+ space)
                             "Test: divisible by " (group (1+ digit)) (+ space)
                             "If true: throw to monkey " (group digit) (+ space)
                             "If false: throw to monkey " (group digit) eol)
                         nil t)
    (apply #'solver-monkey-make
           (mapcar #'match-string (number-sequence 1 6)))))

(defun solver-monkey-business (works)
  (let ((ranks (sort works #'>)))
    (* (aref ranks 0) (aref ranks 1))))

(defun solver-get-monkeys (filename)
  (with-temp-buffer
    (insert-file-contents filename)
    (goto-char (point-min))
    (cl-loop for monkey = (solver-parse-monkey-entry) while monkey collect monkey)))

(defun solver-monkey-rounds (monkeys rounds)
  (let ((monkey-work (make-vector (length monkeys) 0)))
    ;; play round
    (dotimes (_ rounds)
      (dolist (monkey monkeys)
        (let ((items (nreverse (monkey-items monkey))))
          (setf (monkey-items monkey) nil)
          (cl-incf (aref monkey-work (monkey-id monkey)) (length items))
          (mapc (lambda (item)
                  (let* ((item-concern (funcall (monkey-worry-level monkey) item))
                         (target-monkey (funcall (monkey-throw-to monkey) item-concern)))
                    (push item-concern (monkey-items (cl-find target-monkey monkeys :key #'monkey-id)))))
                items))
        ;; (message "monkey %d - items: %s\n all: %S" (monkey-id monkey) (monkey-items monkey)
        ;;          (mapcar #'monkey-items monkeys))
        ))
    (solver-monkey-business monkey-work)))

(= 10605
   (thread-first
     "eg-in"
     (solver-get-monkeys)
     (solver-monkey-rounds 20)))

(= 50830
   (thread-first
     "input"
     (solver-get-monkeys)
     (solver-monkey-rounds 20)))