From c9e4d63abe90fb231554775f8dd5c59ae52e6769 Mon Sep 17 00:00:00 2001 From: Glenn Griffin Date: Wed, 23 Dec 2020 23:41:59 -0800 Subject: [PATCH] day24 part 2 --- src/day24.rs | 115 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 101 insertions(+), 14 deletions(-) diff --git a/src/day24.rs b/src/day24.rs index 9d6cab6..6361539 100644 --- a/src/day24.rs +++ b/src/day24.rs @@ -1,6 +1,21 @@ use aoc_runner_derive::aoc; use std::collections::HashMap; +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +struct Pos(isize, isize); +impl Pos { + fn step(self, dir: Direction) -> Self { + match dir { + Direction::E => Pos(self.0 + 2, self.1), + Direction::SE => Pos(self.0 + 1, self.1 -1), + Direction::SW => Pos(self.0 -1, self.1 -1), + Direction::W => Pos(self.0 -2, self.1), + Direction::NE => Pos(self.0 + 1, self.1 + 1), + Direction::NW => Pos(self.0 -1, self.1 + 1), + } + } +} + #[derive(Debug, Copy, Clone)] enum Direction { E, @@ -24,17 +39,6 @@ impl Direction { } } - fn step(self) -> (isize, isize) { - match self { - Direction::E => (2, 0), - Direction::SE => (1, -1), - Direction::SW => (-1, -1), - Direction::W => (-2, 0), - Direction::NE => (1, 1), - Direction::NW => (-1, 1), - } - } - fn iter(input: &[u8]) -> impl Iterator + '_ { struct Iter<'a>(&'a [u8]); impl<'a> Iterator for Iter<'a> { @@ -53,13 +57,26 @@ impl Direction { } } +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +enum Tile { + Black, + White, +} +impl Tile { + fn flip(&mut self) { + *self = match *self { + Tile::Black => Tile::White, + Tile::White => Tile::Black, + }; + } +} + #[aoc(day24, part1)] fn solve_d24_p1(input: &str) -> usize { let mut tiles: HashMap<_, usize> = HashMap::new(); for pos in input.split('\n').map(|line| { - Direction::iter(line.as_bytes()).fold((0, 0), |pos, dir| { - let (x_step, y_step) = dir.step(); - (pos.0 + x_step, pos.1 + y_step) + Direction::iter(line.as_bytes()).fold(Pos(0, 0), |pos, dir| { + pos.step(dir) }) }) { *tiles.entry(pos).or_default() += 1; @@ -70,3 +87,73 @@ fn solve_d24_p1(input: &str) -> usize { .filter(|×_flipped| times_flipped % 2 == 1) .count() } + +#[aoc(day24, part2)] +fn solve_d24_p2(input: &str) -> usize { + let mut floor: HashMap<_, Tile> = HashMap::new(); + for pos in input.split('\n').map(|line| { + Direction::iter(line.as_bytes()).fold(Pos(0, 0), |pos, dir| { + pos.step(dir) + }) + }) { + floor.entry(pos).or_insert(Tile::White).flip() + } + + for _ in 0..100 { + let mut tiles_visited = HashMap::new(); + for &pos in floor.keys() { + run(&floor, &mut tiles_visited, pos); + } + for pos in tiles_visited + .into_iter() + .filter_map(|(k, should_flip)| if should_flip { Some(k) } else { None }) + { + floor.entry(pos).or_insert(Tile::White).flip(); + } + } + + floor.values().filter(|&&tile| tile == Tile::Black).count() +} + +fn run( + floor: &HashMap, + tiles_visited: &mut HashMap, + pos: Pos, +) { + if tiles_visited.contains_key(&pos) { + return; + } + let n = neighbors(floor, pos); + let black_tiles = n + .iter() + .copied() + .filter(|&tile| tile == Tile::Black) + .count(); + let tile = floor.get(&pos).copied().unwrap_or(Tile::White); + if (tile == Tile::Black && (black_tiles == 0 || black_tiles > 2)) + || (tile == Tile::White && black_tiles == 2) + { + tiles_visited.insert(pos, true); + } else { + tiles_visited.insert(pos, false); + } + if black_tiles > 0 { + run(floor, tiles_visited, pos.step(Direction::E)); + run(floor, tiles_visited, pos.step(Direction::SE)); + run(floor, tiles_visited, pos.step(Direction::SW)); + run(floor, tiles_visited, pos.step(Direction::W)); + run(floor, tiles_visited, pos.step(Direction::NE)); + run(floor, tiles_visited, pos.step(Direction::NW)); + } +} + +fn neighbors(floor: &HashMap, pos: Pos) -> [Tile; 6] { + [ + floor.get(&pos.step(Direction::E)).copied().unwrap_or(Tile::White), + floor.get(&pos.step(Direction::SE)).copied().unwrap_or(Tile::White), + floor.get(&pos.step(Direction::SW)).copied().unwrap_or(Tile::White), + floor.get(&pos.step(Direction::W)).copied().unwrap_or(Tile::White), + floor.get(&pos.step(Direction::NE)).copied().unwrap_or(Tile::White), + floor.get(&pos.step(Direction::NW)).copied().unwrap_or(Tile::White), + ] +}