diff --git a/src/tasks/day20.rs b/src/tasks/day20.rs index 5a91f4d..0a251d7 100644 --- a/src/tasks/day20.rs +++ b/src/tasks/day20.rs @@ -8,38 +8,57 @@ pub fn run() { } type C = i32; -type FieldFactory = fn(&Point) -> Box; +type FieldFactory = fn(&MapPoint) -> Box; #[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)] -struct Point { +struct MapPoint { x: C, y: C, } -impl Point { +impl MapPoint { fn of(x: C, y: C) -> Self { - Point { x, y } + MapPoint { x, y } } - fn neighbors(self) -> Vec { + fn neighbors(self) -> Vec { vec![ - Point::of(self.x + 1, self.y), - Point::of(self.x, self.y + 1), - Point::of(self.x - 1, self.y), - Point::of(self.x, self.y - 1), + MapPoint::of(self.x + 1, self.y), + MapPoint::of(self.x, self.y + 1), + MapPoint::of(self.x - 1, self.y), + MapPoint::of(self.x, self.y - 1), ] } } +#[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)] +struct RealPoint { + x: C, + y: C, + level: usize, +} + +impl RealPoint { + fn map_point(&self) -> MapPoint { + MapPoint { x: self.x, y: self.y } + } +} + +impl RealPoint { + fn from(map_point: MapPoint, level: usize) -> Self { + RealPoint { x: map_point.x, y: map_point.y, level } + } +} + 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; + fn neighbors(&self, at_level: usize) -> Vec; + fn set_label_partner(&mut self, point: MapPoint); + fn set_neighbors(&mut self, neighbors: Vec); + fn create(point: &MapPoint) -> Box where Self: Sized; } struct PortalField { - neighbors: Vec, + neighbors: Vec, } impl PortalField { @@ -49,19 +68,19 @@ impl PortalField { } impl Field for PortalField { - fn neighbors(&self) -> Vec { - self.neighbors.clone() + fn neighbors(&self, _: usize) -> Vec { + self.neighbors.iter().map(|p| RealPoint::from(*p, 0)).collect() } - fn set_label_partner(&mut self, point: Point) { + fn set_label_partner(&mut self, point: MapPoint) { self.neighbors.push(point); } - fn set_neighbors(&mut self, neighbors: Vec) { + fn set_neighbors(&mut self, neighbors: Vec) { self.neighbors = neighbors; } - fn create(_: &Point) -> Box where Self: Sized { + fn create(_: &MapPoint) -> Box where Self: Sized { Box::new(PortalField::new()) } } @@ -82,12 +101,12 @@ impl Field for PortalField { // } //} -type FieldMap = HashMap>; +type FieldMap = HashMap>; struct Maze { map: FieldMap, - start: Point, - finish: Point, + start: RealPoint, + finish: RealPoint, } impl Maze { @@ -101,14 +120,14 @@ impl Maze { let start = labels["AA"][0]; let finish = labels["ZZ"][0]; - Maze { map, start, finish } + Maze { map, start: RealPoint::from(start, 0), finish: RealPoint::from(finish, 0) } } fn shortest_path(&self) -> usize { bfs(&self.map, self.start, self.finish) } - fn process_labels(map: &mut FieldMap, labels: &HashMap>) { + fn process_labels(map: &mut FieldMap, labels: &HashMap>) { for (label, points) in labels { if label == "AA" || label == "ZZ" { continue; @@ -119,37 +138,37 @@ impl Maze { } } - fn labels(moc: &HashMap, width: C, height: C) -> HashMap> { - let horizontal: Vec<(String, Point)> = (0..width - 2) + fn labels(moc: &HashMap, width: C, height: C) -> HashMap> { + let horizontal: Vec<(String, MapPoint)> = (0..width - 2) .into_iter() .flat_map(|x| { (0..height).into_iter().flat_map(move |y| { let mut triple = [ - moc[&Point::of(x, y)], - moc[&Point::of(x + 1, y)], - moc[&Point::of(x + 2, y)], + moc[&MapPoint::of(x, y)], + moc[&MapPoint::of(x + 1, y)], + moc[&MapPoint::of(x + 2, y)], ]; - let left = Self::label(triple).map(|label| (label, Point::of(x, y))); + let left = Self::label(triple).map(|label| (label, MapPoint::of(x, y))); triple.reverse(); - let right = Self::label(triple).map(|label| (label, Point::of(x + 2, y))); + let right = Self::label(triple).map(|label| (label, MapPoint::of(x + 2, y))); vec![left, right] }) }) .flatten() .collect(); - let vertical: Vec<(String, Point)> = (0..width) + let vertical: Vec<(String, MapPoint)> = (0..width) .into_iter() .flat_map(|x| { (0..height - 2).into_iter().flat_map(move |y| { let mut triple = [ - moc[&Point::of(x, y)], - moc[&Point::of(x, y + 1)], - moc[&Point::of(x, y + 2)], + moc[&MapPoint::of(x, y)], + moc[&MapPoint::of(x, y + 1)], + moc[&MapPoint::of(x, y + 2)], ]; - let left = Self::label(triple).map(|label| (label, Point::of(x, y))); + let left = Self::label(triple).map(|label| (label, MapPoint::of(x, y))); triple.reverse(); - let right = Self::label(triple).map(|label| (label, Point::of(x, y + 2))); + let right = Self::label(triple).map(|label| (label, MapPoint::of(x, y + 2))); vec![left, right] }) }) @@ -180,7 +199,7 @@ impl Maze { } fn add_physical_neighbors(map: &mut FieldMap) { - let points: HashSet = map.keys().map(|p| *p).collect(); + let points: HashSet = map.keys().map(|p| *p).collect(); map.iter_mut().for_each(|(p, f)| { let neighbors = p .neighbors() @@ -191,21 +210,21 @@ impl Maze { }) } - fn create_map_of_free_spots(moc: &HashMap, field_factory: FieldFactory) -> FieldMap { + fn create_map_of_free_spots(moc: &HashMap, field_factory: FieldFactory) -> FieldMap { moc.keys() .filter(|p| moc[p] == '.') .map(|p| (*p, field_factory(p))) .collect() } - fn map_of_chars(input: &String) -> (HashMap, C, C) { - let mut map: HashMap = input + fn map_of_chars(input: &String) -> (HashMap, C, C) { + let mut map: HashMap = input .lines() .enumerate() .flat_map(|(y, line)| { line.chars() .enumerate() - .map(move |(x, c)| (Point::of(x as C, y as C), c)) + .map(move |(x, c)| (MapPoint::of(x as C, y as C), c)) }) .collect(); @@ -214,8 +233,8 @@ impl Maze { for x in 0..width { for y in 0..height { - if !map.contains_key(&Point::of(x, y)) { - map.insert(Point::of(x, y), ' '); + if !map.contains_key(&MapPoint::of(x, y)) { + map.insert(MapPoint::of(x, y), ' '); } } } @@ -223,9 +242,9 @@ impl Maze { } } -fn bfs(map: &FieldMap, start: Point, finish: Point) -> usize { - let mut open: VecDeque<(Point, usize)> = VecDeque::new(); - let mut seen: HashSet = HashSet::new(); +fn bfs(map: &FieldMap, start: RealPoint, finish: RealPoint) -> usize { + let mut open: VecDeque<(RealPoint, usize)> = VecDeque::new(); + let mut seen: HashSet = HashSet::new(); open.push_back((start, 0)); @@ -234,7 +253,7 @@ fn bfs(map: &FieldMap, start: Point, finish: Point) -> usize { return d; } - for neighbor in map[&p].neighbors() { + for neighbor in map[&p.map_point()].neighbors(p.level) { if !seen.contains(&neighbor) { open.push_back((neighbor, d + 1)); }