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}