Files
aoc2025/src/day4.rs

97 lines
2.3 KiB
Rust

use aoc_runner_derive::{aoc, aoc_generator};
use grid::Grid;
use itertools::Itertools;
#[aoc_generator(day4)]
fn parse(input: &str) -> Grid<u8> {
input.parse().unwrap()
}
#[aoc(day4, part1, Brute)]
fn part1(input: &Grid<u8>) -> u64 {
(0..input.height() * input.width())
.filter(|i| *input.get(&input.coord(*i as i64).unwrap()).unwrap() == b'@')
.map(|i| input.adjacent_count(&input.coord(i as i64).unwrap(), |c| *c == b'@'))
.filter(|n| *n < 4)
.count() as u64
}
#[aoc(day4, part2, Brute)]
fn part2(input: &Grid<u8>) -> u64 {
let mut grid = input.clone();
let mut removed = 0;
loop {
let mut removed_iteration = 0;
for i in 0..grid.width() * grid.height() {
let pos = grid.coord(i as i64).unwrap();
if grid.get(&pos).is_some_and(|c| *c == b'@')
&& grid.adjacent_count(&pos, |c| *c == b'@') < 4
{
// remove the roll
grid.set(&pos, b'.');
removed_iteration += 1;
}
}
if removed_iteration == 0 {
return removed;
}
removed += removed_iteration
}
}
#[aoc(day4, part2, RollList)]
fn part2_list(input: &Grid<u8>) -> u64 {
let mut grid = input.clone();
let mut to_check = grid.find_all(&b'@').collect_vec();
let mut removed = 0;
while let Some(roll) = to_check.pop() {
if grid.get(&roll).is_none_or(|c| *c == b'.') {
continue;
}
let adjacent_rolls = grid
.adjacent_iter(&roll)
.filter_map(|i| if *i.value == b'@' { Some(i.pos) } else { None })
.collect_vec();
if adjacent_rolls.len() < 4 {
grid.set(&roll, b'.');
removed += 1;
to_check.extend_from_slice(&adjacent_rolls);
}
}
removed
}
#[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)), 43);
}
#[test]
fn part2_list_example() {
assert_eq!(part2_list(&parse(EXAMPLE)), 43);
}
}