day20 refactored for part 2
This commit is contained in:
@@ -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));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user