day20 refactored for part 2

This commit is contained in:
2022-10-02 14:16:50 +02:00
parent 4002297ede
commit 922f2a483c

View File

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