Advent of Code 2025 Day 3
Day 3 of solving The Advent of Code in Clojure .
The puzzle today has us figuring out the joltage of a bank of batteries. This is a puzzle of the type “largest sequence in a list”. When you start you already know that part 2 will be something that a naive approach will not be able to handle, but I still did part 1 with a naive combination function.
The Clojure
combinatorics library will not work here, as it will take a look at the distinct pairs that will be in the list. So in a list of (2 8 2) it will find the unique pair of (2 8), resulting in the integer 28 for the puzzle, but it will fail to see that 82 was also an option.
I wrote a simple combinations function to start with, and then puzzle 2 hit me with a combination of 12 digits. The algorithm did not work for that amount. I changed it to search for the largest number n positions from the end. So, first search the highest number at least 12 positions away from the end, from then search for the highest number at least 11 positions from the end, etc. The algorithm works beautifully well.
code snippet start
Original: 12397658
First pass (2 positions remaining): ___97658
First pass (1 positions remaining): ___9___8
Result: 98code snippet end
While writing this I am wondering if it would be even better to convert the string to numbers before finding the digits, but I will leave that as an exercise to you, dear reader.
clojure code snippet start
(ns day3
(:require
[clojure.string :as str]))
(defn find-highest-digit
"Find the highest digit on to the end of the string.
This is an optimization to not interpolate the entire string."
[s start end]
(loop [max-digit nil
max-pos nil
pos start]
(cond
(> pos end) ;; break out the loop with the current highest number
{:digit max-digit :pos max-pos}
(or (nil? max-digit) (> (Character/digit (nth s pos) 10) max-digit))
(recur (Character/digit (nth s pos) 10) pos (inc pos))
:else
(recur max-digit max-pos (inc pos)))))
(defn find-max-number
"Find the max number of `remaining-length` size. Keep finding
the max number at least `remaining-length` from the end."
[s remaining-length]
(let [n (count s)]
(when (and (>= n 1) (>= remaining-length 1))
(let [end-pos (- n remaining-length)
{:keys [digit pos]} (find-highest-digit s 0 end-pos)]
(if (nil? digit)
nil
(let [remaining-s (if (< (inc pos) n) (subs s (inc pos)) "")]
(cons digit (find-max-number remaining-s (dec remaining-length)))))))))
(defn max-n-digit-number
"Find the maximum number in a sequence of number, allowing for
dropping intermediate numbers"
[n s]
(let [result (find-max-number s n)]
(Long/parseLong (apply str result))))
(->> "resources/3.in"
slurp
(str/split-lines)
(map #(max-n-digit-number 2 %))
(reduce +))
(->> "resources/3.in"
slurp
(str/split-lines)
(map #(max-n-digit-number 12 %))
(reduce +))clojure code snippet end