Skip to content

Instantly share code, notes, and snippets.

@seltzer1717
Last active December 27, 2022 22:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seltzer1717/ef9a1dffacafd7988e8e942f958b7b1e to your computer and use it in GitHub Desktop.
Save seltzer1717/ef9a1dffacafd7988e8e942f958b7b1e to your computer and use it in GitHub Desktop.
;; Advent of Code 2022
;; Day 11 - https://adventofcode.com/2022/day/11
(ns cloud.seltzer1717.monkey
(:import (java.io BufferedReader FileReader)))
(def notes-header #"(?m)Monkey (?<monkey>\p{Digit}{1,5}):")
(def notes-starting #"\p{Space}{2}Starting items: (?<items>\p{Digit}{1,5}(, \p{Digit}{1,5})*)")
(def notes-operation #"\p{Space}{2}Operation: new = old (?<trater>\+|\-|\*|\/) (?<trand>\p{Digit}{1,5}|old)")
(def notes-test #"\p{Space}{2}Test: divisible by (?<diviser>\p{Digit}{1,5})")
(def test-true #"\p{Space}{4}If true: throw to monkey (?<truemonkey>\p{Digit}{1,5})")
(def test-false #"\p{Space}{4}If false: throw to monkey (?<falsemonkey>\p{Digit}{1,5})")
(defn monkey-throw
"Takes monkey, new worry, returns throw monkey index."
[{:keys [diviser tmonkey fmonkey]} nworry]
(if (zero? (mod nworry diviser))
tmonkey
fmonkey))
(defn worry
"Takes monkey, old worry, and returns new worry."
[{:keys [trater trand]} old]
(as-> old $
(if (= "old" trand) $ trand)
(apply trater [old $])
(/ $ 3)
(int $)))
(defn monkey-item
"Takes monkey-index, monkey, monkeys, item, and returns monkeys after processing item."
[monkey-index monkey monkeys item]
(let [new-worry (worry monkey item)
throw-index (monkey-throw monkey new-worry)]
(-> (update-in monkeys [throw-index :items] conj new-worry)
(update-in [monkey-index :inspected] (fnil inc 0)))))
(defn monkey-inspect
"Takes monkeys, monkey-index, monkey, and returns monkey after processing items."
[monkeys monkey-index _]
(let [monkey (nth monkeys monkey-index)
reduce-fn (partial monkey-item monkey-index monkey)]
(-> (reduce reduce-fn monkeys (:items monkey))
(update-in [monkey-index :items] (constantly [])))))
(defn monkey-round
"Takes monkeys, returns monkeys after round."
[monkeys]
(reduce-kv monkey-inspect monkeys monkeys))
(defn items-reader
"Takes monkey, line, and returns monkey with items."
[monkey line]
(assoc monkey
:items
(mapv #(Long/parseLong %)
(.. (doto (.matcher notes-starting line) (.find))
(group "items")
(split ", ?")))))
(defn operations-reader
"Takes monkey, line, and returns monkey with trater, trand."
[monkey line]
(let [matcher (doto (.matcher notes-operation line) (.find))
mtr (.matches matcher)]
(assoc monkey
:trater (resolve (symbol (.group matcher "trater")))
:trand (let [trand (.group matcher "trand")]
(if (.equals "old" trand) trand (Long/parseLong trand))))))
(defn tests-reader
"Takes monkey, line, and returns monkey with diviser."
[monkey line]
(let [matcher (doto (.matcher notes-test line) (.find))]
(assoc monkey :diviser (Long/parseLong (.group matcher "diviser")))))
(defn testtrue-reader
"Takes monkey, line, returns monkey with tmonkey."
[monkey line]
(let [matcher (doto (.matcher test-true line) (.find))]
(assoc monkey :tmonkey (Long/parseLong (.group matcher "truemonkey")))))
(defn testfalse-reader
"Takes monkey, line, and returns monkey with fmonkey."
[monkey line]
(let [matcher (doto (.matcher test-false line) (.find))]
(assoc monkey :fmonkey (Long/parseLong (.group matcher "falsemonkey")))))
(defn read-notes
"Takes path, returns vector of monkeys.
Monkey: {:items []
:trater <+-*/>
:trand <long or 'old'>
:diviser <long>
:tmonkey <long>
:fmonkey <long>}
:inspected <long>"
[note-path]
(with-open [buffered-reader (BufferedReader. (FileReader. note-path))]
(loop [line (.readLine buffered-reader)
monkeys []
monkey nil
notes-part :monkey]
(if line
(case notes-part
:monkey (recur (.readLine buffered-reader) monkeys {} :items)
:items (recur (.readLine buffered-reader) monkeys (items-reader monkey line) :operation)
:operation (recur (.readLine buffered-reader) monkeys (operations-reader monkey line) :test)
:test (recur (.readLine buffered-reader) monkeys (tests-reader monkey line) :testtrue)
:testtrue (recur (.readLine buffered-reader) monkeys (testtrue-reader monkey line) :testfalse)
;; Finish monkey.
:testfalse (let [finished-monkey (testfalse-reader monkey line)]
(recur (.readLine buffered-reader)
(conj monkeys finished-monkey)
finished-monkey
:done))
(recur (.readLine buffered-reader) monkeys monkey :monkey))
monkeys))))
(defn monkey-worry
"Takes monkey notews, returns which 2 monkeys are most active after 20 rounds."
[notes-path]
(let [monkeys (read-notes notes-path)]
(loop [monks monkeys
mround 1]
(if (<= 1 mround 20)
(let [mr (monkey-round monks)]
(recur mr (inc mround)))
(as-> :inspected $
(map $ monks)
(sort $)
(reverse $)
(take 2 $)
(apply * $)
(printf "Monkey Business: %1$s\n" $))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment