(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 :-)