advent of code 2025 in ts and nix
at main 2.9 kB view raw
1const file = await Bun.file("../../shared/07/input.txt").text(); 2const board: string[][] = file 3 .trimEnd() 4 .split("\n") 5 .map((line) => line.split("")); 6 7type Coord = { r: number; c: number }; 8 9// Find S 10const S: Coord | null = (() => { 11 for (let r = 0; r < board.length; r++) { 12 const c = board[r]?.indexOf("S") as number; 13 if (c !== -1) return { r, c }; 14 } 15 return null; 16})(); 17 18if (!S) throw "No start position found"; 19 20const inBounds = (r: number, c: number) => 21 r >= 0 && r < board.length && c >= 0 && c < board[0].length; 22 23// Part 1: Count unique beam positions and splits 24(() => { 25 type BeamPosition = [number, number]; 26 let activeBeams: BeamPosition[] = [[S.r, S.c]]; 27 let totalSplits = 0; 28 29 while (activeBeams.length > 0) { 30 const nextActive: BeamPosition[] = []; 31 32 for (const [r, c] of activeBeams) { 33 const nr = r + 1; 34 const nc = c; 35 36 if (!inBounds(nr, nc)) continue; 37 38 const cell = board[nr][nc]; 39 40 if (cell === ".") { 41 nextActive.push([nr, nc]); 42 } else if (cell === "^") { 43 totalSplits++; 44 // Split into left and right beams 45 const leftC = nc - 1; 46 const rightC = nc + 1; 47 if (inBounds(nr, leftC)) nextActive.push([nr, leftC]); 48 if (inBounds(nr, rightC)) nextActive.push([nr, rightC]); 49 } else { 50 // 'S' or other chars - continue straight 51 nextActive.push([nr, nc]); 52 } 53 } 54 55 // Remove duplicates 56 const uniqueBeams = [ 57 ...new Set(nextActive.map(([r, c]) => `${r},${c}`)), 58 ].map((s) => s.split(",").map(Number) as BeamPosition); 59 60 activeBeams = uniqueBeams; 61 } 62 63 console.log("part 1:", totalSplits); 64})(); 65 66// Part 2: Count total timelines (beams multiply through splitters) 67(() => { 68 let currentStates: Record<string, number> = { [`${S.r},${S.c}`]: 1 }; 69 70 for (let step = 0; step < board.length; step++) { 71 const nextStates: Record<string, number> = {}; 72 73 for (const [key, count] of Object.entries(currentStates)) { 74 const [r, c] = key.split(",").map(Number); 75 const nr = r + 1; 76 77 if (nr >= board.length) continue; 78 if (!inBounds(nr, c)) continue; 79 80 const cell = board[nr][c]; 81 82 if (cell === ".") { 83 const nkey = `${nr},${c}`; 84 nextStates[nkey] = (nextStates[nkey] || 0) + count; 85 } else if (cell === "^") { 86 // Each timeline splits into two 87 const lc = c - 1; 88 const rc = c + 1; 89 if (inBounds(nr, lc)) { 90 const lkey = `${nr},${lc}`; 91 nextStates[lkey] = (nextStates[lkey] || 0) + count; 92 } 93 if (inBounds(nr, rc)) { 94 const rkey = `${nr},${rc}`; 95 nextStates[rkey] = (nextStates[rkey] || 0) + count; 96 } 97 } else { 98 // 'S' or other chars - continue straight 99 const nkey = `${nr},${c}`; 100 nextStates[nkey] = (nextStates[nkey] || 0) + count; 101 } 102 } 103 104 if (Object.keys(nextStates).length === 0) break; 105 currentStates = nextStates; 106 } 107 108 const totalTimelines = Object.values(currentStates).reduce( 109 (a, b) => a + b, 110 0, 111 ); 112 console.log("part 2:", totalTimelines); 113})();