|
@@ -1,5 +1,5 @@
|
|
#![feature(let_chains)]
|
|
#![feature(let_chains)]
|
|
-use std::{collections::{HashSet, HashMap}, thread::current};
|
|
|
|
|
|
+use std::{collections::{HashSet, HashMap}, thread::current, borrow::Borrow};
|
|
|
|
|
|
#[derive(Clone, Hash, Eq, PartialEq)]
|
|
#[derive(Clone, Hash, Eq, PartialEq)]
|
|
pub struct Point {
|
|
pub struct Point {
|
|
@@ -49,58 +49,59 @@ impl HeightMap {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-fn search_map(map: &mut HeightMap, mut breadcrumbs: HashSet<Point>, current_pos: Point, best: usize) -> usize {
|
|
|
|
- if breadcrumbs.len() + map.best_possible_dist(¤t_pos) >= best {
|
|
|
|
- return usize::MAX;
|
|
|
|
- }
|
|
|
|
- breadcrumbs.insert(current_pos.clone());
|
|
|
|
- if current_pos == map.end {
|
|
|
|
- println!("We've arrived!");
|
|
|
|
- return breadcrumbs.len();
|
|
|
|
|
|
+
|
|
|
|
+// if !(neighbor_val == HeightMap::acceptable_next(&curr_val) || (neighbor_val <= curr_val) && (neighbor_val != 'E' && neighbor_val != 'S')) {
|
|
|
|
+// continue;
|
|
|
|
+
|
|
|
|
+fn neighbor_has_acceptbale_value(our_value: char, neighbor_value: char, acceptable_value: char) -> bool {
|
|
|
|
+ if neighbor_value == acceptable_value {
|
|
|
|
+ return true
|
|
}
|
|
}
|
|
|
|
+ if neighbor_value != 'S' && neighbor_value != 'E' && neighbor_value <= our_value {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ false
|
|
|
|
+}
|
|
|
|
|
|
- let mut min = best;
|
|
|
|
|
|
+fn dijkstra(map: HeightMap, unvisited: &mut HashSet<Point>, distances: &mut HashMap<Point, usize>, end: &Point) {
|
|
|
|
+ while unvisited.contains(end) {
|
|
|
|
+ let curr_point = unvisited.iter().reduce(|curr, new| if distances[curr] < distances[new] { curr} else {new}).unwrap().clone();
|
|
|
|
+ // let (_curr_point, _curr_dist) = distances.iter().reduce(|old, new| if new.1 < old.1 { new } else { old }).unwrap();
|
|
|
|
+ let curr_dist = distances[&curr_point];
|
|
|
|
+ // println!("checking {}, {}", curr_point.x, curr_point.y);
|
|
|
|
|
|
- for neighbor in map.get_neighbors(¤t_pos) {
|
|
|
|
- if breadcrumbs.contains(&neighbor) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- let neighbor_val = map.map[neighbor.y][neighbor.x];
|
|
|
|
- let curr_val = map.map[current_pos.y][current_pos.x];
|
|
|
|
- if !(neighbor_val == HeightMap::acceptable_next(&curr_val) || (neighbor_val <= curr_val) && (neighbor_val != 'E' && neighbor_val != 'S')) {
|
|
|
|
- continue;
|
|
|
|
|
|
+ if curr_point == *end {
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
- if map.best_steps.contains_key(&neighbor) && map.best_steps[&neighbor] <= breadcrumbs.len() + map.best_possible_dist(¤t_pos) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- let new = search_map(map, breadcrumbs.clone(), neighbor, min);
|
|
|
|
- if new < min {
|
|
|
|
- min = new;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ let our_value = map.map[curr_point.y][curr_point.x];
|
|
|
|
+ let allowed_neighbor_value = HeightMap::acceptable_next(&our_value);
|
|
|
|
+ let neighbors: Vec<Point> = map.get_neighbors(&curr_point).into_iter().filter(
|
|
|
|
+ |neighbor| neighbor_has_acceptbale_value(our_value, map.map[neighbor.y][neighbor.x], allowed_neighbor_value)
|
|
|
|
+ ).collect();
|
|
|
|
|
|
- if !map.best_steps.contains_key(¤t_pos) {
|
|
|
|
- map.best_steps.insert(current_pos, min);
|
|
|
|
- } else {
|
|
|
|
- if min < map.best_steps[¤t_pos] {
|
|
|
|
- map.best_steps.insert(current_pos, min);
|
|
|
|
|
|
+ for neighbor in neighbors {
|
|
|
|
+ if distances[&neighbor] > curr_dist + 1 {
|
|
|
|
+ distances.insert(neighbor, curr_dist + 1);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
|
|
- min
|
|
|
|
|
|
+ unvisited.remove(&curr_point);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
pub fn part_one(input: &str) -> Option<usize> {
|
|
pub fn part_one(input: &str) -> Option<usize> {
|
|
let _map: Vec<Vec<char>> = input.lines().map(|line| line.chars().collect()).collect();
|
|
let _map: Vec<Vec<char>> = input.lines().map(|line| line.chars().collect()).collect();
|
|
let mut end_coord = Point { x: 0, y: 0 };
|
|
let mut end_coord = Point { x: 0, y: 0 };
|
|
let mut start_coord = Point { x: 0, y: 0 };
|
|
let mut start_coord = Point { x: 0, y: 0 };
|
|
|
|
+ let mut to_visit: HashSet<Point> = HashSet::new();
|
|
|
|
+ let mut distances: HashMap<Point, usize> = HashMap::new();
|
|
|
|
|
|
|
|
|
|
for (r_idx, row) in _map.iter().enumerate() {
|
|
for (r_idx, row) in _map.iter().enumerate() {
|
|
for (col_idx, c) in row.iter().enumerate() {
|
|
for (col_idx, c) in row.iter().enumerate() {
|
|
|
|
+ to_visit.insert(Point {x: col_idx, y: r_idx});
|
|
|
|
+ distances.insert(Point {x: col_idx, y: r_idx}, usize::MAX);
|
|
if *c == 'E' {
|
|
if *c == 'E' {
|
|
end_coord = Point {y: r_idx, x: col_idx};
|
|
end_coord = Point {y: r_idx, x: col_idx};
|
|
} else if *c == 'S' {
|
|
} else if *c == 'S' {
|
|
@@ -109,15 +110,17 @@ pub fn part_one(input: &str) -> Option<usize> {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ distances.insert(start_coord.clone(), 0);
|
|
|
|
+
|
|
let mut map = HeightMap {
|
|
let mut map = HeightMap {
|
|
best_steps: HashMap::new(),
|
|
best_steps: HashMap::new(),
|
|
map: _map,
|
|
map: _map,
|
|
start: start_coord.clone(),
|
|
start: start_coord.clone(),
|
|
end: end_coord.clone()
|
|
end: end_coord.clone()
|
|
};
|
|
};
|
|
|
|
+ dijkstra(map, &mut to_visit, &mut distances, &end_coord);
|
|
|
|
+ return Some(distances[&end_coord]);
|
|
|
|
|
|
- let best = map.map.len() * map.map[0].len();
|
|
|
|
- Some(search_map(&mut map, HashSet::from_iter([start_coord.clone()].into_iter()), start_coord, best) - 1)
|
|
|
|
}
|
|
}
|
|
|
|
|
|
pub fn part_two(input: &str) -> Option<u32> {
|
|
pub fn part_two(input: &str) -> Option<u32> {
|