day20 shortest path to come
This commit is contained in:
19
input/day20_example1.txt
Normal file
19
input/day20_example1.txt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
A
|
||||||
|
A
|
||||||
|
#######.#########
|
||||||
|
#######.........#
|
||||||
|
#######.#######.#
|
||||||
|
#######.#######.#
|
||||||
|
#######.#######.#
|
||||||
|
##### B ###.#
|
||||||
|
BC...## C ###.#
|
||||||
|
##.## ###.#
|
||||||
|
##...DE F ###.#
|
||||||
|
##### G ###.#
|
||||||
|
#########.#####.#
|
||||||
|
DE..#######...###.#
|
||||||
|
#.#########.###.#
|
||||||
|
FG..#########.....#
|
||||||
|
###########.#####
|
||||||
|
Z
|
||||||
|
Z
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
mod tasks;
|
mod tasks;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
tasks::day19::run();
|
tasks::day20::run();
|
||||||
}
|
}
|
||||||
|
|||||||
199
src/tasks/day20.rs
Normal file
199
src/tasks/day20.rs
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::fmt::format;
|
||||||
|
|
||||||
|
pub fn run() {}
|
||||||
|
|
||||||
|
type C = i32;
|
||||||
|
|
||||||
|
#[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)]
|
||||||
|
struct Point {
|
||||||
|
x: C,
|
||||||
|
y: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Point {
|
||||||
|
fn of(x: C, y: C) -> Self {
|
||||||
|
Point { x, y }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn neighbors(self) -> Vec<Point> {
|
||||||
|
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),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Field {
|
||||||
|
point: Point,
|
||||||
|
neighbors: Vec<Point>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Field {
|
||||||
|
fn of(point: Point) -> Self {
|
||||||
|
Field {
|
||||||
|
point,
|
||||||
|
neighbors: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Maze {
|
||||||
|
map: HashMap<Point, Field>,
|
||||||
|
width: C,
|
||||||
|
height: C,
|
||||||
|
start: Point,
|
||||||
|
finish: Point,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Maze {
|
||||||
|
pub fn from(input: &String) -> Self {
|
||||||
|
let (moc, width, height) = Self::map_of_chars(input);
|
||||||
|
println!("moc size {}, w {width}, h {height}", moc.len());
|
||||||
|
|
||||||
|
let mut map = Self::create_map_of_free_spots(&moc);
|
||||||
|
Self::add_physical_neighbors(&mut map);
|
||||||
|
let labels = Self::labels(&moc, width, height);
|
||||||
|
Self::add_portals(&mut map, &labels);
|
||||||
|
let start = labels["AA"][0];
|
||||||
|
let finish = labels["ZZ"][0];
|
||||||
|
|
||||||
|
Maze { map, width, height, start, finish }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shortest_path(&self) -> usize {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_portals(map: &mut HashMap<Point, Field>, labels: &HashMap<String, Vec<Point>>) {
|
||||||
|
println!("{:?}", labels);
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn labels(moc: &HashMap<Point, char>, width: C, height: C) -> HashMap<String, Vec<Point>> {
|
||||||
|
let horizontal: Vec<(String, Point)> = (0..width - 2)
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|x| {
|
||||||
|
(0..height).into_iter().flat_map(move |y| {
|
||||||
|
println!("{x} {y} h?");
|
||||||
|
let mut triple = [
|
||||||
|
moc[&Point::of(x, y)],
|
||||||
|
moc[&Point::of(x + 1, y)],
|
||||||
|
moc[&Point::of(x + 2, y)],
|
||||||
|
];
|
||||||
|
let left = Self::label(triple).map(|label| (label, Point::of(x, y)));
|
||||||
|
triple.reverse();
|
||||||
|
let right = Self::label(triple).map(|label| (label, Point::of(x + 2, y)));
|
||||||
|
vec![left, right]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let vertical: Vec<(String, Point)> = (0..width)
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|x| {
|
||||||
|
(0..height - 2).into_iter().flat_map(move |y| {
|
||||||
|
println!("{x} {y} v?");
|
||||||
|
let mut triple = [
|
||||||
|
moc[&Point::of(x, y)],
|
||||||
|
moc[&Point::of(x, y + 1)],
|
||||||
|
moc[&Point::of(x, y + 2)],
|
||||||
|
];
|
||||||
|
let left = Self::label(triple).map(|label| (label, Point::of(x, y)));
|
||||||
|
triple.reverse();
|
||||||
|
let right = Self::label(triple).map(|label| (label, Point::of(x, y + 2)));
|
||||||
|
vec![left, right]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut result = HashMap::new();
|
||||||
|
for (s, p) in horizontal.into_iter().chain(vertical.into_iter()) {
|
||||||
|
if !result.contains_key(&s) {
|
||||||
|
result.insert(s.clone(), vec![]);
|
||||||
|
}
|
||||||
|
result.get_mut(&s).unwrap().push(p);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn label(chars: [char; 3]) -> Option<String> {
|
||||||
|
println!("{}{}{}", chars[0], chars[1], chars[2]);
|
||||||
|
if chars[0] == '.' && chars[1].is_alphabetic() && chars[2].is_alphabetic() {
|
||||||
|
let label = if chars[1] < chars[2] {
|
||||||
|
format!("{}{}", chars[1], chars[2])
|
||||||
|
} else {
|
||||||
|
format!("{}{}", chars[2], chars[1])
|
||||||
|
};
|
||||||
|
Some(label)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_physical_neighbors(map: &mut HashMap<Point, Field>) {
|
||||||
|
let points: HashSet<Point> = map.keys().map(|p| *p).collect();
|
||||||
|
map.iter_mut().for_each(|(p, f)| {
|
||||||
|
let neighbors = p
|
||||||
|
.neighbors()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|neighbor| points.contains(neighbor))
|
||||||
|
.collect();
|
||||||
|
f.neighbors = neighbors;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_map_of_free_spots(moc: &HashMap<Point, char>) -> HashMap<Point, Field> {
|
||||||
|
moc.keys()
|
||||||
|
.filter(|p| moc[p] == '.')
|
||||||
|
.map(|p| (*p, Field::of(*p)))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_of_chars(input: &String) -> (HashMap<Point, char>, C, C) {
|
||||||
|
let mut map: HashMap<Point, char> = input
|
||||||
|
.lines()
|
||||||
|
.enumerate()
|
||||||
|
.flat_map(|(y, line)| {
|
||||||
|
line.chars()
|
||||||
|
.enumerate()
|
||||||
|
.map(move |(x, c)| (Point::of(x as C, y as C), c))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let width = map.keys().map(|p| p.x).max().unwrap() + 1;
|
||||||
|
let height = map.keys().map(|p| p.y).max().unwrap() + 1;
|
||||||
|
|
||||||
|
for x in 0..width {
|
||||||
|
for y in 0..height {
|
||||||
|
if !map.contains_key(&Point::of(x, y)) {
|
||||||
|
map.insert(Point::of(x, y), ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(map, width, height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::tasks::day20::Maze;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example1() {
|
||||||
|
let input = std::fs::read_to_string("input/day20_example1.txt").unwrap();
|
||||||
|
let maze = Maze::from(&input);
|
||||||
|
assert_eq!(maze.shortest_path(), 23);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ pub mod day16;
|
|||||||
pub mod day17;
|
pub mod day17;
|
||||||
pub mod day18;
|
pub mod day18;
|
||||||
pub mod day19;
|
pub mod day19;
|
||||||
|
pub mod day20;
|
||||||
pub mod day21;
|
pub mod day21;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub mod day22;
|
pub mod day22;
|
||||||
|
|||||||
Reference in New Issue
Block a user