diff --git a/.aoc_tiles/tiles/2025/04.png b/.aoc_tiles/tiles/2025/04.png new file mode 100644 index 0000000..2b574ec Binary files /dev/null and b/.aoc_tiles/tiles/2025/04.png differ diff --git a/README.md b/README.md index ba3e2c6..2518675 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- 2025 - 6 ⭐ - Rust + 2025 - 7 ⭐ - Rust

@@ -11,4 +11,7 @@ + + + diff --git a/src/day4.rs b/src/day4.rs new file mode 100644 index 0000000..ab98f5e --- /dev/null +++ b/src/day4.rs @@ -0,0 +1,47 @@ +use aoc_runner_derive::{aoc, aoc_generator}; +use grid::Grid; + +#[aoc_generator(day4)] +fn parse(input: &str) -> Grid { + input.parse().unwrap() +} + +#[aoc(day4, part1)] +fn part1(input: &Grid) -> u64 { + (0..input.height() * input.width()) + .filter(|i| *input.get(&input.coord(*i as i64).unwrap()).unwrap() == b'@') + .map(|i| input.neighbours_count(input.coord(i as i64).unwrap(), |c| *c == b'@')) + .filter(|n| *n < 4) + .count() as u64 +} + +#[aoc(day4, part2)] +fn part2(input: &Grid) -> u64 { + input.width() as u64 +} + +#[cfg(test)] +mod tests { + use super::*; + + const EXAMPLE: &str = "..@@.@@@@. +@@@.@.@.@@ +@@@@@.@.@@ +@.@@@@..@. +@@.@@@@.@@ +.@@@@@@@.@ +.@.@.@.@@@ +@.@@@.@@@@ +.@@@@@@@@. +@.@.@@@.@."; + + #[test] + fn part1_example() { + assert_eq!(part1(&parse(EXAMPLE)), 13); + } + + #[test] + fn part2_example() { + assert_eq!(part2(&parse(EXAMPLE)), 0); + } +} diff --git a/src/lib.rs b/src/lib.rs index 31454ef..3961a65 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ mod day1; mod day2; mod day3; +mod day4; use aoc_runner_derive::aoc_lib; diff --git a/utils/grid/lib.rs b/utils/grid/lib.rs index 67f810c..2b0b6e3 100644 --- a/utils/grid/lib.rs +++ b/utils/grid/lib.rs @@ -352,6 +352,28 @@ impl Grid { } } + /// Return the count of neighbours (8 directions) matching predicate p + pub fn neighbours_count(&self, c: C, mut p: P) -> usize + where + P: FnMut(&T) -> bool, + { + const DIRECTIONS: [(i64, i64); 8] = [ + (-1, -1), + (0, -1), + (1, -1), + (-1, 0), + (1, 0), + (1, 1), + (0, 1), + (-1, 1), + ]; + DIRECTIONS + .iter() + .map(|d| (c.x() + d.0, c.y() + d.1)) + .filter(|c| self.get(c).is_some_and(|x| p(x))) + .count() + } + // fn window_compare_impl(&self, needle: &[T]) -> Vec<(i64, i64)> { // if (self.width as usize) < needle.len() { // return Vec::new();