use winnow::{ Parser, Result, ascii::{multispace0, newline}, combinator::{alt, preceded, repeat, terminated}, }; use crate::{AoC, SimpleDay, WinnowDay}; fn day() -> impl WinnowDay { AoC::new(parse as _, part1 as _, part2 as _) } type Parsed = Vec>; #[derive(Debug, PartialEq, Eq)] enum Cell { Empty, Paper, } impl Cell { fn is_empty(&self) -> bool { self == &Cell::Empty } fn is_paper(&self) -> bool { self == &Cell::Paper } } fn parse(input: &mut &str) -> Result { repeat(1.., preceded(multispace0, parse_line)).parse_next(input) } fn parse_line(input: &mut &str) -> Result> { repeat(1.., parse_cell).parse_next(input) } fn parse_cell(input: &mut &str) -> Result { alt((".".map(|_| Cell::Empty), "@".map(|_| Cell::Paper))).parse_next(input) } fn part1(input: Parsed) -> usize { let mut input = input; remove_paper(&mut input) } fn remove_paper(input: &mut [Vec]) -> usize { let mut score = 0; let mut access = Vec::new(); let h = input.len(); let w = input[0].len(); let directions = [ (-1, -1), (0, -1), (1, -1), (1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), ]; for y in 0..h { for x in 0..w { match input[y][x] { Cell::Empty => {} Cell::Paper => { let count = directions .iter() .filter(|dir| { let nx = x as isize + dir.0; let ny = y as isize + dir.1; nx >= 0 && nx < w as isize && ny >= 0 && ny < h as isize && input[ny as usize][nx as usize].is_paper() }) .count(); if count < 4 { score += 1; access.push((x, y)); } } } } } access.iter().for_each(|(x, y)| { input[*y][*x] = Cell::Empty; }); score } fn part2(input: Parsed) -> usize { let mut input = input; let mut score = 0; loop { let removed = remove_paper(&mut input); score += removed; if removed == 0 { return score; } } } #[cfg(test)] mod tests { use crate::Day; use super::*; #[test] fn part1_test() { day().assert1( "..@@.@@@@. @@@.@.@.@@ @@@@@.@.@@ @.@@@@..@. @@.@@@@.@@ .@@@@@@@.@ .@.@.@.@@@ @.@@@.@@@@ .@@@@@@@@. @.@.@@@.@.", "13", ); } #[test] fn part1_solve() { day().assert1(include_str!("../input/day4.txt"), "1356"); } #[test] fn part2_test() { day().assert2( "..@@.@@@@. @@@.@.@.@@ @@@@@.@.@@ @.@@@@..@. @@.@@@@.@@ .@@@@@@@.@ .@.@.@.@@@ @.@@@.@@@@ .@@@@@@@@. @.@.@@@.@.", "43", ); } #[test] fn part2_solve() { day().assert2(include_str!("../input/day4.txt"), "8713"); } }