diff --git a/.run/run-day-16.run.xml b/.run/run-day-16.run.xml
new file mode 100644
index 0000000..74145d1
--- /dev/null
+++ b/.run/run-day-16.run.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/day16.rs b/src/day16.rs
index 9c374c5..f823466 100644
--- a/src/day16.rs
+++ b/src/day16.rs
@@ -1,4 +1,5 @@
use std::collections::HashMap;
+use crate::day16::ValveStep::{MoveTo, OpenValve};
use crate::day_solver::DaySolver;
use super::util;
@@ -59,6 +60,104 @@ impl Day16 {
res
}
+ fn should_valve_be_opened(&self, valve_idx: &usize, open_valves_mask: &u64) -> bool {
+ if Self::is_open(valve_idx, open_valves_mask) { false }
+ else if let Some(valve) = self.valves.get(*valve_idx) {
+ valve.flow_rate > 0
+ } else { false }
+ }
+
+ fn find_best_option_pt2(&self, valve_state: ValveStatePt2, cur_flow_rate: u32, cache: &mut HashMap) -> BestOptionPt2 {
+
+ if valve_state.minutes_left == 0 {
+ return BestOptionPt2 {
+ // my_step: ValveStep::None,
+ // elephant_step: ValveStep::None,
+ total_flow: 0,
+ // cur_flow: cur_flow_rate
+ }
+ }
+
+ if let Some(res) = cache.get(&valve_state) {
+ return res.to_owned();
+ }
+
+ let mut my_options = Vec::new();
+ let mut elephant_options = Vec::new();
+
+ if self.should_valve_be_opened(&valve_state.my_position, &valve_state.open_valves_mask) {
+ // One option is to open the valve at the current position
+ my_options.push(OpenValve(valve_state.my_position));
+ }
+
+ if valve_state.my_position != valve_state.elephant_position && self.should_valve_be_opened(&valve_state.elephant_position, &valve_state.open_valves_mask) {
+ elephant_options.push(OpenValve(valve_state.elephant_position));
+ }
+
+ // We try and move to an adjacent valve, see if we can be more useful there
+ let my_valve = &self.valves[valve_state.my_position];
+ for connection in my_valve.connections.iter() {
+ my_options.push(MoveTo(connection.to_owned()))
+ }
+
+ let elephant_valve = &self.valves[valve_state.elephant_position];
+ for connection in elephant_valve.connections.iter() {
+ elephant_options.push(MoveTo(connection.to_owned()))
+ }
+
+ // Now we try all combinations of my and elephants options:
+ let mut best: u32 = 0;
+ let mut my_best_step = None;
+ let mut elephant_best_step = None;
+ let next_minutes_left = valve_state.minutes_left - 1;
+ for my_option in my_options {
+
+ let mut my_next_position = valve_state.my_position;
+ let mut next_valve_mask_for_me = valve_state.open_valves_mask;
+ let mut next_flow_rate_for_me = cur_flow_rate;
+
+ match my_option {
+ MoveTo(idx) => my_next_position = idx,
+ OpenValve(idx) => {
+ next_valve_mask_for_me = Self::set_open(&idx, &next_valve_mask_for_me);
+ next_flow_rate_for_me += self.valves[idx].flow_rate
+ }
+ _ => {}
+ }
+ for elephant_option in &elephant_options {
+
+ let mut next_valve_mask = next_valve_mask_for_me;
+ let mut next_flow_rate = next_flow_rate_for_me;
+ let mut elephant_next_position = valve_state.elephant_position;
+
+ match elephant_option {
+ MoveTo(idx) => elephant_next_position = *idx,
+ OpenValve(idx) => {
+ next_valve_mask = Self::set_open(&idx, &next_valve_mask);
+ next_flow_rate += self.valves[*idx].flow_rate
+ }
+ _ => {}
+ }
+
+ let res = self.find_best_option_pt2(ValveStatePt2::new(my_next_position, elephant_next_position, next_valve_mask, next_minutes_left), next_flow_rate, cache);
+ if best == 0 || res.total_flow > best {
+ best = res.total_flow;
+ my_best_step = Some(my_option);
+ elephant_best_step = Some(elephant_option.to_owned());
+ }
+ }
+ }
+
+ let res = BestOptionPt2 {
+ // my_step: my_best_step.unwrap(),
+ // elephant_step: elephant_best_step.unwrap(),
+ // cur_flow: cur_flow_rate,
+ total_flow: best + cur_flow_rate
+ };
+ cache.insert(valve_state, res.to_owned());
+ res
+ }
+
fn find_best_option(&self, valve_state: ValveState, cur_flow_rate: u32, cache: &mut HashMap) -> Option {
if valve_state.minutes_left == 0 { return None }
@@ -70,7 +169,7 @@ impl Day16 {
let cur_valve = &self.valves.get(valve_state.my_position).unwrap();
let mut best_step_option: Option = None;
let mut best_step_result_option: Option = None;
- if Self::is_closed(&valve_state.my_position, &valve_state.open_valves_mask) && cur_valve.flow_rate > 0 {
+ if self.should_valve_be_opened(&valve_state.my_position, &valve_state.open_valves_mask) {
// One option is to open the valve at the current position
let new_open_valves_mask = Self::set_open(&valve_state.my_position, &valve_state.open_valves_mask);
best_step_result_option = self.find_best_option(ValveState::new(valve_state.my_position, new_open_valves_mask, valve_state.minutes_left - 1), cur_flow_rate + cur_valve.flow_rate, cache);
@@ -127,19 +226,23 @@ impl DaySolver for Day16 {
// }
let best = self.find_best_option(ValveState::new(self.initial_valve_idx, 0, 30), 0, &mut cache).unwrap();
- for i in 0..best.steps.len() {
- println!("Step {}", i + 1);
- match best.steps[i] {
- ValveStep::OpenValve(v) => println!("Opening valve {}", self.valve_names[v]),
- ValveStep::MoveTo(v ) => println!("Moving to valve {}", self.valve_names[v])
- }
- println!("The flow is now {}\n", best.flow_per_step[i]);
- }
+ // for i in 0..best.steps.len() {
+ // println!("Step {}", i + 1);
+ // match best.steps[i] {
+ // ValveStep::OpenValve(v) => println!("Opening valve {}", self.valve_names[v]),
+ // ValveStep::MoveTo(v ) => println!("Moving to valve {}", self.valve_names[v])
+ // }
+ // println!("The flow is now {}\n", best.flow_per_step[i]);
+ // }
best.total_flow.to_string()
}
fn solve_part2(&mut self) -> String {
- return 0.to_string();
+
+ let mut cache= HashMap::new();
+ let best = self.find_best_option_pt2(ValveStatePt2::new(self.initial_valve_idx, self.initial_valve_idx, 0, 26), 0, &mut cache);
+
+ return best.total_flow.to_string();
}
}
@@ -163,6 +266,28 @@ impl ValveState {
}
}
+#[derive(Debug, Clone, Hash, Eq, PartialEq)]
+struct ValveStatePt2 {
+ my_position: usize,
+ elephant_position: usize,
+ open_valves_mask: u64,
+ minutes_left: u32
+}
+
+#[derive(Debug, Clone, Copy)]
+struct BestOptionPt2 {
+ // my_step: ValveStep,
+ // elephant_step: ValveStep,
+ total_flow: u32,
+ // cur_flow: u32
+}
+
+impl ValveStatePt2 {
+ fn new(my_position: usize, elephant_position: usize, open_valves_mask: u64, minutes_left: u32) -> Self{
+ ValveStatePt2 { my_position, elephant_position, open_valves_mask, minutes_left }
+ }
+}
+
#[derive(Debug, Clone)]
struct BestOptionResult {
steps: Vec,
@@ -170,8 +295,9 @@ struct BestOptionResult {
total_flow: u32
}
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq)]
enum ValveStep {
OpenValve(usize),
- MoveTo(usize)
+ MoveTo(usize),
+ None
}
\ No newline at end of file