summaryrefslogtreecommitdiff
path: root/src/bin/day12.rs
diff options
context:
space:
mode:
authorReiner Herrmann <reiner@reiner-h.de>2022-12-12 15:47:09 +0100
committerReiner Herrmann <reiner@reiner-h.de>2022-12-12 15:47:09 +0100
commitdecb41c8226d50121dd2febd0c669b4e208eb514 (patch)
treea14a21b4489384b54b893a5f14b598b3912c7b7e /src/bin/day12.rs
parent6a04e03f69b524d8ac053d34ffc116102a520d5f (diff)
day12
Diffstat (limited to 'src/bin/day12.rs')
-rw-r--r--src/bin/day12.rs102
1 files changed, 102 insertions, 0 deletions
diff --git a/src/bin/day12.rs b/src/bin/day12.rs
new file mode 100644
index 0000000..85bbe0d
--- /dev/null
+++ b/src/bin/day12.rs
@@ -0,0 +1,102 @@
+use std::collections::HashMap;
+
+static DAY: u8 = 12;
+
+fn main() {
+ let input = advent::read_lines(DAY);
+ println!("{DAY}a: {}", steps_required_start(&input));
+ println!("{DAY}b: {}", steps_required_any_a(&input));
+}
+
+#[derive(PartialEq,Eq,Hash,Clone,Copy)]
+struct Position {
+ x: isize,
+ y: isize,
+}
+
+fn parse_map(input: &[String]) -> (HashMap<Position,u32>, Position, Position) {
+ let mut map = HashMap::new();
+ let mut start = Position { x: 0, y: 0};
+ let mut end = Position { x: 0, y: 0};
+
+ for (y, line) in input.iter().enumerate() {
+ for (x, c) in line.chars().enumerate() {
+ let pos = Position { x: x as isize, y: y as isize };
+ let elevation = match c {
+ 'S' => { start = pos; 'a' }
+ 'E' => { end = pos; 'z' }
+ e => e,
+ };
+ let elevation = elevation.to_digit(36).unwrap();
+ map.insert(pos, elevation);
+ }
+ }
+
+ (map, start, end)
+}
+
+fn steps_required(map: &HashMap<Position,u32>, end: &Position, found_position: impl Fn(&Position, u32) -> bool) -> u32 {
+ let mut distances = HashMap::new();
+ distances.insert(*end, 0);
+
+ loop {
+ let positions = distances.keys().cloned().collect::<Vec<_>>();
+ for pos in positions {
+ let next_dist = distances[&pos] + 1;
+ let neighbors = [
+ Position { x: pos.x + 1, y: pos.y },
+ Position { x: pos.x, y: pos.y + 1 },
+ Position { x: pos.x - 1, y: pos.y },
+ Position { x: pos.x, y: pos.y - 1 },
+ ];
+ for neighbor in neighbors {
+ if distances.contains_key(&neighbor) || !map.contains_key(&neighbor){
+ continue;
+ }
+ if map[&pos] <= map[&neighbor] || map[&pos] == map[&neighbor] + 1 {
+ distances.insert(neighbor, next_dist);
+ if found_position(&neighbor, map[&neighbor]) {
+ return next_dist;
+ }
+ }
+ }
+ }
+ }
+}
+
+fn steps_required_start(input: &[String]) -> u32 {
+ let (map, start, end) = parse_map(input);
+ let found_position = |pos: &Position, _ele: u32| -> bool {
+ /* looking for the starting position */
+ *pos == start
+ };
+ steps_required(&map, &end, found_position)
+}
+
+fn steps_required_any_a(input: &[String]) -> u32 {
+ let (map, _, end) = parse_map(input);
+ let found_position = |_pos: &Position, ele: u32| -> bool {
+ /* looking for any location with elevation 'a' */
+ ele == 'a'.to_digit(36).unwrap()
+ };
+ steps_required(&map, &end, found_position)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test() {
+ let input = [
+ "Sabqponm",
+ "abcryxxl",
+ "accszExk",
+ "acctuvwj",
+ "abdefghi",
+ ].iter().map(|&x| String::from(x)).collect::<Vec<_>>();
+
+ assert_eq!(steps_required_start(&input), 31);
+ assert_eq!(steps_required_any_a(&input), 29);
+ }
+}