···
2
+
input = builtins.readFile ../../shared/06/input.txt;
3
+
lines = builtins.filter (s: builtins.isString s && s != "") (builtins.split "\n" input);
5
+
# Helper to get character at position or space if out of bounds
7
+
if idx < 0 || idx >= builtins.stringLength str
9
+
else builtins.substring idx 1 str;
11
+
# Find whitespace columns (columns that are all spaces/tabs in data rows)
12
+
dataRows = builtins.genList (i: builtins.elemAt lines i) (builtins.length lines - 1);
13
+
maxLen = builtins.foldl' (max: row:
14
+
let len = builtins.stringLength row;
15
+
in if len > max then len else max
18
+
# Find columns that are all whitespace
19
+
splitCols = builtins.filter (col: col != null) (builtins.genList (i:
21
+
allWS = builtins.foldl' (acc: row:
22
+
acc && (let ch = charAt row i; in ch == " " || ch == " ")
24
+
in if allWS then i else null
27
+
# Split each row at whitespace columns
30
+
rowLen = builtins.stringLength row;
31
+
splitImpl = cuts: startPos: acc:
32
+
if builtins.length cuts == 0
33
+
then acc ++ [(builtins.substring startPos (rowLen - startPos) row)]
36
+
cut = builtins.head cuts;
37
+
restCuts = builtins.tail cuts;
38
+
end = if cut + 1 > rowLen then rowLen else cut + 1;
39
+
segment = builtins.substring startPos (end - startPos) row;
40
+
in splitImpl restCuts end (acc ++ [segment]);
41
+
in splitImpl splitCols 0 [];
43
+
# Split all lines (including operator row)
44
+
segmentedRows = builtins.map splitRow lines;
46
+
# Transpose to get columns (problems)
47
+
numProblems = builtins.length (builtins.head segmentedRows);
48
+
problems = builtins.genList (colIdx:
49
+
builtins.map (row: builtins.elemAt row colIdx) segmentedRows
52
+
# Fast trim - just remove spaces and tabs
53
+
# Extract just digits from a string for numbers
56
+
cleaned = builtins.replaceStrings [" " " "] ["" ""] str;
57
+
in if builtins.stringLength cleaned == 0 then 0 else builtins.fromJSON cleaned;
62
+
cleaned = builtins.replaceStrings [" " " "] ["" ""] str;
65
+
# Part 1: Normal left-to-right evaluation
66
+
part1 = builtins.foldl' (total: problem:
68
+
lastIdx = builtins.length problem - 1;
69
+
operator = extractOp (builtins.elemAt problem lastIdx);
70
+
nums = builtins.map (s: extractNum s) (builtins.genList (i: builtins.elemAt problem i) lastIdx);
73
+
then builtins.foldl' (acc: n: acc * n) 1 nums
74
+
else builtins.foldl' (acc: n: acc + n) 0 nums;
78
+
# Part 2: Cepheid (vertical) reading
79
+
part2 = builtins.foldl' (total: problem:
81
+
lastIdx = builtins.length problem - 1;
82
+
operator = extractOp (builtins.elemAt problem lastIdx);
83
+
numStrs = builtins.genList (i: builtins.elemAt problem i) lastIdx;
86
+
maxWidth = builtins.foldl' (max: s:
87
+
let len = builtins.stringLength s;
88
+
in if len > max then len else max
91
+
# Read vertically from right to left
92
+
cephNums = builtins.filter (n: n != null) (builtins.genList (colR:
94
+
# Build digits string from this column (right to left)
95
+
idx = maxWidth - colR;
96
+
digitsStr = builtins.concatStringsSep "" (builtins.filter (ch: ch != " " && ch != " ") (builtins.map (s:
97
+
if idx >= 0 && idx < builtins.stringLength s
98
+
then builtins.substring idx 1 s
101
+
in if builtins.stringLength digitsStr > 0
102
+
then builtins.fromJSON digitsStr
108
+
then builtins.foldl' (acc: n: acc * n) 1 cephNums
109
+
else builtins.foldl' (acc: n: acc + n) 0 cephNums;
114
+
inherit part1 part2;