Compare commits

...

61 Commits

Author SHA1 Message Date
56738fd7f9 Merge branch 'master' of git.ajet.fyi:ajet/advent-of-code 2026-05-15 09:39:52 -04:00
Adam Jeniski
b89c7ce3f2 do day 13 2026-05-15 09:27:49 -04:00
Adam Jeniski
a1db8ae128 do day 12 2026-05-15 09:27:46 -04:00
Adam Jeniski
e6357d9802 do day 11 2026-05-15 09:27:43 -04:00
b62c9346f5 cons is for boomers 2026-05-13 07:55:24 -04:00
505453974b refactor day 03 2026-05-13 07:39:51 -04:00
0aed472a32 do 2017 day 9 2026-05-04 08:47:30 -04:00
Adam Jeniski
9703c017a9 do 2017 day 8 2026-05-04 07:02:38 -04:00
Adam Jeniski
733c833f66 do 2017 day 7 2026-05-04 07:02:34 -04:00
1087a7649b do 2017 day 6 2026-04-26 11:01:02 -04:00
5077215205 do 2017 day 5 2026-04-26 11:00:57 -04:00
Adam Jeniski
8ff632503f use #() > (fn [] ,,,) 2026-04-23 15:39:59 -04:00
Adam Jeniski
a889d088ae franz newline 2026-04-23 15:38:55 -04:00
Adam Jeniski
484e507af1 init 2017 2026-04-23 15:36:25 -04:00
7057247936 do day 12 2025-12-31 19:37:09 -10:00
52e2bf8202 redundant do 2025-12-29 09:12:51 -05:00
0616318a09 add default pretty printed tap> 2025-12-29 09:11:22 -05:00
e851c41935 fix orderings to match comment better 2025-12-29 08:46:51 -05:00
ajet
5a1773ca77 update gitignore 2025-12-26 21:56:10 -05:00
db1a89199b golf 2025-12-22 18:06:10 -05:00
e51b3296d6 golf 2025-12-22 18:02:29 -05:00
14ac947ae3 golf 2025-12-22 18:00:33 -05:00
8fa11862e1 use java deps for z3 2025-12-22 17:55:11 -05:00
d55ca4c019 franz newline 2025-12-19 08:52:47 -10:00
f88a28cad2 finish day 11 2025-12-19 13:35:51 -05:00
d04209497b do day11 part 1 2025-12-19 08:07:31 -10:00
9ea11f35c9 rename 2025-12-12 12:21:02 -10:00
50e6464eba golf 2025-12-12 12:19:40 -10:00
56a1bed93d rename, format 2025-12-12 09:31:42 -10:00
d379c21296 do day 10 2025-12-12 09:17:55 -10:00
a2492b2b2a renames 2025-12-09 06:33:04 -10:00
d2e6f920f3 simplify 2025-12-09 06:20:28 -10:00
aae7ad038b simplify 2025-12-08 22:32:23 -10:00
5ca7f15404 golf + comments 2025-12-08 22:29:46 -10:00
c47c11a973 golf 2025-12-08 22:20:28 -10:00
055a37a089 rename var 2025-12-08 22:18:16 -10:00
37c2786336 spacing 2025-12-08 22:16:53 -10:00
bcffe4e5bf golf 2025-12-08 22:14:19 -10:00
b0bbb1fcdb do day 9 2025-12-08 21:42:38 -10:00
9e57a7dffb golf 2025-12-08 15:08:59 -10:00
4e5cba07bf golf 2025-12-08 15:07:48 -10:00
f70ba6d543 golf 2025-12-08 15:06:57 -10:00
4eae354f25 rename 2025-12-08 14:01:45 -10:00
da7b893c37 golf 2025-12-08 14:00:26 -10:00
e0fba7c72f remove dead code 2025-12-08 06:33:28 -10:00
4c101f2afa do day 8 2025-12-07 20:22:59 -10:00
4e548d4d40 do day 7 2025-12-06 20:03:01 -10:00
ac6c0097e6 golf 2025-12-06 05:58:21 -10:00
63746d88b8 remove lein repl history 2025-12-06 05:37:33 -10:00
c4cafb19b0 reduce superiority 2025-12-06 05:36:39 -10:00
2ef3eb8d2c inline var 2025-12-05 20:46:33 -10:00
b0d0cf5b59 golf 2025-12-05 20:44:22 -10:00
fdd38bd6b1 franz newline 2025-12-05 20:36:52 -10:00
5289e1dfdf simplify 2025-12-05 20:34:10 -10:00
d853e89137 clean up 2025-12-05 20:31:57 -10:00
0093533054 do day 6 2025-12-05 20:20:15 -10:00
940135c14c do day 5 2025-12-05 12:00:47 -10:00
7f4c260855 do day3 2025-12-04 11:06:46 -10:00
6306a76b7e remove unused dep 2025-12-04 11:04:17 -10:00
a9b1c35984 do day 4 2025-12-04 09:53:17 -10:00
318092c1c5 do day 2 2025-12-04 09:53:10 -10:00
32 changed files with 975 additions and 29 deletions
+3
View File
@@ -17,3 +17,6 @@ target/
.cpcache
.calva
.nrepl-port
## intellij nonsense
.idea
+4
View File
@@ -0,0 +1,4 @@
input/
.lein-repl-history
.idea/
*.iml
+15
View File
@@ -0,0 +1,15 @@
(defproject org.ajet/advent-of-code "0.0.0-SNAPSHOT"
:description "my 2017 advent of code solutions in clojure"
:url "http://github.com/ajetski/advent-of-code"
:min-lein-version "2.0.0"
:jvm-opts ["-Xmx16g"]
:plugins [[cider/cider-nrepl "0.57.0"]]
:dependencies [[org.clojure/clojure "1.12.0"]
[org.clojure/data.priority-map "1.2.0"]
[org.clojure/math.combinatorics "0.3.0"]
[babashka/fs "0.5.23"]
[org.babashka/http-client "0.4.22"]
[org.clojure/core.match "1.1.0"]
[clj-python/libpython-clj "2.025"]
[tools.aqua/z3-turnkey "4.14.1"]]
:source-paths ["src" "../shared/clj/src"])
+23
View File
@@ -0,0 +1,23 @@
(ns day01
(:require input-manager))
(defn to-digit [c] (Character/digit c 10))
(def input (mapv to-digit (input-manager/get-input-raw 2017 01)))
(defn solve [offset]
(let [lookup (fn [idx]
(input (mod idx (count input))))]
(->> input
(map-indexed vector)
(filter (fn [[idx el]]
(= el (lookup (+ offset idx)))))
(map second)
(apply +))))
;; part 1
(solve 1)
;; part 2
(solve (/ (count input) 2))
+25
View File
@@ -0,0 +1,25 @@
(ns day02
(:require input-manager
core))
(def input (mapv (comp #(mapv parse-long %)
core/split-whitespace)
(input-manager/get-input 2017 02)))
;; part 1
(->> input
(map (comp #(apply - %)
(juxt #(apply max %)
#(apply min %))))
(apply +))
(defn find-divisible [l]
(or (first
(for [a (range (count l))
b (range (count l))
:when (and (not= a b)
(= (mod (l a) (l b)) 0))]
(/ (l a) (l b))))
0))
(apply + (map find-divisible input))
+18
View File
@@ -0,0 +1,18 @@
(ns day04
(:require input-manager
core))
(def input (map core/split-whitespace (input-manager/get-input 2017 04)))
;; part 1
(->> input
(filter #(= (count %)
(count (into #{} %))))
count)
;; part 2
(->> input
(filter #(= (count (into #{} (map frequencies %)))
(count %)))
count)
+30
View File
@@ -0,0 +1,30 @@
(ns day05
(:require input-manager))
(def input (->> (input-manager/get-input 2017 5)
(mapv parse-long)))
(def MAX_IDX (count input))
;; part 1
(loop [steps 0
maze input
idx 0]
(let [maze' (update maze idx inc)
idx' (+ (maze idx) idx)]
(if (< -1 idx' MAX_IDX)
(recur (inc steps) maze' idx')
(inc steps))))
;; part 2
(loop [steps 0
maze input
idx 0]
(let [offset (maze idx)
maze' (update maze idx (if (>= offset 3)
dec
inc))
idx' (+ offset idx)]
(if (< -1 idx' MAX_IDX)
(recur (inc steps) maze' idx')
(inc steps))))
+26
View File
@@ -0,0 +1,26 @@
(ns day06
(:require [input-manager]
[core :refer [split-whitespace]]))
(def input
(->> (input-manager/get-input-raw 2017 6)
split-whitespace
(mapv parse-long)))
(loop [state input
i 0
seen {}]
(if (contains? seen state)
{:part-one i
:part-two (- i (seen state))}
(let [cnt (apply max state)
idx (->> state
(map-indexed vector)
(filter #(= (second %) cnt))
ffirst)]
(recur (->> (range cnt)
(map #(mod (+ idx 1 %) (count state)))
(reduce #(update %1 %2 inc) (assoc state idx 0)))
(inc i)
(assoc seen state i)))))
+67
View File
@@ -0,0 +1,67 @@
(ns day07
(:require
[clojure.string :as str]
[core :refer [split-whitespace]]
[input-manager]))
(def input
(->> (input-manager/get-input-raw 2017 7)
str/split-lines
(map (comp split-whitespace
#(str/replace % #"," "")))))
;; part 1
(def base-node
(->> input
(filter (fn [[_ _ _ & children]] children))
(filter (fn [[node]]
(empty? (filter (fn [[_ _ _ & children]]
(some #(= % node) children))
input))))
ffirst))
(do
(def get-depth
(memoize (fn [node]
(let [[_ w-str _ & children] (first (filter (fn [[n]] (= node n))
input))
w (parse-long (subs w-str 1 (dec (count w-str))))]
(apply + w (map get-depth children))))))
(def get-weight
(memoize (fn [node]
(let [w-str (->> input
(filter (fn [[n]] (= node n)))
first
second)]
(parse-long (subs w-str 1 (dec (count w-str))))))))
(def get-children
(memoize (fn [node] (->> input
(filter (fn [[n]] (= node n)))
first
(drop 3))))))
(defn get-children-data [node]
(map (juxt identity get-depth get-weight) (get-children node)))
(defn get-counts [data]
(->> data
(map second)
frequencies
(sort-by second)))
;; part 2
(let [[bad-parent bad-node]
(loop [parent nil
node base-node]
(let [data (get-children-data node)
counts (get-counts data)
row (first (filter #(= (second %) (ffirst counts)) data))]
(if (= (count counts) 1)
[parent node]
(recur node (first row)))))
diff (->> bad-parent
get-children-data
get-counts
(map first)
(apply -))]
(- (get-weight bad-node) diff))
+46
View File
@@ -0,0 +1,46 @@
(ns day08
(:require
[clojure.string :as str]
[core]
[input-manager]))
(def op {"inc" +
"dec" -})
(def cond-op {"<" <
"<=" <=
">" >
">=" >=
"==" =
"!=" not=})
(def input (map (comp
(fn [[name operation num _ cond-name cond-operation cond-val]]
[name
(op operation)
(parse-long num)
cond-name
(cond-op cond-operation)
(parse-long cond-val)])
core/split-whitespace)
(input-manager/get-input 2017 8)))
(defn compute [acc [reg reg-op val cond-reg cond-op cond-val]]
(if (cond-op (acc cond-reg 0) cond-val)
(assoc acc reg (reg-op (acc reg 0) val))
acc))
;; part 1
(->> input
(reduce compute {})
(sort-by second)
last
second)
;; part 2
(->> input
(reductions compute {})
(mapcat identity)
set
(sort-by second)
last
second)
+34
View File
@@ -0,0 +1,34 @@
(ns day09
(:require [clojure.string :as str]
core
input-manager))
(def input (input-manager/get-input-raw 2017 9))
(defn sum-recursive-depths [s sum idx depth]
(if (>= idx (count s))
sum
(condp = (.charAt s idx)
\, (recur s sum (inc idx) depth)
\{ (recur s
(+ sum depth)
(inc idx)
(inc depth))
\} (recur s
sum
(inc idx)
(max (dec depth) 0)))))
(defn exlam-canceler [s] (str/replace s #"!." ""))
(def angle-bracket-regex #"<[^>]*>")
(-> input
exlam-canceler
(str/replace angle-bracket-regex "")
(sum-recursive-depths 0 0 1))
(->> input
exlam-canceler
(re-seq angle-bracket-regex)
(map #(- (count %) 2))
(reduce +))
+27
View File
@@ -0,0 +1,27 @@
(ns day11
(:require [core]
input-manager
[clojure.string :as str]))
(def input (-> (input-manager/get-input-raw 2017 11)
(str/split #",")))
(def offsets {"n" [0 1]
"ne" [0.5 0.5]
"se" [0.5 -0.5]
"s" [0 -1]
"sw" [-0.5 -0.5]
"nw" [-0.5 0.5]})
(defn distance-from-origin [pos]
(let [[x y] (map abs pos)]
(+ (* x 2) (- y x))))
(->> input
(map offsets)
(reductions #(map + %1 %2) [0 0])
(map distance-from-origin)
((juxt last (partial apply max)))
(zipmap [:part-one :part-two]))
+34
View File
@@ -0,0 +1,34 @@
(ns day12
(:require
[clojure.string :as str]
core
input-manager
[clojure.set :refer [difference]]))
(def input (->> (input-manager/get-input 2017 12)
(map #(str/replace % #"," ""))
(map core/split-whitespace)
(map (fn [[a _ & rst]]
[(parse-long a) (mapv parse-long rst)]))
(into {})))
(defn group-from-start [start]
(loop [visited #{}
queue [start]]
(if-not (seq queue)
visited
(let [[curr & rst] queue
ns (filter (complement visited) (input curr))]
(recur (into visited ns)
(concat rst ns))))))
;; part one
(count (group-from-start 0))
;; part two
(loop [ks (into #{} (keys input))
i 0]
(if-not (seq ks)
i
(recur (difference ks (group-from-start (first ks)))
(inc i))))
+58
View File
@@ -0,0 +1,58 @@
(ns day13
(:require
[clojure.string :as str]
[core]
[input-manager]))
(def lengths (->> (input-manager/get-input 2017 13)
(map (comp #(mapv parse-long %)
#(str/split % #": ")))
(into {})))
(defn move-sensor [{:keys [idx depth increasing-depth] :as sensor}]
(let [[keep-moving reverse-step] (if increasing-depth [inc dec] [dec inc])
depth' (keep-moving depth)]
(if (or (> depth' (dec (lengths idx)))
(< depth' 0))
(-> sensor
(update :depth reverse-step)
(update :increasing-depth not))
(assoc sensor :depth depth'))))
(def initial-sensors (->> lengths
keys
(map #(hash-map :depth 0
:idx %
:increasing-depth true))))
(defn is-spotted-by-sensors [acc pos]
(some #(when (and (= (:idx %) pos)
(= (:depth %) 0))
%)
(:sensors acc)))
(->> lengths keys (apply max) inc range
(reduce (fn [acc pos]
(let [spotted (is-spotted-by-sensors acc pos)]
(-> acc
(update :sensors (partial map move-sensor))
(update :solution + (if spotted
(* pos (lengths pos))
0)))))
{:sensors initial-sensors
:solution 0})
:solution)
(loop [i 0
start-val initial-sensors]
(if
(= true
(->> lengths keys (apply max) inc range
(reduce (fn [acc pos]
(let [spotted (is-spotted-by-sensors acc pos)]
(if spotted
(reduced true)
(update acc :sensors (partial map move-sensor)))))
{:sensors start-val})))
(recur (inc i) (map move-sensor start-val))
i))
+11
View File
@@ -0,0 +1,11 @@
(ns user
(:require
[clojure.pprint :as pprint]))
(defonce printer (bound-fn* pprint/pprint))
(add-tap printer)
(comment
;; tap debugging
(remove-tap printer))
+19 -25
View File
@@ -1,37 +1,31 @@
(ns day03
(:require [core :as c]
[input-manager :refer [get-input]]
(:require [input-manager]
[clojure.string :as str]))
(def input (str/join (get-input 3)))
(def input (input-manager/get-input-raw 2024 3))
(defn parse-muls
"takes in a string containing mul instructions
returns list of parsed integral multiplication results"
[s]
(->> (c/get-match-groups #"mul\((\d{1,3}),(\d{1,3})\)" s)
(map #(map parse-long %))
(map #(reduce * %))))
(defn compute-muls [s]
(map (comp #(reduce * %)
#(map parse-long %)
#(str/split % #",")
#(subs % 4 (dec (count %)))) ;; remove `mul(` prefix and `)` suffix
s))
(defn enforce-toggles [[el & rst]]
(cond (= el "do()") (recur rst)
(= el "don't()") (recur (drop-while #(not= % "do()") rst))
el (conj (lazy-seq (enforce-toggles rst)) el)))
;; part 1
(->> input
parse-muls
(re-seq #"mul\(\d{1,3},\d{1,3}\)")
compute-muls
(reduce +))
;; part 2
(->> input
(c/re-pos #"mul\((\d{1,3}),(\d{1,3})\)|(do\(\))|(don't\(\))")
(sort-by key)
(reduce
(fn [acc [_idx instr]]
(cond
(.startsWith instr "mul") (if (:on acc)
(update acc :val
+ (->> instr parse-muls first))
acc)
(.startsWith instr "don't") (assoc acc :on false)
(.startsWith instr "do") (assoc acc :on true)))
{:on true
:val 0})
:val)
(re-seq #"mul\(\d{1,3},\d{1,3}\)|do\(\)|don't\(\)")
enforce-toggles
compute-muls
(reduce +))
+1
View File
@@ -1,3 +1,4 @@
input/
.lein-repl-history
.idea/
*.iml
View File
+4 -2
View File
@@ -9,5 +9,7 @@
[org.clojure/math.combinatorics "0.3.0"]
[babashka/fs "0.5.23"]
[org.babashka/http-client "0.4.22"]
[org.clojure/core.match "1.1.0"]]
:source-paths ["src" "../shared/clj/src"])
[org.clojure/core.match "1.1.0"]
[clj-python/libpython-clj "2.025"]
[tools.aqua/z3-turnkey "4.14.1"]]
:source-paths ["src" "../shared/clj/src"])
+1 -2
View File
@@ -1,6 +1,5 @@
(ns day01
(:require input-manager
#_[clojure.string :as str]))
(:require input-manager))
(defn parse-line [line]
[(.charAt line 0)
+55
View File
@@ -0,0 +1,55 @@
(ns day02
(:require
[clojure.string :as str]
input-manager))
(defn split-comma [s] (str/split s #","))
(def input (->> (input-manager/get-input-raw 2025 2)
#_"11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124"
split-comma
(map (comp #(map parse-long %)
#(str/split % #"-")))))
(defn splitable-num? [n]
(let [s (str n)
len (count s)
parition (int (/ len 2))]
(and (even? len)
(= (.substring s 0 parition) (.substring s parition)))))
;; part 1
(->> input
(map (fn [[a b]]
(filter splitable-num? (range a (inc b)))))
(mapcat identity)
(apply +))
(defn repeated-num? [n]
(let [s (str n)
len (count s)]
(loop [L 1]
(cond
;; Stop if the potential substring length L exceeds half the total length
;; (a repetition must be at least twice the substring length)
(> L (/ len 2)) false
;; Check if L is a divisor of len. If not, this L can't form a full repetition.
(not= (mod len L) 0) (recur (inc L))
;; L is a divisor. Check if the string is formed by repeating the first L characters.
:else
(let [substring (subs s 0 L)
num-repetitions (/ len L)
repeated-string (apply str (repeat num-repetitions substring))]
(if (= s repeated-string)
true
(recur (inc L))))))))
;; part 2
(->> input
(map (fn [[a b]]
(filter repeated-num? (range a (inc b)))))
(mapcat identity)
(apply +))
+26
View File
@@ -0,0 +1,26 @@
(ns day03
(:require input-manager))
(def input (input-manager/get-input 2025 3))
(defn max-joltage [bank num-batteries-to-activate]
(let [len (count bank)]
(loop [n num-batteries-to-activate
acc ""
idx-iter 0]
(let [search-space (.substring bank idx-iter (- len (dec n)))
max-char (apply max (map int search-space))
max-char-idx (.indexOf bank max-char idx-iter)]
(if (= n 1)
(parse-long (str acc (char max-char)))
(recur (dec n)
(str acc (char max-char))
(inc max-char-idx)))))))
(->> input
(map #(max-joltage % 2))
(apply +))
(->> input
(map #(max-joltage % 12))
(apply +))
+41
View File
@@ -0,0 +1,41 @@
(ns day04
(:require input-manager
core))
(def input (input-manager/get-input 2025 4))
(def grid (core/map-by-coords input))
(def offsets [[-1 -1] [-1 0] [-1 1]
[0 -1] [0 1]
[1 -1] [1 0] [1 1]])
;; part 1
(->> grid
(filter (fn [[_ v]]
(= v \@)))
(map first)
(filter (fn [pos]
(< (count (filter (comp (partial = \@) grid)
(for [o offsets]
(mapv + pos o))))
4)))
count)
;; part 2
(loop [grid grid
acc 0]
(let [locs
(->> grid
(filter (fn [[_ v]]
(= v \@)))
(map first)
(filter (fn [pos]
(< (count (filter (comp (partial = \@) grid)
(for [o offsets]
(mapv + pos o))))
4))))]
(if (empty? locs)
acc
(recur (reduce #(dissoc %1 %2) grid locs)
(+ acc (count locs))))))
+28
View File
@@ -0,0 +1,28 @@
(ns day05
(:require input-manager))
(let [[ranges [_ & nums]] (->> (input-manager/get-input 2025 5)
(split-with (partial not= "")))]
(def ranges (sort (mapv (comp #(mapv parse-long %)
#(re-seq #"\d+" %))
ranges)))
(def nums (mapv parse-long nums)))
(defn fresh? [num]
(some (fn [[a b]]
(<= a num b))
ranges))
;; part 1
(count (filter fresh? nums))
;; part 2
(->> ranges
(reduce (fn [[fresh-cnt max-seen :as acc]
[a b]]
(cond (>= max-seen b) acc
(>= max-seen a) [(+ fresh-cnt (- b max-seen)) b]
:else [(+ fresh-cnt (inc (- b a))) b]))
[0 0])
first)
+35
View File
@@ -0,0 +1,35 @@
(ns day06
(:require input-manager))
(def input (input-manager/get-input 2025 6))
(def numeric-line? (comp not #{\* \+} first))
(def numeric-lines (take-while numeric-line? input))
(def nums (map #(map parse-long (re-seq #"\d+" %)) numeric-lines))
(def ops (->> (drop-while numeric-line? input)
first
(filter (partial not= \space))
(mapv {\+ +, \* *})))
;; part 1
(apply + (apply map (fn [op & rst] (apply op rst))
ops
nums))
;; part 2
(->> (range (count (first numeric-lines)))
(reduce (fn [{:keys [op-idx curr-nums] :as acc} col-idx]
(let [op (ops op-idx)
col (->> (map #(.charAt % col-idx) numeric-lines)
(filter (partial not= \space))
(map #(- (int %) (int \0))))]
(if (empty? col)
(-> (update acc :ans + (apply op curr-nums))
(update :op-idx inc)
(assoc :curr-nums []))
(update acc :curr-nums conj (parse-long (apply str col))))))
{:ans 0, :op-idx 0, :curr-nums []})
((juxt :ans
#(apply (last ops) (:curr-nums %))))
(apply +))
+55
View File
@@ -0,0 +1,55 @@
(ns day07
(:require input-manager
core))
(def input (input-manager/get-input 2025 7))
(def start ((core/map-to-coords input) \S))
(def grid (core/map-by-coords input))
(def NUM_ROWS (count input))
(defn left [loc] (update loc 1 dec))
(defn right [loc] (update loc 1 inc))
(defn down [loc] (update loc 0 inc))
(defn splitter? [loc] (= (grid loc) \^))
;; part 1
(->> (range NUM_ROWS)
(reduce (fn [{:keys [acc search-locs]} _]
(if (empty? search-locs)
(reduced acc)
(let [next-locs (map down search-locs)
splitters (filter splitter? next-locs)
next-locs (-> #{}
(into (filter (complement splitter?) next-locs))
(into (mapcat (juxt left right) splitters)))]
{:acc (into acc splitters)
:search-locs next-locs})))
{:acc #{}, :search-locs #{start}})
:acc
count)
(defn left-entry [[loc cnt]] [(left loc) cnt])
(defn right-entry [[loc cnt]] [(right loc) cnt])
(defn splitter-entry? [[loc _]] (= (grid loc) \^))
(defn join-flows [flows]
(reduce (fn [acc [loc cnt]]
(if (acc loc)
(update acc loc + cnt)
(assoc acc loc cnt)))
{}
flows))
;; part 2
(->> (range NUM_ROWS)
(reduce (fn [{:keys [acc search-locs]} _]
(if (empty? search-locs)
(reduced acc)
(let [next-locs (update-keys search-locs down)
splitters (filter splitter-entry? next-locs)
next-locs (join-flows (concat (filter (complement splitter-entry?) next-locs)
(mapcat (juxt left-entry right-entry) splitters)))]
{:acc (apply + acc (map (fn [[_ cnt]] cnt) splitters))
:search-locs next-locs})))
{:acc 1, :search-locs {start 1}})
:acc)
+51
View File
@@ -0,0 +1,51 @@
(ns day08
(:require input-manager clojure.set))
(def input (->> (input-manager/get-input 2025 8)
(mapv (comp (partial mapv parse-long)
(partial re-seq #"\d+")))))
(def initial-circuits (into #{} (map hash-set input)))
(defn square [x] (* x x))
(defn dist-squared [[ax ay az] [bx by bz]]
(+ (square (- ax bx))
(square (- ay by))
(square (- az bz))))
(def closest-points (->> (for [a input
b input
:when (not= a b)]
#{a b})
distinct
(map vec)
(sort-by (partial apply dist-squared))))
;; part 1
(->> (take 1000 closest-points)
(reduce (fn [circuits [a b]]
(let [circuit-a (first (filter #(% a) circuits))
circuit-b (first (filter #(% b) circuits))]
(if (= circuit-a circuit-b)
circuits
(let [combined (clojure.set/union circuit-a circuit-b)]
(-> circuits (disj circuit-a) (disj circuit-b) (conj combined))))))
initial-circuits)
(sort-by count)
(take-last 3)
(map count)
(apply *))
;; part 2
(->> (take 6498 closest-points)
(reduce (fn [circuits [a b]]
(let [circuit-a (first (filter #(% a) circuits))
circuit-b (first (filter #(% b) circuits))]
(if (= circuit-a circuit-b)
circuits
(let [combined (clojure.set/union circuit-a circuit-b)
circuits' (-> circuits (disj circuit-a) (disj circuit-b) (conj combined))]
(if (= 1 (count circuits'))
(reduced [a b])
circuits')))))
initial-circuits)
(map first)
(apply *))
+51
View File
@@ -0,0 +1,51 @@
(ns day09
(:require [input-manager]))
(def input (->> (input-manager/get-input 2025 9)
(mapv #(mapv parse-long (re-seq #"\d+" %)))))
(defn area [[ax ay] [bx by]]
(* (inc (abs (- ax bx)))
(inc (abs (- ay by)))))
(def largest-rects (->> (for [a input
b input
:when (not= a b)]
#{a b})
distinct
(map vec)
(sort-by #(apply area %))))
;; part 1
(->> largest-rects
last
(apply area))
(defn normalize [x] (min 1 (max -1 x)))
(defn orientation
"returns a value indicating if point B is to the left, right, or on the line AC"
[[ax ay] [bx by] [cx cy]]
(normalize (- (* (- by ay) (- cx bx))
(* (- bx ax) (- cy by)))))
(defn intersect?
"Lines AB and CD intersect if points A and B falls on different sides of CD
and if C and D fall on different sides of AB"
[[a b] [c d]]
(let [o1 (orientation a c b)
o2 (orientation a d b)
o3 (orientation c a d)
o4 (orientation c b d)]
(and (not= o1 o2) (not= o3 o4))))
(def line-segments (map vector input (rest input)))
;; part 2
(->> largest-rects
(filter (fn [[a b :as rect]]
(let [segments (filter (fn overlapping? [[c d]]
(and (not= a c) (not= a d)
(not= b c) (not= b d))) ;; filter out segments that include points a or b
line-segments)
[[cx cy] [dx dy]] rect
reverse-diag [[cx dy] [dx cy]]]
(and (not (some #(intersect? rect %) segments))
(not (some #(intersect? reverse-diag %) segments))))))
(map (partial apply area))
sort
last)
+71
View File
@@ -0,0 +1,71 @@
(ns day10
(:require [clojure.math.combinatorics :as combo]
[input-manager])
(:import (com.microsoft.z3 Context Expr IntNum Optimize Optimize$Handle)))
(defn parse-line [line]
{:indicators (->> line
(drop 1)
(take-while (complement #{\]}))
(mapv (partial = \#)))
:buttons (->> line
(re-seq #"\([\d,]+\)")
(map #(map parse-long (re-seq #"\d+" %))))
:joltages (->> line
(drop-while #(not= % \{))
(drop 1)
(take-while #(not= % \}))
(apply str)
(re-seq #"\d+")
(mapv parse-long))})
(def input (map parse-line (input-manager/get-input 2025 10)))
(defn minimum-button-mashing [{:keys [buttons indicators]}]
(loop [i 0
cnt 1]
(if (>= i (combo/count-combinations buttons cnt))
(recur 0 (inc cnt))
(let [indicators' (reduce (partial reduce #(update %1 %2 not))
indicators
(combo/nth-combination buttons cnt i))]
(if (every? (complement identity) indicators')
cnt
(recur (inc i) cnt))))))
;; part 1
(apply + (map minimum-button-mashing input))
;; part 2
(defn add-expressions [opt expressions]
(.Add opt (into-array Expr expressions)))
(->> input
(map (fn [{:keys [joltages buttons]}]
(let [ctx (Context.)
^Optimize opt (.mkOptimize ctx)
bs (->> buttons
count
range
(map #(.mkIntConst ctx (str "b" %))))
js (->> joltages
count
range
(map #(.mkIntConst ctx (str "j" %))))]
(add-expressions opt (for [idx (range (count joltages))]
(.mkEq ctx (nth js idx) (->> buttons
(map set)
(map-indexed vector)
(filter #(contains? (second %) idx))
(map first)
(map #(nth bs %))
(into-array Expr)
(.mkAdd ctx)))))
(add-expressions opt (for [[idx joltage] (map-indexed vector joltages)]
(.mkEq ctx (nth js idx) (.mkInt ctx (long joltage)))))
(add-expressions opt (for [b bs]
(.mkGe ctx b (.mkInt ctx (long 0)))))
(let [^Optimize$Handle mx (.MkMinimize opt (.mkAdd ctx (into-array Expr bs)))]
(.Check opt (into-array Expr []))
(.getInt ^IntNum (.getValue mx))))))
(apply +))
+21
View File
@@ -0,0 +1,21 @@
(ns day11
(:require [input-manager]))
(def input (->> (input-manager/get-input 2025 11)
(map (comp (fn [[node & edges]]
[node (into #{} edges)])
(partial re-seq #"[a-z]{3}")))
(into {})))
(def count-paths (memoize (fn [start target]
(let [edges (input start)]
(if (contains? edges target)
1
(apply + (map #(count-paths % target) edges)))))))
;; part 1
(count-paths "you" "out")
;; part 2
(+ (* (count-paths "svr" "dac") (count-paths "dac" "fft") (count-paths "fft" "out"))
(* (count-paths "svr" "fft") (count-paths "fft" "dac") (count-paths "dac" "out")))
+84
View File
@@ -0,0 +1,84 @@
(ns day12
(:require input-manager
core
[clojure.string :as str]
clojure.set))
(def requirements (->> (input-manager/get-input-raw 2025 12)
(core/split-on-double-newlines)
(map str/split-lines)
last
(map (comp (fn [[x y & cnts]]
[[x y] (into {} (map-indexed vector cnts))])
(partial map parse-long)
(partial re-seq #"\d+")))))
(defn fits-trivially?
"is it trivially possible to fit all the pieces if they were 3x3 blocks instead of jigsaws"
[[dimensions cnts]]
(let [area (apply * dimensions)
guess (->> cnts vals (reduce +) (* 9))]
(>= area guess)))
;; part 1
(->> requirements
(filter fits-trivially?)
count)
(comment
;; NP Hard... general solution is not fast enough
(defn flip [grid]
(vec (reverse grid)))
(defn rotations [grid]
(->> [(for [x (range 0 3)]
(for [y (range 0 3)]
(.charAt (grid x) y)))
(for [y (range 2 -1 -1)]
(for [x (range 0 3)]
(.charAt (grid x) y)))
(for [x (range 2 -1 -1)]
(for [y (range 2 -1 -1)]
(.charAt (grid x) y)))
(for [y (range 2 -1 -1)]
(for [x (range 3)]
(.charAt (grid x) y)))]
(map (partial map-indexed (fn [row-idx row]
(map-indexed (fn [col-idx cell]
(when (= cell \#)
[row-idx col-idx]))
row))))
(map (partial mapcat (partial filter identity)))
(mapv (partial mapv vec))
set))
#_(def jigsaws (->> (drop-last (->> (input-manager/get-input-raw 2025 12)
(core/split-on-double-newlines)
(map str/split-lines)))
(map (fn [[idx & puzzle-lines]]
[(parse-long (apply str (drop-last idx)))
(clojure.set/union (rotations (vec puzzle-lines)) (rotations (flip puzzle-lines)))]))
(into {})))
(defn placeable? [jigsaw filled]
(every? #(not (contains? filled %)) jigsaw))
(defn offset [loc jigsaw]
(into #{} (map #(mapv + % loc) jigsaw)))
(defn fits? [[[rows cols :as dimensions] cnts] jigsaws filled]
(cond
(every? (partial = 0) (vals cnts)) true
:else
(let [[id] (first (filter (fn [[_ cnt]] (> cnt 0)) cnts))
orientations (jigsaws id)
locs (for [row (range (- rows 2))
col (range (- cols 2))]
[row col])
cnts' (update cnts id dec)]
(some (fn [loc]
(->> orientations
(map #(offset loc %))
(filter #(placeable? % filled))
(map #(fits? [dimensions cnts'] jigsaws (clojure.set/union filled %)))
(filter identity)
first))
locs)))))
+11
View File
@@ -0,0 +1,11 @@
(ns user
(:require
[clojure.pprint :as pprint]))
(defonce printer (bound-fn* pprint/pprint))
(add-tap printer)
(comment
;; tap debugging
(remove-tap printer))