advent of code 2025 in ts and nix

feat: add day 3 nix

dunkirk.sh 17f2fd0f 02e86d9e

verified
Changed files
+94
nix
+94
nix/03/solution.nix
···
+
let
+
input = builtins.readFile ../../shared/03/input.txt;
+
banks = builtins.filter (s: builtins.isString s && s != "") (builtins.split "\n" input);
+
+
# Helper to convert string to list of digit ints
+
stringToDigits = str:
+
let
+
len = builtins.stringLength str;
+
indices = builtins.genList (i: i) len;
+
in map (i: builtins.fromJSON (builtins.substring i 1 str)) indices;
+
+
# Part 1: Find highest pair (largestI * 10 + jVal) for each bank
+
part1 =
+
let
+
processBank = bank:
+
let
+
digits = stringToDigits bank;
+
L = builtins.length digits;
+
+
# For each position j, find the largest digit before it and form pair
+
processPair = state: j:
+
let
+
jVal = builtins.elemAt digits j;
+
# Find largest digit in digits[0..j-1]
+
largestI = builtins.foldl'
+
(max: i: let iVal = builtins.elemAt digits i; in if iVal > max then iVal else max)
+
(-1)
+
(builtins.genList (i: i) j);
+
pair = largestI * 10 + jVal;
+
newHighest = if pair > state.highest then pair else state.highest;
+
in { highest = newHighest; };
+
+
# Process j from 1 to L-1
+
result = builtins.foldl'
+
processPair
+
{ highest = -1; }
+
(builtins.genList (i: i + 1) (L - 1));
+
in result.highest;
+
+
jolts = map processBank banks;
+
in builtins.foldl' builtins.add 0 jolts;
+
+
# Part 2: Monotonic stack to find best K-digit number
+
part2 =
+
let
+
K = 12;
+
+
processBank = bank:
+
let
+
digits = stringToDigits bank;
+
L = builtins.length digits;
+
+
# Process each digit with monotonic stack approach
+
processDigit = state: j:
+
let
+
jVal = builtins.elemAt digits j;
+
remaining = L - j;
+
+
# Pop smaller tail digits if we can still reach K
+
popSmaller = stack:
+
let
+
stackLen = builtins.length stack;
+
canPop = stackLen > 0 &&
+
(builtins.elemAt stack (stackLen - 1)) < jVal &&
+
stackLen - 1 + remaining >= K;
+
in
+
if canPop then
+
popSmaller (builtins.genList (i: builtins.elemAt stack i) (stackLen - 1))
+
else
+
stack;
+
+
newStack = popSmaller state.stack;
+
stackLen = builtins.length newStack;
+
+
# Add current digit if we still need more
+
finalStack = if stackLen < K then newStack ++ [jVal] else newStack;
+
in { stack = finalStack; };
+
+
# Process all digits
+
result = builtins.foldl'
+
processDigit
+
{ stack = []; }
+
(builtins.genList (i: i) L);
+
+
# Convert stack to number
+
stackToNum = builtins.foldl' (acc: d: acc * 10 + d) 0 result.stack;
+
in stackToNum;
+
+
jolts = map processBank banks;
+
in builtins.foldl' builtins.add 0 jolts;
+
+
in {
+
inherit part1 part2;
+
}