summaryrefslogtreecommitdiff
path: root/aoc/2025/04
diff options
context:
space:
mode:
Diffstat (limited to 'aoc/2025/04')
-rwxr-xr-xaoc/2025/04/python.py36
-rw-r--r--aoc/2025/04/rust/Cargo.lock7
-rw-r--r--aoc/2025/04/rust/Cargo.toml6
-rw-r--r--aoc/2025/04/rust/src/main.rs66
4 files changed, 115 insertions, 0 deletions
diff --git a/aoc/2025/04/python.py b/aoc/2025/04/python.py
new file mode 100755
index 0000000..844c38e
--- /dev/null
+++ b/aoc/2025/04/python.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+
+from fileinput import input
+
+g = {
+ complex(x, y): ch
+ for y, line in enumerate(input())
+ for x, ch in enumerate(line.strip())
+}
+
+
+def accessible():
+ return {
+ p
+ for p, x in g.items()
+ if x == "@"
+ and sum(
+ 1
+ for dx in (-1, 0, 1)
+ for dy in (-1j, 0j, 1j)
+ if dx + dy != 0 and g.get(p + dx + dy, ".") == "@"
+ )
+ < 4
+ }
+
+
+silver = len(accessible())
+gold = 0
+
+while rem := accessible():
+ gold += len(rem)
+ for gone in rem:
+ g.pop(gone)
+
+print("silver:", silver)
+print("gold:", gold)
diff --git a/aoc/2025/04/rust/Cargo.lock b/aoc/2025/04/rust/Cargo.lock
new file mode 100644
index 0000000..ac79b17
--- /dev/null
+++ b/aoc/2025/04/rust/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "puzzle"
+version = "0.1.0"
diff --git a/aoc/2025/04/rust/Cargo.toml b/aoc/2025/04/rust/Cargo.toml
new file mode 100644
index 0000000..26e4e77
--- /dev/null
+++ b/aoc/2025/04/rust/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "puzzle"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
diff --git a/aoc/2025/04/rust/src/main.rs b/aoc/2025/04/rust/src/main.rs
new file mode 100644
index 0000000..3b13140
--- /dev/null
+++ b/aoc/2025/04/rust/src/main.rs
@@ -0,0 +1,66 @@
+use std::{collections::VecDeque, io};
+
+fn main() {
+ let mut grid: Vec<Vec<Option<usize>>> = io::stdin()
+ .lines()
+ .flatten()
+ .map(|line| line.chars().map(|ch| (ch == '@').then_some(0)).collect())
+ .collect();
+
+ // count neighbours
+ points(&grid)
+ .collect::<Vec<_>>()
+ .into_iter()
+ .for_each(|p @ (x, y)| {
+ let ns = neighbours(p, &grid).count();
+ if let Some(n) = grid[y][x].as_mut() {
+ *n = ns;
+ }
+ });
+
+ let mut stack = points(&grid)
+ .filter(|&(x, y)| grid[y][x].is_some_and(|n| n < 4))
+ .collect::<VecDeque<_>>();
+ let silver = stack.len();
+ let mut gold = 0;
+
+ while let Some(p @ (x, y)) = stack.pop_back() {
+ if grid[y][x].take().is_none() {
+ continue;
+ }
+ gold += 1;
+ // reduce neighbours' neighbour counts by 1
+ neighbours(p, &grid)
+ .collect::<Vec<_>>()
+ .into_iter()
+ .for_each(|(nx, ny)| {
+ if let Some(n) = grid[ny][nx].as_mut() {
+ *n -= 1;
+ if *n < 4 {
+ stack.push_back((nx, ny))
+ }
+ }
+ });
+ }
+
+ println!("silver: {silver}");
+ println!("gold: {gold}");
+}
+
+fn neighbours<T>(
+ (x, y): (usize, usize),
+ grid: &Vec<Vec<Option<T>>>,
+) -> impl Iterator<Item = (usize, usize)> {
+ let xs = x.saturating_sub(1)..=(x + 1).min(grid.first().unwrap().len() - 1);
+ let ys = y.saturating_sub(1)..=(y + 1).min(grid.len() - 1);
+
+ xs.flat_map(move |nx| ys.clone().map(move |ny| (nx, ny)))
+ .filter(move |n| *n != (x, y))
+ .filter(|&(nx, ny)| grid.get(ny).and_then(|row| row.get(nx)).unwrap().is_some())
+}
+
+fn points<T>(grid: &Vec<Vec<T>>) -> impl Iterator<Item = (usize, usize)> {
+ let xs = 0..grid.first().unwrap().len();
+ let ys = 0..grid.len();
+ xs.flat_map(move |x| ys.clone().map(move |y| (x, y)))
+}