Skip to content

Commit

Permalink
day20.clj
Browse files Browse the repository at this point in the history
  • Loading branch information
narimiran committed Dec 20, 2023
1 parent 8e42c63 commit 3be7d9c
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 3 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ I really liked the language (I've also written about [how to make Clojure soluti

As a preparation for this year, I used Clojure for AoC 2016 and I experimented with the `quil` library to [make some visualizations](https://github.com/narimiran/advent_of_code_2016#visualizations).

This year, I plan to do as much visualizations as I can, using the same library.
~~This year, I plan to do as much visualizations as I can, using the same library.~~


 
Expand Down Expand Up @@ -56,7 +56,7 @@ Day 00: Helper file | [aoc.clj](clojure/aoc.clj) |
[Day 17](http://adventofcode.com/2023/day/17) | [day17.clj](clojure/day17.clj) | Consider only L/R directions, and then go straight as far as you can.
[Day 18](http://adventofcode.com/2023/day/18) | [day18.clj](clojure/day18.clj) | TIL about Shoelace formula and Pick's theorem.
[Day 19](http://adventofcode.com/2023/day/19) | [day19.clj](clojure/day19.clj) | Simpler ranges than Day 5.
<!-- [Day 20](http://adventofcode.com/2023/day/20) | [day20.clj](clojure/day20.clj) | -->
[Day 20](http://adventofcode.com/2023/day/20) | [day20.clj](clojure/day20.clj) | Some manual searching through the input needed.
<!-- [Day 21](http://adventofcode.com/2023/day/21) | [day21.clj](clojure/day21.clj) | -->
<!-- [Day 22](http://adventofcode.com/2023/day/22) | [day22.clj](clojure/day22.clj) | -->
<!-- [Day 23](http://adventofcode.com/2023/day/23) | [day23.clj](clojure/day23.clj) | -->
Expand Down
3 changes: 3 additions & 0 deletions clojure/aoc.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
(:require [clojure.string :as str]))


(def empty-queue clojure.lang.PersistentQueue/EMPTY)


(defn integers
[s & {:keys [negative?]
:or {negative? true}}]
Expand Down
101 changes: 101 additions & 0 deletions clojure/day20.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
(ns day20
(:require aoc
[clojure.string :as str]))


(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)]
(let [queue' (pop queue)
{:keys [typ dest amt pulse pulses]} ((:modules state) curr)]
(cond
(or (nil? typ)
(and (= typ :%) (= v 1)))
(recur queue' state)

(= curr :broadcaster)
(recur (into queue' (map (fn [d] [curr d v]) dest))
(update state :low-cnt + amt))

:else
(let [pulses' (assoc pulses from v)
pulse' (case typ
:% (- 1 pulse)
:& (if (not-any? zero? (vals pulses')) 0 1))
zp? (zero? pulse')]
(recur (into queue' (map (fn [d] [curr d pulse']) dest))
(cond-> state
(= typ :%) (assoc-in [:modules curr :pulse] pulse')
(= typ :&) (assoc-in [: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
(assoc-in [:periods curr] n))))))
state)))


(defn push-button [times modules]
(reduce
(fn [state n]
(if (= (count (:periods state)) 4)
(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-file]
(let [modules (->> (aoc/read-input input-file parse-line)
(into {})
init-pulses)]
[(part-1 modules)
(part-2 modules)]))


(solve 20)
3 changes: 2 additions & 1 deletion clojure/tests/solutions_tests.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
day01 day02 day03 day04 day05
day06 day07 day08 day09 day10
day11 day12 day13 day14 day15
day16 day17 day18 day19 ;day20
day16 day17 day18 day19 day20
; day21 day22 day23 day24 day25
[clojure.test :refer [deftest is run-tests successful?]]))

Expand Down Expand Up @@ -43,6 +43,7 @@
(check-day 17 [102 94] [758 892])
(check-day 18 [62 952408144115] [47045 147839570293376])
(check-day 19 [19114 167409079868000] [386787 131029523269531])
(check-day 20 nil [836127690 240914003753369])

(let [summary (run-tests)]
(when-not (successful? summary)
Expand Down
58 changes: 58 additions & 0 deletions inputs/20.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
%ng -> vz
%hv -> zz
%cn -> fv, kp
%sc -> sm
&rt -> jf, hv, bs, kt, fn
%bc -> fv
%sb -> gk
%vz -> gk, lg
%sm -> mx
%kp -> fv, pq
&gk -> mx, sc, vq, bz, ng, zk, sm
%bs -> rt, mk
%pn -> rt
%rq -> sl, xd
%jr -> fv, bc
%vm -> rt, pn
%rk -> gk, sb
%gs -> xt
%dc -> sl
%bz -> gk, sc
%ql -> sl, fz
%kt -> bt
%gn -> fv, hk
broadcaster -> bs, rq, cn, bz
%rl -> rh, gk
&hj -> rx
%vj -> rt, rr
%jx -> fv, bf
&ks -> hj
%rh -> gk, vq
%hk -> jx
%fn -> vj
%jl -> mr, sl
%vq -> ng
%mr -> sl, dc
%fk -> cc
%jc -> fk, sl
&jf -> hj
%lg -> gk, rk
%zz -> jg, rt
%pq -> lx, fv
%xt -> gn
%bf -> fv, jr
&qs -> hj
%gv -> sl, jl
%bt -> rt, fn
%mm -> sl, ql
%jg -> vm, rt
%lx -> gs
%rr -> hv, rt
&fv -> xt, qs, gs, cn, lx, hk
%mx -> rl
&zk -> hj
&sl -> fk, rq, fz, xd, ks
%fz -> jc
%mk -> rt, kt
%xd -> mm
%cc -> sl, gv

0 comments on commit 3be7d9c

Please sign in to comment.