diff --git a/y2024/src/days/d16.rs b/y2024/src/days/d16.rs index 14c8bda..fab4ecf 100644 --- a/y2024/src/days/d16.rs +++ b/y2024/src/days/d16.rs @@ -1,7 +1,4 @@ -use std::{ - collections::{HashMap, HashSet}, - error::Error, -}; +use std::{collections::HashMap, error::Error}; use itertools::Itertools; @@ -37,6 +34,7 @@ pub fn process_part1(input: &str) -> usize { }]; let mut arrived: Vec = Vec::new(); let mut visited = HashMap::new(); + let mut iter = 0; while !next_paths.is_empty() { next_paths = next_paths .iter() @@ -59,7 +57,9 @@ pub fn process_part1(input: &str) -> usize { arrived.push(arrived_reindeer); } } + iter += 1; } + println!("Iterations to goal {iter}"); arrived.iter().map(|reindeer| reindeer.score).min().unwrap() } @@ -89,15 +89,15 @@ pub fn process_part2(input: &str) -> usize { .collect_vec() }) .collect_vec(); - let mut visited = HashSet::new(); - visited.insert(start); + let mut smallest_score = usize::MAX; + let mut visited = HashMap::new(); + visited.insert((start, Orientation::East), 0); let mut next_paths = vec![Reindeer { coords: start, - visited, + visited: visited.clone(), ..Default::default() }]; let mut arrived: Vec = Vec::new(); - let mut visited = HashMap::new(); while !next_paths.is_empty() { next_paths = next_paths .iter() @@ -105,33 +105,47 @@ pub fn process_part2(input: &str) -> usize { .collect_vec() .concat(); for (idx, reindeer) in next_paths.clone().iter().enumerate().rev() { - if let Some(_score) = visited.get_mut(&reindeer.coords) { - //if *score < reindeer.score { - // next_paths.remove(idx); - // continue; - //} else { - // *score = reindeer.score; - //} - } else { - visited.insert(reindeer.coords, reindeer.score); + if reindeer.score > smallest_score + || reindeer + .visited + .contains_key(&(reindeer.coords, reindeer.orientation)) + { + next_paths.remove(idx); + continue; } - if reindeer.state == ReindeerState::Arrived { + next_paths[idx] + .visited + .insert((reindeer.coords, reindeer.orientation), reindeer.score); + if let Some(score) = visited.get_mut(&(reindeer.coords, reindeer.orientation)) { + if *score < reindeer.score { + next_paths.remove(idx); + continue; + } else { + *score = reindeer.score; + } + } else { + visited.insert((reindeer.coords, reindeer.orientation), reindeer.score); + } + if reindeer.state == ReindeerState::Arrived && reindeer.score <= smallest_score { + smallest_score = reindeer.score; let arrived_reindeer = next_paths.remove(idx); arrived.push(arrived_reindeer); } } + arrived.retain(|reindeer| reindeer.score == smallest_score); } - let min_score = arrived.iter().map(|reindeer| reindeer.score).min().unwrap(); let visited = arrived - .into_iter() - .filter(|reindeer| reindeer.score == min_score) - .collect_vec(); - println!("{visited:?}"); - let visited = visited - .into_iter() - .map(|reindeer| reindeer.visited.into_iter().collect_vec()) + .iter() + .map(|reindeer| { + reindeer + .visited + .keys() + .map(|(coords, _)| coords) + .collect_vec() + }) .collect_vec() .concat(); + log_maze(&grid, &arrived); visited.iter().unique().count() } @@ -177,7 +191,7 @@ struct Reindeer { orientation: Orientation, coords: (usize, usize), score: usize, - visited: HashSet<(usize, usize)>, + visited: HashMap<((usize, usize), Orientation), usize>, state: ReindeerState, } @@ -195,28 +209,23 @@ impl Reindeer { Orientation::South => (self.coords.0, self.coords.1 + 1), Orientation::North => (self.coords.0, self.coords.1 - 1), }; - let mut visited = self.visited.clone(); - visited.insert(coords); if tile == GridTile::Wall { Reindeer { state: ReindeerState::Stuck, - visited, - ..*self + ..self.clone() } } else if tile == GridTile::End { Reindeer { score: self.score + 1, state: ReindeerState::Arrived, coords, - visited, - ..*self + ..self.clone() } } else { Reindeer { score: self.score + 1, coords, - visited, - ..*self + ..self.clone() } } } @@ -234,13 +243,10 @@ impl Reindeer { Orientation::South => (self.coords.0 - 1, self.coords.1), Orientation::North => (self.coords.0 + 1, self.coords.1), }; - let mut visited = self.visited.clone(); - visited.insert(coords); if tile == GridTile::Wall { Reindeer { state: ReindeerState::Stuck, - visited, - ..*self + ..self.clone() } } else if tile == GridTile::End { Reindeer { @@ -248,15 +254,14 @@ impl Reindeer { state: ReindeerState::Arrived, coords, orientation: self.orientation.turn_clockwise(), - visited, + ..self.clone() } } else { Reindeer { score: self.score + 1001, orientation: self.orientation.turn_clockwise(), coords, - visited, - ..*self + ..self.clone() } } } @@ -274,13 +279,10 @@ impl Reindeer { Orientation::South => (self.coords.0 + 1, self.coords.1), Orientation::North => (self.coords.0 - 1, self.coords.1), }; - let mut visited = self.visited.clone(); - visited.insert(coords); if tile == GridTile::Wall { Reindeer { state: ReindeerState::Stuck, - visited, - ..*self + ..self.clone() } } else if tile == GridTile::End { Reindeer { @@ -288,15 +290,14 @@ impl Reindeer { state: ReindeerState::Arrived, coords, orientation: self.orientation.turn_counterclockwise(), - visited, + ..self.clone() } } else { Reindeer { score: self.score + 1001, orientation: self.orientation.turn_counterclockwise(), coords, - visited, - ..*self + ..self.clone() } } } @@ -342,6 +343,47 @@ impl TryFrom for GridTile { } } +fn log_maze(grid: &[Vec], visited: &Vec) { + for (yidx, row) in grid.iter().enumerate() { + for (xidx, tile) in row.iter().enumerate() { + let contains = { + let mut contains = false; + for reindeer in visited { + if reindeer + .visited + .contains_key(&((xidx, yidx), Orientation::East)) + || reindeer + .visited + .contains_key(&((xidx, yidx), Orientation::West)) + || reindeer + .visited + .contains_key(&((xidx, yidx), Orientation::North)) + || reindeer + .visited + .contains_key(&((xidx, yidx), Orientation::South)) + { + contains = true; + break; + } + } + contains + }; + if contains && !(*tile == GridTile::Start || *tile == GridTile::End) { + print!("O"); + } else if *tile == GridTile::Wall { + print!("#"); + } else if *tile == GridTile::Path { + print!("."); + } else if *tile == GridTile::Start { + print!("S"); + } else if *tile == GridTile::End { + print!("E"); + } + } + println!(); + } +} + #[cfg(test)] mod tests { use super::*;