day20 shortest path to come

This commit is contained in:
2022-10-02 11:28:33 +02:00
parent eeda13a0d6
commit 358e185501
4 changed files with 220 additions and 1 deletions

19
input/day20_example1.txt Normal file
View File

@@ -0,0 +1,19 @@
A
A
#######.#########
#######.........#
#######.#######.#
#######.#######.#
#######.#######.#
##### B ###.#
BC...## C ###.#
##.## ###.#
##...DE F ###.#
##### G ###.#
#########.#####.#
DE..#######...###.#
#.#########.###.#
FG..#########.....#
###########.#####
Z
Z

View File

@@ -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
View 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);
}
}

View File

@@ -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;