advent of code 2025 in ts and nix
1let 2 input = builtins.readFile ../../shared/04/input.txt; 3 lines = builtins.filter (s: builtins.isString s && s != "") (builtins.split "\n" input); 4 5 # Parse input into grid of booleans (true = @, false = .) 6 paperMap = builtins.map (line: 7 let 8 len = builtins.stringLength line; 9 indices = builtins.genList (i: i) len; 10 in builtins.map (i: 11 let ch = builtins.substring i 1 line; 12 in if ch == "@" then true else false 13 ) indices 14 ) lines; 15 16 # Count accessible papers and return new map 17 accessiblePapers = map: 18 let 19 numRows = builtins.length map; 20 21 # Process all cells in one pass using foldl' 22 result = builtins.foldl' (state: rowIdx: 23 let 24 rowData = builtins.elemAt map rowIdx; 25 numCols = builtins.length rowData; 26 27 rowResult = builtins.foldl' (rowState: colIdx: 28 let 29 cell = builtins.elemAt rowData colIdx; 30 in 31 if !cell then { 32 accessible = rowState.accessible; 33 newRow = rowState.newRow ++ [false]; 34 } 35 else 36 let 37 # Check all 8 neighbors inline 38 check = r: c: 39 if r < 0 || c < 0 || r >= numRows then false 40 else 41 let rd = builtins.elemAt map r; 42 in if c >= builtins.length rd then false 43 else builtins.elemAt rd c; 44 45 fullAdj = 46 (if check (rowIdx - 1) colIdx then 1 else 0) + 47 (if check (rowIdx + 1) colIdx then 1 else 0) + 48 (if check rowIdx (colIdx + 1) then 1 else 0) + 49 (if check rowIdx (colIdx - 1) then 1 else 0) + 50 (if check (rowIdx - 1) (colIdx + 1) then 1 else 0) + 51 (if check (rowIdx + 1) (colIdx + 1) then 1 else 0) + 52 (if check (rowIdx - 1) (colIdx - 1) then 1 else 0) + 53 (if check (rowIdx + 1) (colIdx - 1) then 1 else 0); 54 55 isAccessible = fullAdj < 4; 56 in { 57 accessible = rowState.accessible + (if isAccessible then 1 else 0); 58 newRow = rowState.newRow ++ [(if isAccessible then false else true)]; 59 } 60 ) { accessible = 0; newRow = []; } (builtins.genList (i: i) numCols); 61 in { 62 accessible = state.accessible + rowResult.accessible; 63 newMap = state.newMap ++ [rowResult.newRow]; 64 } 65 ) { accessible = 0; newMap = []; } (builtins.genList (i: i) numRows); 66 in result; 67 68 # Part 1: Single iteration 69 part1 = (accessiblePapers paperMap).accessible; 70 71 # Part 2: Iterate until no more accessible papers 72 part2 = 73 let 74 iterate = state: 75 let 76 result = accessiblePapers state.map; 77 in 78 if result.accessible == 0 then state.total 79 else iterate { 80 map = result.newMap; 81 total = state.total + result.accessible; 82 }; 83 in iterate { map = paperMap; total = 0; }; 84 85in { 86 inherit part1 part2; 87}