use super::intcode;\r
use std::iter::FromIterator;\r
use std::collections::HashMap;\r
+use std::collections::HashSet;\r
\r
#[derive(Debug, Eq, PartialEq, Copy, Clone)]\r
enum LocationState {\r
DeadEnd,\r
}\r
\r
-struct DroidTrackingSystem {\r
+#[derive(Clone)]\r
+pub struct DroidTrackingSystem {\r
board: HashMap<(i32, i32), LocationState>,\r
current_path: Vec<(i32, i32)>,\r
- oxygen_found: bool\r
+ oxygen_location: (i32, i32),\r
+ steps_to_oxygen: i32,\r
+ all_locations_explored: bool,\r
}\r
\r
impl DroidTrackingSystem {\r
DroidTrackingSystem {\r
board: HashMap::from_iter(vec![((0, 0), LocationState::Visited)].into_iter()),\r
current_path: vec![(0, 0)],\r
- oxygen_found: false\r
+ oxygen_location: (0, 0),\r
+ steps_to_oxygen: 0,\r
+ all_locations_explored: false\r
}\r
}\r
\r
}\r
}\r
\r
- panic!("Droid stuck");\r
+ self.all_locations_explored = true;\r
+ 1\r
}\r
\r
// 0: droid hit a wall, 1: droid moved one step, 2: droid moved one step and has found the oxygen system.\r
fn reply_from_droid(&mut self, status: i64) {\r
- match status {\r
- 0 => {\r
- self.set_state(self.current_position(), LocationState::Wall);\r
- self.current_path.pop();\r
+ if status == 0 {\r
+ self.set_state(self.current_position(), LocationState::Wall);\r
+ self.current_path.pop();\r
+ } else if status == 1 || status == 2 {\r
+ self.set_state(self.current_position(), LocationState::Visited);\r
+\r
+ // We need to explore all positions even if we find the oxygen to compute the time (see 'time_to_flood_the_area') in part 2.\r
+ if status == 2 {\r
+ self.steps_to_oxygen = self.current_path.len() as i32 - 1;\r
+ self.oxygen_location = self.current_position();\r
}\r
- 1 => self.set_state(self.current_position(), LocationState::Visited),\r
- 2 => self.oxygen_found = true,\r
- _ => panic!("Unkown droid status: {}", status)\r
+ } else {\r
+ panic!("Unkown droid status: {}", status)\r
}\r
}\r
}\r
}\r
\r
fn halt(&self) -> bool {\r
- self.oxygen_found\r
+ self.all_locations_explored\r
}\r
}\r
\r
-pub fn nb_of_movement_to_reach_oxygen(code: &[i64]) -> i32 {\r
+pub fn nb_of_movement_to_reach_oxygen(code: &[i64]) -> (i32, DroidTrackingSystem) {\r
let mut dts = DroidTrackingSystem::new();\r
intcode::execute_op_code_with_custom_io(code, &mut dts);\r
- dts.current_path.len() as i32 - 1\r
+ (dts.steps_to_oxygen, dts)\r
+}\r
+\r
+pub fn time_to_flood_the_area(dts: &DroidTrackingSystem) -> i32 {\r
+ let mut dts = dts.clone(); // To be mutable.\r
+ dts.current_path = vec![dts.oxygen_location];\r
+ let mut visited: HashSet<(i32, i32)> = HashSet::from_iter(dts.current_path.iter().copied());\r
+ let mut max_length = 0;\r
+\r
+ 'main: while !dts.current_path.is_empty() {\r
+ for (_, pos) in dts.positions_around() {\r
+ if dts.get_state(pos) != LocationState::Wall && !visited.contains(&pos) {\r
+ dts.current_path.push(pos);\r
+ visited.insert(pos);\r
+ max_length = max_length.max(dts.current_path.len() as i32);\r
+ continue 'main;\r
+ }\r
+ }\r
+\r
+ dts.current_path.pop();\r
+ }\r
+\r
+ max_length - 1\r
}
\ No newline at end of file