commit 3eefdb2273f806d24906a42adde838478009e9ac
parent 247b36212dd6ce2855956d336deedbf0dbd53917
Author: finwo <finwo@pm.me>
Date: Wed, 24 Dec 2025 17:42:11 +0100
Completed 2025/04
Diffstat:
2 files changed, 121 insertions(+), 0 deletions(-)
diff --git a/2025/04/example.txt b/2025/04/example.txt
@@ -0,0 +1,10 @@
+..@@.@@@@.
+@@@.@.@.@@
+@@@@@.@.@@
+@.@@@@..@.
+@@.@@@@.@@
+.@@@@@@@.@
+.@.@.@.@@@
+@.@@@.@@@@
+.@@@@@@@@.
+@.@.@@@.@.
diff --git a/2025/04/index.js b/2025/04/index.js
@@ -0,0 +1,111 @@
+#!/usr/bin/env node
+
+const fs = require('node:fs');
+
+const grid = fs
+ .readFileSync('input', 'utf-8')
+ .split('\r\n').join('\n')
+ .split('\r').join('\n')
+ .split('\n')
+ .map(str => str.trim())
+ .filter(str => str)
+ .map(str => str.split(''))
+ .map(row => row.map(c => c === '@'))
+ ;
+
+const buildNeighbours = (grid) => {
+ const neighbours = grid
+ .map(row => row.map(() => 0));
+
+ // Mark adjacent locations as having 'current' as neighbour
+ for(let y = 0; y < grid.length; y++) {
+ const row = grid[y];
+ for(let x = 0; x < row.length ; x++) {
+ // Skip if we're empty
+ if (!grid[y][x]) continue;
+ for(let ny = -1; ny <= 1; ny++) {
+ if ((y+ny) < 0) continue;
+ if ((y+ny) >= grid.length) continue;
+ for(let nx = -1; nx <= 1; nx++) {
+ if ((x+nx) < 0) continue;
+ if ((x+nx) >= row.length) continue;
+ // Skip self
+ if (nx === 0 && ny === 0) continue;
+ neighbours[y+ny][x+nx]++;
+ }
+ }
+ }
+ }
+
+ return neighbours;
+};
+
+const buildReachable = (grid, neighbours) => {
+ // Mark reachable rolls in part 1
+ let count = 0;
+ const _map = grid.map(row => row.map(() => false));
+ for(let y = 0; y < grid.length; y++) {
+ const row = grid[y];
+ for(let x = 0; x < row.length ; x++) {
+ // Skip if we're empty
+ if (!grid[y][x]) continue;
+ if (neighbours[y][x] >= 4) continue;
+ _map[y][x] = true;
+ count++;
+ }
+ }
+ return {
+ _map,
+ count,
+ };
+};
+
+const removeReachable = (grid, reachableMap) => {
+ for(let y = 0; y < grid.length; y++) {
+ const row = grid[y];
+ for(let x = 0; x < row.length ; x++) {
+ if (reachableMap[y][x]) row[x] = false;
+ }
+ }
+};
+
+// Debug display origin grid
+const displayGrid = grid => {
+ process.stdout.write(
+ grid.map(row => row.map(c => c ? '@' : '.').join('')).join('\n') + '\n\n'
+ );
+};
+
+// Debug display
+const displayReachable = (grid, reachableMap) => {
+ process.stdout.write(
+ grid.map(
+ (row,y) => row.map(
+ (roll,x) => reachableMap[y][x] ? 'x' : roll ? '@' : '.'
+ ).join('')
+ ).join('\n') + '\n\n'
+ );
+}
+
+let neighbours = buildNeighbours(grid);
+let reachable = buildReachable(grid, neighbours);
+const part1 = reachable.count;
+
+let totalRemoved = 0;
+
+console.log(`Initial state:`);
+displayGrid(grid);
+
+while(reachable.count) {
+ console.log(`Remove ${reachable.count} rolls of paper:`);
+ totalRemoved += reachable.count;
+ displayReachable(grid, reachable._map);
+
+ removeReachable(grid, reachable._map);
+ neighbours = buildNeighbours(grid);
+ reachable = buildReachable(grid, neighbours);
+}
+
+process.stdout.write('\n');
+process.stdout.write(`------[ Part 1: ${part1} ]------\n`);
+process.stdout.write(`------[ Part 2: ${totalRemoved} ]------\n`);