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
|
||||
.calva
|
||||
.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/
|
||||
.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"]
|
||||
: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.babashka/http-client "0.4.22"]
|
||||
[org.clojure/core.match "1.1.0"]]
|
||||
:source-paths ["src" "../shared/clj/src"])
|
||||
|
||||
+14
-16
@@ -1,26 +1,24 @@
|
||||
(ns day01
|
||||
(:require
|
||||
[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))))
|
||||
(:require input-manager))
|
||||
|
||||
;; 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
|
||||
(map sort)
|
||||
(apply zipmap)
|
||||
(map #(abs (apply - %)))
|
||||
(reduce +))
|
||||
(apply map (comp abs -))
|
||||
(apply +))
|
||||
|
||||
;; part 2
|
||||
(let [[a b] input
|
||||
freqs (frequencies b)]
|
||||
(->> a
|
||||
(let [[left-col right-col] input
|
||||
freqs (frequencies right-col)]
|
||||
(->> left-col
|
||||
(map #(* (or (freqs %) 0) %))
|
||||
(reduce +)))
|
||||
|
||||
|
||||
|
||||
+19
-25
@@ -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 +))
|
||||
|
||||
|
||||
@@ -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])
|
||||
)
|
||||
+4
-5
@@ -22,8 +22,7 @@
|
||||
(mapv (constantly 0) puzzle))
|
||||
last))
|
||||
|
||||
(let [[w _ & p]
|
||||
(input-manager/get-input 2024 19)]
|
||||
(let [[w _ & p] (input-manager/get-input 2024 19)]
|
||||
(def words (into #{} (str/split w #", ")))
|
||||
(def puzzles p))
|
||||
|
||||
@@ -36,8 +35,8 @@
|
||||
(apply + (map (partial valid-combination-count words) puzzles))
|
||||
|
||||
(comment
|
||||
(increment-counts-for-matching-words #{"a"} "atest" [0 0 0 0 0 0] 0) ; [1 0 0 0 0 0]
|
||||
(increment-counts-for-matching-words #{"a"} "btest" [0 0 0 0 0 0] 0) ; [0 0 0 0 0 0]
|
||||
(increment-counts-for-matching-words #{"a"} "atest" [0 0 0 0 0 0] 0) ; [1 0 0 0 0 0]
|
||||
(increment-counts-for-matching-words #{"a"} "btest" [0 0 0 0 0 0] 0) ; [0 0 0 0 0 0]
|
||||
(increment-counts-for-matching-words #{"te"} "atest" [1 0 0 0 0 0] 1) ; [1 0 1 0 0 0]
|
||||
|
||||
(increment-counts-for-matching-words #{"wo" "rd"} "word" [0 1 0 0] 2) ; [0 1 0 1]
|
||||
@@ -45,5 +44,5 @@
|
||||
(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]
|
||||
(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