Last active
December 27, 2022 22:04
-
-
Save seltzer1717/ef9a1dffacafd7988e8e942f958b7b1e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; 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