AdventOfCode/2025.clj
2025-12-27 20:52:59 +07:00

409 lines
12 KiB
Clojure

(ns aoc2025
(:require [clojure.string :as str]))
(defn get-input [day] (slurp (str "2025/day" day "-input.txt")))
(defn remove-index
"Removes an item at the specified position in a vector"
[coll ^long index]
(-> (into (subvec coll 0 index)
(subvec coll (inc index)))
(with-meta (meta coll))))
(def directions {:N [-1 0] :S [1 0] :W [0 -1] :E [0 1]
:NW [-1 -1] :NE [-1 1] :SW [1 -1] :SE [1 1]})
;; _____ __
;; | __ \ /_ |
;; | | | | __ _ _ _ | |
;; | | | |/ _` | | | | | |
;; | |__| | (_| | |_| | | |
;; |_____/ \__,_|\__, | |_|
;; __/ |
;; |___/
(def day1-input-test
"L68
L30
R48
L5
R60
L55
L1
L99
R14
L82")
(defn day1 [input zero-count-fn]
(let [sequence (map (fn [line]
[(if (= "R" (str (first line)))
#'+
#'-)
(parse-long (str/join (rest line)))])
(str/split-lines input))]
(loop [s sequence
curr 50
zero-count 0]
(if (not (seq s))
zero-count
(let [[f amount] (first s)
new-dial-pos (mod (f curr amount) 100)
spins (zero-count-fn curr (f amount) new-dial-pos)]
(println curr new-dial-pos amount spins)
(recur (rest s) new-dial-pos (+ zero-count spins)))))))
(defn day1-p1 [input]
(day1 input (fn [_ _ new-dial-pos] (if (zero? new-dial-pos) 1 0))))
(defn day1-p2 [input]
(day1 input (fn [curr rotation _]
(let [amount (abs rotation)]
(if (and (neg? rotation)
(not (zero? curr)))
(quot (+ (- 100 curr) (abs amount)) 100)
(quot (+ curr amount) 100))))))
(comment
(day1-p1 day1-input-test)
(day1-p1 (get-input 1))
(day1-p2 day1-input-test)
(day1-p2 (get-input 1))
:-)
;; _____ ___
;; | __ \ |__ \
;; | | | | __ _ _ _ ) |
;; | | | |/ _` | | | | / /
;; | |__| | (_| | |_| | / /_
;; |_____/ \__,_|\__, | |____|
;; __/ |
;; |___/
(def day2-input-test
"11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124")
(defn day2-parse-input [input]
(->> (str/split (str/trim input) #",")
(map #(str/split % #"-"))
(map #(mapv parse-long %))
(map (fn [[lo hi]] (range lo (inc hi))))
flatten))
(defn day2-p1 [input]
(->> input
(keep #(let [num-str (str %)
length (count num-str)
half (/ length 2)]
(when (and (even? length)
(= (subs num-str 0 half)
(subs num-str half length)))
%)))
(reduce +)))
(defn day2-p2 [input]
(->> input
(keep #(let [num-str (str %)
length (count num-str)]
(loop [p-size (quot length 2)]
(cond
(zero? p-size)
nil
(apply = (partition-all p-size num-str))
%
:else
(recur (dec p-size))))))
(reduce +)))
(comment
(day2-p1 (day2-parse-input day2-input-test))
(day2-p1 (day2-parse-input (get-input 2)))
(day2-p2 (day2-parse-input day2-input-test))
(day2-p2 (day2-parse-input (get-input 2)))
:-)
;; _____ ____
;; | __ \ |___ \
;; | | | | __ _ _ _ __) |
;; | | | |/ _` | | | | |__ <
;; | |__| | (_| | |_| | ___) |
;; |_____/ \__,_|\__, | |____/
;; __/ |
;; |___/
(def day3-input-test
"987654321111111
811111111111119
234234234234278
818181911112111")
(defn day3-get-max-battery [total-digits bank]
(loop [remaining (dec total-digits)
curr-idx 0
nums []]
(if (= (count nums) total-digits)
(reduce (fn [acc digit] (+ (* acc 10) digit)) 0 nums)
(let [subbank (subvec bank curr-idx (- (count bank) remaining))
[idx max-num] (->> (map-indexed vector subbank)
(reduce (fn [[idx max] [i n]]
(if (> n max)
[i n]
[idx max]))
[-1 -1]))]
(recur (dec remaining) (+ curr-idx idx 1) (conj nums max-num))))))
(defn day3 [total-digits input]
(->> (str/split-lines input)
(mapv #(mapv (fn [c] (Character/digit c 10)) (vec %)))
(map (partial day3-get-max-battery total-digits))
(reduce +)))
(comment
(day3 2 day3-input-test)
(day3 2 (get-input 3))
(day3 12 day3-input-test)
(day3 12 (get-input 3))
:-)
;; _____ _ _
;; | __ \ | || |
;; | | | | __ _ _ _ | || |_
;; | | | |/ _` | | | | |__ _|
;; | |__| | (_| | |_| | | |
;; |_____/ \__,_|\__, | |_|
;; __/ |
;; |___/
(def day4-input-test
"..@@.@@@@.
@@@.@.@.@@
@@@@@.@.@@
@.@@@@..@.
@@.@@@@.@@
.@@@@@@@.@
.@.@.@.@@@
@.@@@.@@@@
.@@@@@@@@.
@.@.@@@.@.")
(defn day4-adjacent-count [grid [row col]]
(when (= \@ (get-in grid [row col]))
(->> (for [[dir [dy dx]] directions]
(get-in grid [(+ row dy) (+ col dx)]))
concat
(filter #(= % \@))
count)))
(defn day4-p1 [input]
(let [grid (str/split-lines input)]
(->> (for [row (range (count grid))
col (range (count (first grid)))]
(day4-adjacent-count grid [row col]))
(remove nil?)
(filter #(< % 4))
count)))
(defn day4-p2 [input]
(let [grid (str/split-lines input)
ROWS (count grid)
COLS (count (first grid))]
(loop [grid grid
removed-count 0]
(let [marked-cells (->> (for [row (range ROWS)
col (range COLS)]
(when-let [adj-count (day4-adjacent-count grid [row col])]
(when (< adj-count 4)
[row col])))
(remove nil?)
set)]
(if (empty? marked-cells)
removed-count
(recur (->> (for [row (range ROWS)
col (range COLS)]
(if (contains? marked-cells [row col])
\x
(get-in grid [row col])))
(partition COLS)
(mapv #(reduce str %)))
(+ removed-count (count marked-cells))))))))
(comment
(day4-p1 day4-input-test)
(day4-p1 (get-input 4))
(day4-p2 day4-input-test)
(day4-p2 (get-input 4))
:-)
;; _____ _____
;; | __ \ | ____|
;; | | | | __ _ _ _ | |__
;; | | | |/ _` | | | | |___ \
;; | |__| | (_| | |_| | ___) |
;; |_____/ \__,_|\__, | |____/
;; __/ |
;; |___/
(def day5-input-test
"3-5
10-14
16-20
12-18
1
5
8
11
17
32")
(defn day5-parse-input [input]
(let [[ranges ids] (->> (str/split input #"\n\n")
(map #(str/split-lines %)))]
[(map #(mapv parse-long (str/split % #"-")) ranges)
(map parse-long ids)]))
(defn day5-p1 [input]
(let [[ranges ids] (day5-parse-input input)]
(->> (map #(some (fn [[min max]] (<= min % max)) ranges) ids)
(remove nil?)
count)))
(defn day5-p2 [input]
(let [[ranges _] (day5-parse-input input)]
(->> (reduce (fn [acc elem]
(if (empty? acc)
(list elem)
(let [next-min (first elem)
[curr-min curr-max] (first acc)]
(if (<= curr-min next-min curr-max)
(cons [curr-min (max (second elem) curr-max)] (rest acc))
(cons elem acc)))))
'()
(sort ranges))
(map #(inc (- (second %) (first %))))
(reduce +))))
(comment
(day5-p1 day5-input-test)
(day5-p1 (get-input 5))
(day5-p2 day5-input-test)
(day5-p2 (get-input 5))
:-)
;; _____ __
;; | __ \ / /
;; | | | | __ _ _ _ / /_
;; | | | |/ _` | | | | | '_ \
;; | |__| | (_| | |_| | | (_) |
;; |_____/ \__,_|\__, | \___/
;; __/ |
;; |___/
(def day6-input-test
"123 328 51 64
45 64 387 23
6 98 215 314
* + * + ")
(defn day6-p1 [input]
(let [parsed (->> (str/split-lines input)
(mapv #(->> (str/split % #"\s+")
(remove empty?))))]
(->> (butlast parsed)
(mapv #(mapv parse-long %))
(into [(mapv #(resolve (symbol %)) (last parsed))])
(apply mapv vector)
(map #(apply (first %) (rest %)))
(reduce +))))
(defn day6-p2 [input]
(let [grid (->> (str/split-lines input)
(mapv vec))
row-count (count grid)]
(loop [curr-col (dec (count (first grid)))
curr-row 0
curr-num-str ""
nums []
total 0]
(if (= curr-col -1)
total
(let [curr (get-in grid [curr-row curr-col])
last-row (= curr-row (dec row-count))]
(cond
(Character/isDigit curr)
(recur curr-col (mod (inc curr-row) row-count) (str curr-num-str curr) nums total)
last-row
(let [sum (parse-long curr-num-str)]
(if (#{\+ \*} curr)
(recur (dec curr-col) 0 "" [] (+ total (reduce (resolve (symbol (str curr))) (conj nums sum))))
(recur (dec curr-col) 0 "" (if sum (conj nums sum) []) total)))
:else
(recur curr-col (mod (inc curr-row) row-count) curr-num-str nums total)))))))
(comment
(day6-p1 day6-input-test) ;; => 4277556
(day6-p1 (get-input 6)) ;; => 6343365546996
(day6-p2 day6-input-test) ;; => 3263827
(day6-p2 (get-input 6)) ;; => 11136895955912
:-)
;; _____ ______
;; | __ \ |____ |
;; | | | | __ _ _ _ / /
;; | | | |/ _` | | | | / /
;; | |__| | (_| | |_| | / /
;; |_____/ \__,_|\__, | /_/
;; __/ |
;; |___/
(def day7-input-test
".......S.......
...............
.......^.......
...............
......^.^......
...............
.....^.^.^.....
...............
....^.^...^....
...............
...^.^...^.^...
...............
..^...^.....^..
...............
.^.^.^.^.^...^.
...............")
(defn day7-p1 [input]
(let [lanes (->> (str/split-lines input)
(mapv vec)
(apply mapv vector))
length (count (first lanes))]
(loop [active-lanes (set (keep-indexed #(when (= (first %2) \S) %1) lanes))
idx 2 ;; The splitters start on row 3
count 0]
(if (= idx length)
count
(let [[new-lanes added-count]
(reduce (fn [[ls c] lane]
(if (not= \^ (get-in lanes [lane idx]))
[ls c]
[(conj (disj ls lane) (dec lane) (inc lane)) (inc c)]))
[active-lanes 0]
active-lanes)]
(recur new-lanes (inc idx) (+ count added-count)))))))
(defn day7-p2 [input]
())
(comment
(day7-p1 day7-input-test)
(day7-p1 (get-input 7))
(day7-p2 day7-input-test)
(day7-p2 (get-input 7))
:-)