diff --git a/src/tasks/day20.rs b/src/tasks/day20.rs index f82bb71..5a91f4d 100644 --- a/src/tasks/day20.rs +++ b/src/tasks/day20.rs @@ -2,12 +2,13 @@ use std::collections::{HashMap, HashSet, VecDeque}; pub fn run() { let input = std::fs::read_to_string("input/day20.txt").unwrap(); - let maze = Maze::from(&input); + let maze = Maze::from(&input, PortalField::create); let part1 = maze.shortest_path(); println!("Part 1: {}", part1); } type C = i32; +type FieldFactory = fn(&Point) -> Box; #[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)] struct Point { @@ -30,48 +31,91 @@ impl Point { } } -struct Field { +trait Field { + fn neighbors(&self) -> Vec; + fn set_label_partner(&mut self, point: Point); + fn set_neighbors(&mut self, neighbors: Vec); + fn create(point: &Point) -> Box where Self: Sized; +} + +struct PortalField { neighbors: Vec, } -impl Field { - fn of() -> Self { - Field { neighbors: vec![] } +impl PortalField { + fn new() -> Self { + PortalField { neighbors: vec![] } } } -pub struct Maze { - map: HashMap, +impl Field for PortalField { + fn neighbors(&self) -> Vec { + self.neighbors.clone() + } + + fn set_label_partner(&mut self, point: Point) { + self.neighbors.push(point); + } + + fn set_neighbors(&mut self, neighbors: Vec) { + self.neighbors = neighbors; + } + + fn create(_: &Point) -> Box where Self: Sized { + Box::new(PortalField::new()) + } +} + +//impl Field for PortalField { +// fn neighbors(self, level: usize) -> Vec { +// if let Some((direction, p)) = self.dimension_neighbor { +// if direction == DimensionUp && level < 0 { +// let mut v = self.neighbors.clone(); +// v.push(p); +// v +// } else { +// self.neighbors.clone() +// } +// } else { +// self.neighbors.clone() +// } +// } +//} + +type FieldMap = HashMap>; + +struct Maze { + map: FieldMap, start: Point, finish: Point, } impl Maze { - pub fn from(input: &String) -> Self { + fn from(input: &String, field_factory: FieldFactory) -> Self { let (moc, width, height) = Self::map_of_chars(input); - let mut map = Self::create_map_of_free_spots(&moc); + let mut map = Self::create_map_of_free_spots(&moc, field_factory); Self::add_physical_neighbors(&mut map); let labels = Self::labels(&moc, width, height); - Self::add_portals(&mut map, &labels); + Self::process_labels(&mut map, &labels); let start = labels["AA"][0]; let finish = labels["ZZ"][0]; Maze { map, start, finish } } - pub fn shortest_path(&self) -> usize { + fn shortest_path(&self) -> usize { bfs(&self.map, self.start, self.finish) } - fn add_portals(map: &mut HashMap, labels: &HashMap>) { + fn process_labels(map: &mut FieldMap, labels: &HashMap>) { for (label, points) in labels { if label == "AA" || label == "ZZ" { continue; } - map.get_mut(&points[0]).unwrap().neighbors.push(points[1]); - map.get_mut(&points[1]).unwrap().neighbors.push(points[0]); + map.get_mut(&points[0]).unwrap().set_label_partner(points[1]); + map.get_mut(&points[1]).unwrap().set_label_partner(points[0]); } } @@ -135,7 +179,7 @@ impl Maze { } } - fn add_physical_neighbors(map: &mut HashMap) { + fn add_physical_neighbors(map: &mut FieldMap) { let points: HashSet = map.keys().map(|p| *p).collect(); map.iter_mut().for_each(|(p, f)| { let neighbors = p @@ -143,14 +187,14 @@ impl Maze { .into_iter() .filter(|neighbor| points.contains(neighbor)) .collect(); - f.neighbors = neighbors; + f.set_neighbors(neighbors); }) } - fn create_map_of_free_spots(moc: &HashMap) -> HashMap { + fn create_map_of_free_spots(moc: &HashMap, field_factory: FieldFactory) -> FieldMap { moc.keys() .filter(|p| moc[p] == '.') - .map(|p| (*p, Field::of())) + .map(|p| (*p, field_factory(p))) .collect() } @@ -179,7 +223,7 @@ impl Maze { } } -fn bfs(map: &HashMap, start: Point, finish: Point) -> usize { +fn bfs(map: &FieldMap, start: Point, finish: Point) -> usize { let mut open: VecDeque<(Point, usize)> = VecDeque::new(); let mut seen: HashSet = HashSet::new(); @@ -190,11 +234,11 @@ fn bfs(map: &HashMap, start: Point, finish: Point) -> usize { return d; } - for neighbor in &map[&p].neighbors { - if !seen.contains(neighbor) { - open.push_back((*neighbor, d + 1)); + for neighbor in map[&p].neighbors() { + if !seen.contains(&neighbor) { + open.push_back((neighbor, d + 1)); } - seen.insert(*neighbor); + seen.insert(neighbor); } } panic!("no path found") @@ -202,19 +246,19 @@ fn bfs(map: &HashMap, start: Point, finish: Point) -> usize { #[cfg(test)] mod test { - use crate::tasks::day20::Maze; + use crate::tasks::day20::{Field, Maze, PortalField}; #[test] fn example1() { let input = std::fs::read_to_string("input/day20_example1.txt").unwrap(); - let maze = Maze::from(&input); + let maze = Maze::from(&input, PortalField::create); assert_eq!(maze.shortest_path(), 23); } #[test] fn result() { let input = std::fs::read_to_string("input/day20.txt").unwrap(); - let maze = Maze::from(&input); + let maze = Maze::from(&input, PortalField::create); assert_eq!(maze.shortest_path(), 454); } }