]> aoc.elinar.fr Git - aoc_2024/commitdiff
Day06 - part 2
authoralex <>
Fri, 6 Dec 2024 10:28:26 +0000 (11:28 +0100)
committeralex <>
Fri, 6 Dec 2024 10:28:26 +0000 (11:28 +0100)
src/day06.rs

index 20566335b3b09be3a31346470210e516179945ca..f6431f6f40cff5a4e8f49186b367e51ac162e701 100644 (file)
@@ -1,7 +1,8 @@
 use std::error::Error;
 use std::path::Path;
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 
+#[derive(Clone)]
 struct Puzzle {
     map: HashMap<(isize, isize), char>,
     start: (isize, isize),
@@ -41,7 +42,7 @@ impl Puzzle {
         let mut pos: (isize, isize) = self.start;
         let mut dir: (isize, isize) = (-1, 0);
         while self.map.contains_key(&pos) {
-            let mut c = self.map.get_mut(&pos).unwrap();
+            let c = self.map.get_mut(&pos).unwrap();
             if "^.".contains(*c) {
                 *c = 'X';
             }
@@ -52,6 +53,39 @@ impl Puzzle {
             pos = (pos.0 + dir.0, pos.1 + dir.1);
         }
     }
+
+    fn is_guard_loop(self: &Self) -> bool {
+        let mut turn_right: HashMap<(isize, isize), (isize, isize)> = HashMap::new();
+        turn_right.insert((-1,0), (0,1));
+        turn_right.insert((0,1), (1,0));
+        turn_right.insert((1,0), (0,-1));
+        turn_right.insert((0,-1), (-1,0));
+
+        // store the visited position (r,c) with a set of associated direction (dr,dc)
+        let mut visited: HashMap<(isize, isize), HashSet<(isize, isize)>> = HashMap::new();
+
+        let mut pos: (isize, isize) = self.start;
+        let mut dir: (isize, isize) = (-1, 0);
+        while self.map.contains_key(&pos) {
+            let c = self.map.get(&pos).unwrap();
+            if "#O".contains(*c) {
+                pos = (pos.0 - dir.0, pos.1 - dir.1);
+                dir = *turn_right.get(&dir).unwrap();
+            }
+            visited.entry(pos)
+                .and_modify(|dir_set| { dir_set.insert(dir); })
+                .or_insert({
+                    let mut s = HashSet::new();
+                    s.insert(dir);
+                    s
+                });
+            pos = (pos.0 + dir.0, pos.1 + dir.1);
+            if visited.contains_key(&pos) && visited.get(&pos).unwrap().contains(&dir) {
+                return true;
+            }
+        }
+        false
+    }
 }
 
 pub fn run(input: &str) -> Result<(), Box<dyn Error>> {
@@ -86,7 +120,22 @@ fn run_part1(input: &str) -> Result<u32, Box<dyn Error>> {
 fn run_part2(input: &str) -> Result<u32, Box<dyn Error>> {
     println!("Running {} - part 2", get_day());
 
-    Ok(0)
+    let mut puzzle = Puzzle::new(input);
+
+    puzzle.guard_path();
+
+    let res: u32 = puzzle.map.clone().into_keys()
+        .filter(|k| *puzzle.map.get(k).unwrap() == 'X' && *k != puzzle.start)
+        .map(|k| {
+            let mut p = puzzle.clone();
+            let c = p.map.get_mut(&k).unwrap();
+            *c = 'O';
+            p.is_guard_loop()
+        })
+        .filter(|matches| *matches)
+        .count() as u32;
+
+    Ok(res)
 }
 
 #[cfg(test)]
@@ -112,6 +161,6 @@ mod tests {
 
     #[test]
     fn test_part2() {
-        assert_eq!(0, run_part2(TEXT_INPUT).unwrap());
+        assert_eq!(6, run_part2(TEXT_INPUT).unwrap());
     }
 }