advent of code 2025 in ts and nix
1const file = await Bun.file("../../shared/06/input.txt").text();
2const problemsArray: (string | ("*" | "+"))[][] = (() => {
3 const rows = file.trimEnd().split("\n");
4 const dataRows = rows.slice(0, rows.length - 1); // exclude operator row when detecting split columns
5
6 // 1) Find whitespace columns across all data rows
7 const maxLen = Math.max(...dataRows.map((r) => r.length));
8 const splitCols: number[] = [];
9 for (let i = 0; i < maxLen; i++) {
10 let allWS = true;
11 for (const row of dataRows) {
12 const ch = i < row.length ? row[i] : " "; // virtual pad short rows
13 if (ch !== " " && ch !== "\t") {
14 allWS = false;
15 break;
16 }
17 }
18 if (allWS) splitCols.push(i);
19 }
20
21 // 2) Split each row at those columns, including the split whitespace in the left segment
22 const cuts = Array.from(new Set(splitCols)).sort((a, b) => a - b);
23 const segmentedRows: string[][] = rows.map((row) => {
24 const segs: string[] = [];
25 let start = 0;
26 for (const cut of cuts) {
27 const end = Math.min(cut + 1, row.length); // keep the whitespace column with the left segment
28 segs.push(row.slice(start, end));
29 start = end;
30 }
31 segs.push(row.slice(start)); // remainder
32 return segs;
33 });
34
35 // 3) Transpose rows -> columns
36 return segmentedRows.reduce<(string | ("*" | "+"))[][]>((cols, row) => {
37 row.forEach((cell, i) => {
38 (cols[i] ??= []).push(cell as string | ("*" | "+"));
39 });
40 return cols;
41 }, []);
42})();
43
44(() => {
45 let total = 0;
46 problemsArray.forEach((problem) => {
47 const localProblem = [...problem];
48 const operator = localProblem.pop()?.trim() as "*" | "+";
49
50 const nums = localProblem.map((val) =>
51 Number.parseInt(val.trim() as string, 10),
52 );
53
54 const value = nums.reduce((acc, curr) =>
55 operator === "*" ? acc * curr : acc + curr,
56 );
57
58 total += value;
59 });
60
61 // Part 1
62 console.log("part 1:", total);
63})();
64
65(() => {
66 let total = 0;
67 problemsArray.forEach((problem) => {
68 const localProblem = [...problem];
69 const operator = localProblem.pop()?.trim() as "*" | "+";
70
71 const maxWidth = localProblem.reduce((m, s) => Math.max(m, s.length), 0);
72
73 const cephNums: number[] = [];
74 for (let colR = 0; colR <= maxWidth; colR++) {
75 let digits = "";
76
77 for (let r = 0; r < localProblem.length; r++) {
78 const s = localProblem[r] as string;
79 const idx = maxWidth - colR;
80
81 if (idx <= s.length - 1) {
82 const ch = s[idx];
83 if (ch !== " ") digits += ch;
84 }
85 }
86
87 if (digits.length > 0) {
88 cephNums.push(Number.parseInt(digits, 10));
89 }
90 }
91
92 const value =
93 operator === "*"
94 ? cephNums.reduce((p, n) => p * n, 1)
95 : cephNums.reduce((p, n) => p + n, 0);
96
97 total += value;
98 });
99
100 // Part 2
101 console.log("part 2:", total);
102})();