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),
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';
}
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>> {
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)]
#[test]
fn test_part2() {
- assert_eq!(0, run_part2(TEXT_INPUT).unwrap());
+ assert_eq!(6, run_part2(TEXT_INPUT).unwrap());
}
}