Jake Fenton 1 rok temu
rodzic
commit
d6c0cf1cb2
1 zmienionych plików z 40 dodań i 37 usunięć
  1. 40 37
      src/bin/12.rs

+ 40 - 37
src/bin/12.rs

@@ -1,5 +1,5 @@
 #![feature(let_chains)]
-use std::{collections::{HashSet, HashMap}, thread::current};
+use std::{collections::{HashSet, HashMap}, thread::current, borrow::Borrow};
 
 #[derive(Clone, Hash, Eq, PartialEq)]
 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(&current_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(&current_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(&current_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(&current_pos) {
-        map.best_steps.insert(current_pos, min);
-    } else {
-        if min < map.best_steps[&current_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> {
     let _map: Vec<Vec<char>> = input.lines().map(|line| line.chars().collect()).collect();
     let mut end_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 (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' {
                 end_coord = Point {y: r_idx, x: col_idx};
             } 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 {
         best_steps: HashMap::new(),
         map: _map,
         start: start_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> {