Compare commits
78 Commits
c577615973
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 56738fd7f9 | |||
|
|
b89c7ce3f2 | ||
|
|
a1db8ae128 | ||
|
|
e6357d9802 | ||
| b62c9346f5 | |||
| 505453974b | |||
| 0aed472a32 | |||
|
|
9703c017a9 | ||
|
|
733c833f66 | ||
| 1087a7649b | |||
| 5077215205 | |||
|
|
8ff632503f | ||
|
|
a889d088ae | ||
|
|
484e507af1 | ||
| 7057247936 | |||
| 52e2bf8202 | |||
| 0616318a09 | |||
| e851c41935 | |||
|
|
5a1773ca77 | ||
| db1a89199b | |||
| e51b3296d6 | |||
| 14ac947ae3 | |||
| 8fa11862e1 | |||
| d55ca4c019 | |||
| f88a28cad2 | |||
| d04209497b | |||
| 9ea11f35c9 | |||
| 50e6464eba | |||
| 56a1bed93d | |||
| d379c21296 | |||
| a2492b2b2a | |||
| d2e6f920f3 | |||
| aae7ad038b | |||
| 5ca7f15404 | |||
| c47c11a973 | |||
| 055a37a089 | |||
| 37c2786336 | |||
| bcffe4e5bf | |||
| b0bbb1fcdb | |||
| 9e57a7dffb | |||
| 4e5cba07bf | |||
| f70ba6d543 | |||
| 4eae354f25 | |||
| da7b893c37 | |||
| e0fba7c72f | |||
| 4c101f2afa | |||
| 4e548d4d40 | |||
| ac6c0097e6 | |||
| 63746d88b8 | |||
| c4cafb19b0 | |||
| 2ef3eb8d2c | |||
| b0d0cf5b59 | |||
| fdd38bd6b1 | |||
| 5289e1dfdf | |||
| d853e89137 | |||
| 0093533054 | |||
| 940135c14c | |||
| 7f4c260855 | |||
| 6306a76b7e | |||
| a9b1c35984 | |||
| 318092c1c5 | |||
| 4d525dd3a7 | |||
| de3c367d1c | |||
| 171a4d285d | |||
| 66c7ee02d4 | |||
| 0492cb1155 | |||
| 116bc23a2c | |||
| 4418b4da78 | |||
| eb2ca945da | |||
| 249fcb00b6 | |||
| 23b5ed2e90 | |||
| aae825a9df | |||
| 463a291744 | |||
| f7b77d4fd0 | |||
| b2339a21a6 | |||
| 5e55767409 | |||
|
|
4a5ee3d100 | ||
|
|
1cd6a07cf8 |
@@ -17,3 +17,6 @@ target/
|
|||||||
.cpcache
|
.cpcache
|
||||||
.calva
|
.calva
|
||||||
.nrepl-port
|
.nrepl-port
|
||||||
|
|
||||||
|
## intellij nonsense
|
||||||
|
.idea
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
input/
|
||||||
|
.lein-repl-history
|
||||||
|
*.iml
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
(defproject org.ajet/advent-of-code "0.0.0-SNAPSHOT"
|
||||||
|
:description "my 2024 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"]]
|
||||||
|
:source-paths ["src" "../shared/clj/src"])
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
(ns day01
|
||||||
|
(:require input-manager))
|
||||||
|
|
||||||
|
(def input (input-manager/get-input-raw 2015 01))
|
||||||
|
|
||||||
|
(def up? #{\(})
|
||||||
|
(def down? #{\)})
|
||||||
|
|
||||||
|
;; part 1
|
||||||
|
(-
|
||||||
|
(count (filter up? input))
|
||||||
|
(count (filter down? input)))
|
||||||
|
|
||||||
|
;; part 2
|
||||||
|
(loop [i 0
|
||||||
|
floor 0]
|
||||||
|
(cond
|
||||||
|
(< floor 0) i
|
||||||
|
|
||||||
|
(up? (.charAt input i))
|
||||||
|
(recur (inc i)
|
||||||
|
(inc floor))
|
||||||
|
|
||||||
|
:else
|
||||||
|
(recur (inc i)
|
||||||
|
(dec floor))))
|
||||||
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
(ns day02
|
||||||
|
(:require [input-manager]))
|
||||||
|
|
||||||
|
(defn parse-line
|
||||||
|
"s is a string in the form of lxwxh, whee l, w, and h are integral patterns"
|
||||||
|
[s]
|
||||||
|
(map parse-long (re-seq #"\d+" s)))
|
||||||
|
|
||||||
|
(def input (->> (input-manager/get-input 2015 2)
|
||||||
|
(map parse-line)))
|
||||||
|
|
||||||
|
(defn smallest-side [[l w h]]
|
||||||
|
(min (* l w)
|
||||||
|
(* h w)
|
||||||
|
(* l h)))
|
||||||
|
|
||||||
|
(defn paper-needed [[l w h :as args]]
|
||||||
|
(+ (* 2 (+ (* l w) (* w h) (* h l)))
|
||||||
|
(smallest-side args)))
|
||||||
|
|
||||||
|
;; part 1
|
||||||
|
(->> input
|
||||||
|
(map paper-needed)
|
||||||
|
(apply +))
|
||||||
|
|
||||||
|
(defn smallest-perimeter [[l w h]]
|
||||||
|
(* 2 (min (+ l w)
|
||||||
|
(+ h w)
|
||||||
|
(+ l h))))
|
||||||
|
|
||||||
|
(defn volume [[l w h]]
|
||||||
|
(* l w h))
|
||||||
|
|
||||||
|
;; part 2
|
||||||
|
(->> input
|
||||||
|
(map (juxt smallest-perimeter volume))
|
||||||
|
(map #(apply + %))
|
||||||
|
(apply +))
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
(ns day03
|
||||||
|
(:require [input-manager]
|
||||||
|
[clojure.set]))
|
||||||
|
|
||||||
|
(def input (input-manager/get-input-raw 2015 3))
|
||||||
|
|
||||||
|
(defn get-houses [input]
|
||||||
|
(->> input
|
||||||
|
(reduce (fn [[[x y] visited]
|
||||||
|
el]
|
||||||
|
(let [pos' (condp = el
|
||||||
|
\> [(inc x) y]
|
||||||
|
\< [(dec x) y]
|
||||||
|
\^ [x (inc y)]
|
||||||
|
\v [x (dec y)])]
|
||||||
|
[pos' (conj visited pos')]))
|
||||||
|
[[0 0] #{}])
|
||||||
|
second))
|
||||||
|
|
||||||
|
;; part 1
|
||||||
|
(count (get-houses input))
|
||||||
|
|
||||||
|
;; part 2
|
||||||
|
(count (clojure.set/union (get-houses (take-nth 2 input))
|
||||||
|
(get-houses (take-nth 2 (rest input)))))
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
(ns day04
|
||||||
|
(:require [input-manager]
|
||||||
|
[clojure.set])
|
||||||
|
(:import java.security.MessageDigest java.math.BigInteger))
|
||||||
|
|
||||||
|
(def input (input-manager/get-input-raw 2015 4))
|
||||||
|
|
||||||
|
(defn string->md5 [s]
|
||||||
|
(let [algorithm (MessageDigest/getInstance "MD5")
|
||||||
|
raw (.digest algorithm (.getBytes s))]
|
||||||
|
(format "%032x" (BigInteger. 1 raw))))
|
||||||
|
|
||||||
|
(defn solution [target-prefix]
|
||||||
|
(loop [i 0]
|
||||||
|
(let [md5 (string->md5 (str input i))]
|
||||||
|
(if (.startsWith md5 target-prefix)
|
||||||
|
i
|
||||||
|
(recur (inc i))))))
|
||||||
|
|
||||||
|
(solution "00000")
|
||||||
|
(solution "000000")
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
(ns day05
|
||||||
|
(:require [input-manager]
|
||||||
|
[clojure.string :as str]))
|
||||||
|
|
||||||
|
(def input (input-manager/get-input 2015 5))
|
||||||
|
|
||||||
|
(def bad #{"ab" "cd" "pq" "xy"})
|
||||||
|
|
||||||
|
;; part 1
|
||||||
|
(count (filter #(and (not (some (partial str/includes? %) bad))
|
||||||
|
(>= (count (filter #{\a \e \i \o \u} %)) 3)
|
||||||
|
(some (partial apply =) (concat (partition 2 %)
|
||||||
|
(partition 2 (rest %)))))
|
||||||
|
input))
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
input/
|
||||||
|
.lein-repl-history
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
@@ -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"])
|
||||||
@@ -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))
|
||||||
|
|
||||||
@@ -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))
|
||||||
@@ -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)
|
||||||
|
|
||||||
@@ -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))))
|
||||||
@@ -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)))))
|
||||||
|
|
||||||
@@ -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))
|
||||||
@@ -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)
|
||||||
|
|
||||||
@@ -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 +))
|
||||||
@@ -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]))
|
||||||
|
|
||||||
@@ -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))))
|
||||||
@@ -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))
|
||||||
@@ -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))
|
||||||
|
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
input/
|
input/
|
||||||
.lein-repl-history
|
.lein-repl-history
|
||||||
|
*.iml
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# AOC 2024
|
||||||
|
|
||||||
|
## todo (spoilers)
|
||||||
|
15) reimplement to support wide rock
|
||||||
|
16) add backtracking to find all viable paths
|
||||||
|
17) find right input to make computer program output itself
|
||||||
|
20) search in 20x20 grid for larger cheat jumps
|
||||||
|
21) dp for long keypad input sequence
|
||||||
|
24) find the 4 swaps (8 wires) such that the adding machine works for all inputs
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{:deps {org.clojure/clojure {:mvn/version "1.12.0"}
|
|
||||||
org.clojure/math.combinatorics {:mvn/version "0.3.0"}}
|
|
||||||
:paths ["src" "../shared/clj/src"]
|
|
||||||
:tasks {}}
|
|
||||||
+3
-1
@@ -5,7 +5,9 @@
|
|||||||
:jvm-opts ["-Xmx16g"]
|
:jvm-opts ["-Xmx16g"]
|
||||||
:plugins [[cider/cider-nrepl "0.57.0"]]
|
:plugins [[cider/cider-nrepl "0.57.0"]]
|
||||||
:dependencies [[org.clojure/clojure "1.12.0"]
|
:dependencies [[org.clojure/clojure "1.12.0"]
|
||||||
|
[org.clojure/data.priority-map "1.2.0"]
|
||||||
[org.clojure/math.combinatorics "0.3.0"]
|
[org.clojure/math.combinatorics "0.3.0"]
|
||||||
[babashka/fs "0.5.23"]
|
[babashka/fs "0.5.23"]
|
||||||
[org.babashka/http-client "0.4.22"]]
|
[org.babashka/http-client "0.4.22"]
|
||||||
|
[org.clojure/core.match "1.1.0"]]
|
||||||
:source-paths ["src" "../shared/clj/src"])
|
:source-paths ["src" "../shared/clj/src"])
|
||||||
|
|||||||
+14
-16
@@ -1,26 +1,24 @@
|
|||||||
(ns day01
|
(ns day01
|
||||||
(:require
|
(:require input-manager))
|
||||||
[input-manager :refer [get-input]]
|
|
||||||
[core :as c]))
|
|
||||||
|
|
||||||
(def input (->> (get-input 1)
|
|
||||||
(map #(first (c/get-match-groups #"(\d+)\s+(\d+)" %)))
|
|
||||||
(map #(mapv parse-long %))
|
|
||||||
(into {})
|
|
||||||
((juxt keys vals))))
|
|
||||||
|
|
||||||
;; part 1
|
;; part 1
|
||||||
|
(defn every-other [coll]
|
||||||
|
(take-nth 2 coll))
|
||||||
|
|
||||||
|
(def input (->> (input-manager/get-input-raw 2024 1)
|
||||||
|
(re-seq #"\d+")
|
||||||
|
(map parse-long)
|
||||||
|
((juxt every-other (comp every-other rest)))))
|
||||||
|
|
||||||
(->> input
|
(->> input
|
||||||
(map sort)
|
(map sort)
|
||||||
(apply zipmap)
|
(apply map (comp abs -))
|
||||||
(map #(abs (apply - %)))
|
(apply +))
|
||||||
(reduce +))
|
|
||||||
|
|
||||||
;; part 2
|
;; part 2
|
||||||
(let [[a b] input
|
(let [[left-col right-col] input
|
||||||
freqs (frequencies b)]
|
freqs (frequencies right-col)]
|
||||||
(->> a
|
(->> left-col
|
||||||
(map #(* (or (freqs %) 0) %))
|
(map #(* (or (freqs %) 0) %))
|
||||||
(reduce +)))
|
(reduce +)))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+19
-25
@@ -1,37 +1,31 @@
|
|||||||
(ns day03
|
(ns day03
|
||||||
(:require [core :as c]
|
(:require [input-manager]
|
||||||
[input-manager :refer [get-input]]
|
|
||||||
[clojure.string :as str]))
|
[clojure.string :as str]))
|
||||||
|
|
||||||
(def input (str/join (get-input 3)))
|
(def input (input-manager/get-input-raw 2024 3))
|
||||||
|
|
||||||
(defn parse-muls
|
(defn compute-muls [s]
|
||||||
"takes in a string containing mul instructions
|
(map (comp #(reduce * %)
|
||||||
returns list of parsed integral multiplication results"
|
#(map parse-long %)
|
||||||
[s]
|
#(str/split % #",")
|
||||||
(->> (c/get-match-groups #"mul\((\d{1,3}),(\d{1,3})\)" s)
|
#(subs % 4 (dec (count %)))) ;; remove `mul(` prefix and `)` suffix
|
||||||
(map #(map parse-long %))
|
s))
|
||||||
(map #(reduce * %))))
|
|
||||||
|
(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
|
;; part 1
|
||||||
(->> input
|
(->> input
|
||||||
parse-muls
|
(re-seq #"mul\(\d{1,3},\d{1,3}\)")
|
||||||
|
compute-muls
|
||||||
(reduce +))
|
(reduce +))
|
||||||
|
|
||||||
;; part 2
|
;; part 2
|
||||||
(->> input
|
(->> input
|
||||||
(c/re-pos #"mul\((\d{1,3}),(\d{1,3})\)|(do\(\))|(don't\(\))")
|
(re-seq #"mul\(\d{1,3},\d{1,3}\)|do\(\)|don't\(\)")
|
||||||
(sort-by key)
|
enforce-toggles
|
||||||
(reduce
|
compute-muls
|
||||||
(fn [acc [_idx instr]]
|
(reduce +))
|
||||||
(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)
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
(ns day16
|
||||||
|
(:require
|
||||||
|
[input-manager :refer [get-input]]
|
||||||
|
[core :as c]
|
||||||
|
[clojure.data.priority-map :refer [priority-map]]))
|
||||||
|
|
||||||
|
(def maze
|
||||||
|
#_(c/split-whitespace "###############
|
||||||
|
#.......#....E#
|
||||||
|
#.#.###.#.###.#
|
||||||
|
#.....#.#...#.#
|
||||||
|
#.###.#####.#.#
|
||||||
|
#.#.#.......#.#
|
||||||
|
#.#.#####.###.#
|
||||||
|
#...........#.#
|
||||||
|
###.#.#####.#.#
|
||||||
|
#...#.....#.#.#
|
||||||
|
#.#.#.###.#.#.#
|
||||||
|
#.....#...#.#.#
|
||||||
|
#.###.#.#.#.#.#
|
||||||
|
#S..#.....#...#
|
||||||
|
###############")
|
||||||
|
(get-input 2024 16))
|
||||||
|
(def grid (->> maze
|
||||||
|
(map-indexed (fn [row-idx row]
|
||||||
|
(map-indexed (fn [col-idx c]
|
||||||
|
[[row-idx col-idx] c])
|
||||||
|
row)))
|
||||||
|
(mapcat identity)
|
||||||
|
(into {})))
|
||||||
|
(defn find-char [c]
|
||||||
|
(->> grid
|
||||||
|
(filter (comp #{c} second))
|
||||||
|
ffirst))
|
||||||
|
(def start (find-char \S))
|
||||||
|
(def end (find-char \E))
|
||||||
|
|
||||||
|
(defn rotate-clockwise [dir]
|
||||||
|
(condp = dir
|
||||||
|
:right :down
|
||||||
|
:down :left
|
||||||
|
:left :up
|
||||||
|
:up :right))
|
||||||
|
(defn rotate-counterclockwise [dir]
|
||||||
|
(condp = dir
|
||||||
|
:down :right
|
||||||
|
:left :down
|
||||||
|
:up :left
|
||||||
|
:right :up))
|
||||||
|
(defn direction-offset [dir]
|
||||||
|
(condp = dir
|
||||||
|
:up [-1 0]
|
||||||
|
:right [0 1]
|
||||||
|
:down [1 0]
|
||||||
|
:left [0 -1]))
|
||||||
|
|
||||||
|
(defn find-search-path [[start start-dir] goal]
|
||||||
|
(loop [[[[pos dir] cost] & _ :as whole] (priority-map [start start-dir] 0)
|
||||||
|
visited #{[start start-dir]}
|
||||||
|
shortest {start 0}
|
||||||
|
n 0]
|
||||||
|
(if (= pos goal)
|
||||||
|
shortest
|
||||||
|
(let [searches (->> [[[(mapv + pos (direction-offset dir)) dir] (inc cost)]
|
||||||
|
[[pos (rotate-clockwise dir)] (+ 1000 cost)]
|
||||||
|
[[pos (rotate-counterclockwise dir)] (+ 1000 cost)]]
|
||||||
|
(filter (comp not visited first))
|
||||||
|
(filter (comp grid ffirst))
|
||||||
|
(filter (comp not #{\#} grid ffirst)))
|
||||||
|
searches-no-costs (mapv (comp first pop) searches)
|
||||||
|
seaches-no-dirs (mapv (juxt ffirst last) searches)]
|
||||||
|
(recur (into (pop whole) searches)
|
||||||
|
(into visited searches-no-costs)
|
||||||
|
(into (into {} seaches-no-dirs) shortest)
|
||||||
|
(inc n))))))
|
||||||
|
|
||||||
|
(def searched (find-search-path [start :right] end))
|
||||||
|
|
||||||
|
;; part 1 solution
|
||||||
|
(searched end)
|
||||||
|
|
||||||
|
(def max-idx (->> (keys grid)
|
||||||
|
(map first)
|
||||||
|
(apply max)))
|
||||||
|
(def updated-grid (->> grid
|
||||||
|
(map (fn [[k :as entry]] (if (and (contains? searched k) (#{\S \E \.} (grid k)))
|
||||||
|
[k \O]
|
||||||
|
entry)))
|
||||||
|
(into {})))
|
||||||
|
(->> (range 0 max-idx)
|
||||||
|
(map (fn [row] (map #(vector row %) (range 0 max-idx))))
|
||||||
|
(map (partial map updated-grid))
|
||||||
|
(map (partial apply str))
|
||||||
|
(interpose "\n")
|
||||||
|
(apply str)
|
||||||
|
print)
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
(ns day17
|
||||||
|
(:require input-manager
|
||||||
|
[core :as c]
|
||||||
|
[clojure.string :as str]))
|
||||||
|
|
||||||
|
(let [[registers _ [program]]
|
||||||
|
(->> #_(input-manager/get-input 2024 17)
|
||||||
|
"Register A: 729\nRegister B: 0\nRegister C: 0\n\nProgram: 0,1,5,4,3,0"
|
||||||
|
(str/split-lines)
|
||||||
|
(partition-by (partial = "")))]
|
||||||
|
(def registers (update-vals
|
||||||
|
(into {}
|
||||||
|
(map (comp vec
|
||||||
|
rest
|
||||||
|
first
|
||||||
|
(partial re-seq #"(\w)+: (.*)")) registers))
|
||||||
|
parse-long))
|
||||||
|
(def program (mapv parse-long
|
||||||
|
(-> program
|
||||||
|
(str/split #" ")
|
||||||
|
second
|
||||||
|
(str/split #",")))))
|
||||||
|
|
||||||
|
(defn combo-op->value [combo-op registers]
|
||||||
|
(condp = combo-op
|
||||||
|
4 (registers "A")
|
||||||
|
5 (registers "B")
|
||||||
|
6 (registers "C")
|
||||||
|
7 (throw (ex-message "invalid"))
|
||||||
|
combo-op))
|
||||||
|
|
||||||
|
(defn compute
|
||||||
|
([registers program]
|
||||||
|
(compute registers program 0 []))
|
||||||
|
([{A "A", B "B", C "C" :as registers} program instr-ptr out]
|
||||||
|
(if (>= instr-ptr (count program))
|
||||||
|
[out registers]
|
||||||
|
(let [operation (program instr-ptr)
|
||||||
|
operand (program (inc instr-ptr))
|
||||||
|
combo-operand (delay (combo-op->value operand registers))
|
||||||
|
instr-ptr' (+ 2 instr-ptr)]
|
||||||
|
(condp = operation
|
||||||
|
0 (recur (->> (int (/ A (max 1 (bit-shift-left 2 (dec @combo-operand)))))
|
||||||
|
(assoc registers "A"))
|
||||||
|
program instr-ptr' out)
|
||||||
|
1 (recur (->> operand
|
||||||
|
(bit-xor B)
|
||||||
|
(assoc registers "B"))
|
||||||
|
program instr-ptr' out)
|
||||||
|
2 (recur (->> (mod @combo-operand 8)
|
||||||
|
(assoc registers "B"))
|
||||||
|
program instr-ptr' out)
|
||||||
|
3 (if (= A 0)
|
||||||
|
(recur registers program instr-ptr' out)
|
||||||
|
(recur registers program operand out))
|
||||||
|
4 (recur (->> (bit-xor B C)
|
||||||
|
(assoc registers "B"))
|
||||||
|
program instr-ptr' out)
|
||||||
|
5 (recur registers
|
||||||
|
program
|
||||||
|
instr-ptr'
|
||||||
|
(conj out (mod @combo-operand 8)))
|
||||||
|
6 (recur (->> (int (/ A (max 1 (bit-shift-left 2 (dec @combo-operand)))))
|
||||||
|
(assoc registers "B"))
|
||||||
|
program instr-ptr' out)
|
||||||
|
7 (recur (->> (int (/ A (max 1 (bit-shift-left 2 (dec @combo-operand)))))
|
||||||
|
(assoc registers "C"))
|
||||||
|
program instr-ptr' out))))))
|
||||||
|
|
||||||
|
;; part 1
|
||||||
|
(->> (compute registers program)
|
||||||
|
first
|
||||||
|
(interpose ",")
|
||||||
|
(apply str))
|
||||||
|
|
||||||
|
;; part 2
|
||||||
|
(loop [n 0]
|
||||||
|
(when (= (mod n 10000) 0)
|
||||||
|
(println n))
|
||||||
|
(let [res (try (compute (merge registers {"A" n}) program)
|
||||||
|
(catch Exception _e
|
||||||
|
nil))]
|
||||||
|
(if (= (first res) program)
|
||||||
|
n
|
||||||
|
(recur (inc n)))))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
registers
|
||||||
|
program
|
||||||
|
|
||||||
|
(compute {"C" 1} [2 6])
|
||||||
|
(compute {"A" 10} [5, 0, 5, 1, 5, 4])
|
||||||
|
(compute {"A" 2024} [0, 1, 5, 4, 3, 0])
|
||||||
|
(compute {"B" 29} [1, 7])
|
||||||
|
(compute {"B" 2024, "C" 43690} [4 0])
|
||||||
|
)
|
||||||
+2
-3
@@ -22,8 +22,7 @@
|
|||||||
(mapv (constantly 0) puzzle))
|
(mapv (constantly 0) puzzle))
|
||||||
last))
|
last))
|
||||||
|
|
||||||
(let [[w _ & p]
|
(let [[w _ & p] (input-manager/get-input 2024 19)]
|
||||||
(input-manager/get-input 2024 19)]
|
|
||||||
(def words (into #{} (str/split w #", ")))
|
(def words (into #{} (str/split w #", ")))
|
||||||
(def puzzles p))
|
(def puzzles p))
|
||||||
|
|
||||||
@@ -45,5 +44,5 @@
|
|||||||
(valid-combination-count #{"word"} "word") ; 1
|
(valid-combination-count #{"word"} "word") ; 1
|
||||||
|
|
||||||
(increment-counts-for-matching-words #{"wo" "or" "w" "rd" "d"} "word" [0 0 0 0] 0) ; [1 1 0 0]
|
(increment-counts-for-matching-words #{"wo" "or" "w" "rd" "d"} "word" [0 0 0 0] 0) ; [1 1 0 0]
|
||||||
(valid-combination-count #{"wo" "or" "w" "rd" "d"} "word") ; 2, because ("wo" "r" "d") and ("w")
|
(valid-combination-count #{"wo" "or" "w" "rd" "d"} "word") ; 2, because ("wo" "r" "d") and ("w" "or" "d")
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
(ns day20
|
||||||
|
(:require
|
||||||
|
input-manager))
|
||||||
|
|
||||||
|
(def maze (input-manager/get-input 2024 20))
|
||||||
|
(def grid (->> maze
|
||||||
|
(map-indexed (fn [row-idx row]
|
||||||
|
(map-indexed (fn [col-idx c]
|
||||||
|
[[row-idx col-idx] c])
|
||||||
|
row)))
|
||||||
|
(mapcat identity)
|
||||||
|
(into {})))
|
||||||
|
(defn find-char [c]
|
||||||
|
(->> grid
|
||||||
|
(filter (comp #{c} second))
|
||||||
|
ffirst))
|
||||||
|
(def start (find-char \S))
|
||||||
|
(def end (find-char \E))
|
||||||
|
|
||||||
|
(def direction-offsets #{[0 1] [1 0] [0 -1] [-1 0]})
|
||||||
|
|
||||||
|
(defn find-search-path []
|
||||||
|
(loop [[[pos steps] & rst] [[start 0]]
|
||||||
|
visited #{start}
|
||||||
|
shortest {start 0}]
|
||||||
|
(if (= pos end)
|
||||||
|
shortest
|
||||||
|
(let [searches (->> direction-offsets
|
||||||
|
(map (partial mapv + pos))
|
||||||
|
(filter grid)
|
||||||
|
(filter (comp not visited))
|
||||||
|
(filter (comp not #{\#} grid)))
|
||||||
|
searches-w-path-lengths (mapv #(vector % (inc steps)) searches)]
|
||||||
|
(recur (into rst searches-w-path-lengths)
|
||||||
|
(into visited searches)
|
||||||
|
(into shortest searches-w-path-lengths))))))
|
||||||
|
|
||||||
|
(defn find-cheats []
|
||||||
|
(let [search-path (find-search-path)
|
||||||
|
walls (->> grid
|
||||||
|
(filter (comp #{\#} second))
|
||||||
|
(map first))
|
||||||
|
cheats (->> walls
|
||||||
|
(map (fn [pos]
|
||||||
|
(->> direction-offsets
|
||||||
|
(map (partial mapv + pos))
|
||||||
|
(map search-path)
|
||||||
|
(filter identity))))
|
||||||
|
(filter not-empty)
|
||||||
|
(filter (comp (partial <= 2) count))
|
||||||
|
(map sort)
|
||||||
|
(mapcat (fn [[a & bs]]
|
||||||
|
(map #(- % a) bs))))]
|
||||||
|
(frequencies cheats)))
|
||||||
|
|
||||||
|
;; part 1
|
||||||
|
(->> (find-cheats)
|
||||||
|
(filter (comp #(> % 100) first))
|
||||||
|
(map second)
|
||||||
|
(apply +))
|
||||||
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
(ns day22
|
||||||
|
(:require input-manager))
|
||||||
|
|
||||||
|
(def input (->> (input-manager/get-input 2024 22)
|
||||||
|
(map parse-long)))
|
||||||
|
|
||||||
|
(def prune-const 16777216)
|
||||||
|
(defn prune [x] (mod x prune-const))
|
||||||
|
(defn mix [secret v] (bit-xor secret v))
|
||||||
|
|
||||||
|
(defn next-step [secret]
|
||||||
|
(let [a (prune (mix secret (* secret 64)))
|
||||||
|
b (prune (mix a (int (/ a 32))))
|
||||||
|
c (prune (mix b (* b 2048)))]
|
||||||
|
c))
|
||||||
|
|
||||||
|
(defn get-nums
|
||||||
|
([n] (get-nums n 0))
|
||||||
|
([n i] (lazy-seq (cons n (get-nums (next-step n) (inc i))))))
|
||||||
|
|
||||||
|
(def solutions (->> input
|
||||||
|
(map get-nums)
|
||||||
|
(mapv (comp (partial into [])
|
||||||
|
(partial take 2001)))))
|
||||||
|
|
||||||
|
;; part 1 sol
|
||||||
|
(->> solutions
|
||||||
|
(map last)
|
||||||
|
(apply +))
|
||||||
|
|
||||||
|
;; part 2 sol
|
||||||
|
(->> (map (partial map #(mod % 10)) solutions)
|
||||||
|
(map #(map (fn [& prices]
|
||||||
|
(let [price-diff-list (map - (rest prices) prices)
|
||||||
|
sell-price (last prices)]
|
||||||
|
[price-diff-list sell-price]))
|
||||||
|
% (rest %) (drop 2 %) (drop 3 %) (drop 4 %)))
|
||||||
|
(reduce (fn [acc buyer]
|
||||||
|
(->> (reduce (fn [[visited acc2] [price-diff-list price]]
|
||||||
|
(if (visited price-diff-list)
|
||||||
|
[visited acc2]
|
||||||
|
[(conj visited
|
||||||
|
price-diff-list)
|
||||||
|
(update acc2
|
||||||
|
price-diff-list
|
||||||
|
#(+ (or % 0) price))]))
|
||||||
|
[#{} acc]
|
||||||
|
buyer)
|
||||||
|
second))
|
||||||
|
{})
|
||||||
|
vals
|
||||||
|
(apply max))
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
input/
|
||||||
|
.lein-repl-history
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
|||||||
|
(defproject org.ajet/advent-of-code "0.0.0-SNAPSHOT"
|
||||||
|
:description "my 2024 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"])
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
(ns day01
|
||||||
|
(:require input-manager))
|
||||||
|
|
||||||
|
(defn parse-line [line]
|
||||||
|
[(.charAt line 0)
|
||||||
|
(parse-long (.substring line 1))])
|
||||||
|
|
||||||
|
(def input (->> (input-manager/get-input 2025 01)
|
||||||
|
(map parse-line)))
|
||||||
|
|
||||||
|
(def op {\R +, \L -})
|
||||||
|
|
||||||
|
(defn normalize [n]
|
||||||
|
(mod n 100))
|
||||||
|
|
||||||
|
;; part 1
|
||||||
|
(->> input
|
||||||
|
(reductions (fn [acc [dir turn-cnt]]
|
||||||
|
(normalize ((op dir) acc turn-cnt)))
|
||||||
|
50)
|
||||||
|
(filter (partial = 0))
|
||||||
|
count)
|
||||||
|
|
||||||
|
;; part 2
|
||||||
|
(->> input
|
||||||
|
(reduce (fn [[acc dial] [dir turn-cnt]]
|
||||||
|
(let [next-dial ((op dir) dial turn-cnt)]
|
||||||
|
[(+ acc (cond (> next-dial 99) (int (/ next-dial 100))
|
||||||
|
(< next-dial 0) (+ (abs (int (/ next-dial 100)))
|
||||||
|
(if (= dial 0)
|
||||||
|
0
|
||||||
|
1))
|
||||||
|
(= next-dial 0) 1
|
||||||
|
:else 0))
|
||||||
|
(normalize next-dial)]))
|
||||||
|
[0 50])
|
||||||
|
first)
|
||||||
@@ -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 +))
|
||||||
|
|
||||||
@@ -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 +))
|
||||||
@@ -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))))))
|
||||||
@@ -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)
|
||||||
|
|
||||||
@@ -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 +))
|
||||||
|
|
||||||
@@ -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)
|
||||||
@@ -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 *))
|
||||||
|
|
||||||
@@ -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)
|
||||||
@@ -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 +))
|
||||||
@@ -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")))
|
||||||
@@ -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)))))
|
||||||
@@ -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))
|
||||||
|
|
||||||
Reference in New Issue
Block a user