-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday20.clj
103 lines (84 loc) · 3 KB
/
day20.clj
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
(ns day20
(:require aoc
[clojure.string :as str]
[better-cond.core :as b]))
(defn extract-name [src]
(keyword (str/replace src #"%|&" "")))
(defn parse-line [line]
(let [[src dest] (str/split line #" -> ")
destinations (mapv keyword (str/split dest #", "))
amt (count destinations)]
(case (first src)
\b [:broadcaster {:typ :b
:dest destinations
:amt (inc amt)}]
\% [(extract-name src) {:typ :%
:dest destinations
:amt amt
:pulse 0}]
\& [(extract-name src) {:typ :&
:dest destinations
:amt amt
:pulses {}}])))
(defn init-pulses [modules]
(reduce (fn [m k]
(reduce (fn [m d]
(case (:typ (m d))
:& (update-in m [d :pulses] conj {k 0})
m))
m
(:dest (m k))))
modules
(keys modules)))
(defn traverse [state n]
(loop [queue (conj aoc/empty-queue [:button :broadcaster 0])
state state]
(if-let [[from curr v] (peek queue)]
#_{:clj-kondo/ignore [:unresolved-symbol]}
(b/cond
:let [queue' (pop queue)
{:keys [typ dest amt pulse pulses]} ((:modules state) curr)]
(or (nil? typ)
(and (= typ :%) (= v 1)))
(recur queue' state)
(= curr :broadcaster)
(recur (reduce (fn [q d] (conj q [curr d v])) queue' dest)
(update state :low-cnt + amt))
:let [pulses' (assoc pulses from v)
pulse' (case typ
:% (- 1 pulse)
:& (if (not-any? zero? (vals pulses')) 0 1))
zp? (zero? pulse')]
(recur (reduce (fn [q d] (conj q [curr d pulse'])) queue' dest)
(cond-> state
(= typ :%) (aoc/assoc-3 :modules curr :pulse pulse')
(= typ :&) (aoc/assoc-3 :modules curr :pulses pulses')
zp? (update :low-cnt + amt)
(not zp?) (update :high-cnt + amt)
(and (not zp?)
(#{:ks :jf :qs :zk} curr)) ; manually found these keys
(aoc/assoc-2 :periods curr n))))
state)))
(defn push-button [times modules]
(reduce
(fn [state n]
(if (= 4 (count (:periods state)))
(reduced state)
(traverse state (inc n))))
{:modules modules
:low-cnt 0
:high-cnt 0
:periods {}}
(range times)))
(defn part-1 [modules]
(let [m (push-button 1000 modules)]
(* (:low-cnt m) (:high-cnt m))))
(defn part-2 [modules]
(let [m (push-button 999999 modules)]
(reduce aoc/lcm (vals (:periods m)))))
(defn solve [input]
(->> (aoc/parse-input input parse-line)
(into {})
init-pulses
((juxt part-1 part-2))))
(solve (aoc/read-file 20))