From 95e4095f32c01c6b77bd3050d1da35559ca0642c Mon Sep 17 00:00:00 2001 From: jazzpi Date: Wed, 21 Dec 2022 19:33:17 +0100 Subject: [PATCH] Day 16, part 1 solved --- src/bin/d16p1.rs | 70 +++++------------------------------------ src/day16.rs | 81 +++++++++++++++++++++++------------------------- 2 files changed, 46 insertions(+), 105 deletions(-) diff --git a/src/bin/d16p1.rs b/src/bin/d16p1.rs index 841551b..86b2adc 100644 --- a/src/bin/d16p1.rs +++ b/src/bin/d16p1.rs @@ -1,73 +1,17 @@ -use std::{ - sync::{ - atomic::{AtomicUsize, Ordering}, - Arc, Mutex, - }, - thread, +use aoc22::{ + day16, + util::{self, BnBState}, }; -use aoc22::{day16, util}; - pub fn main() { - let valves = Arc::new(day16::parse_valves(&util::parse_input())); - let dists = Arc::new(day16::calc_dists(&valves)); + let valves = day16::parse_valves(&util::parse_input()); + let dists = day16::calc_dists(&valves); let state = day16::State::new(&valves); - let possible_states = Arc::new(Mutex::new(Vec::new())); - possible_states.lock().unwrap().push(state); - - let lower_bound = Arc::new(AtomicUsize::new(0)); - - let mut handles = Vec::new(); - - for _ in 0..16 { - let s = possible_states.clone(); - let l = lower_bound.clone(); - let v = valves.clone(); - let d = dists.clone(); - handles.push(thread::spawn(move || check_states(s, l, v, d))); - } - - for handle in handles { - handle.join().unwrap(); - } + let score = util::maximize(&state, &(&valves, &dists)); println!( "Most pressure released is {}", - lower_bound.load(Ordering::Relaxed) + score.lower_bound(&(&valves, &dists)) ); } - -pub fn check_states( - possible_states: Arc>>, - lower_bound: Arc, - valves: Arc>, - dists: Arc>>, -) { - let mut i = 0; - loop { - i += 1; - let state = { possible_states.lock().unwrap().pop() }; - if state.is_none() { - break; - } - let state = state.unwrap(); - if state.finished() { - let score = state.lower_bound(); - dbg!(score); - lower_bound.fetch_max(score, Ordering::Relaxed); - } else { - let x = day16::possible_actions(&state, &valves, &dists); - // let x = state.possible_actions(&valves, &dists); - // let state_upper = state.upper_bound(&valves, &dists); - for action in x { - let action_upper = action.upper_bound(&valves, &dists); - // assert!(action_upper <= state_upper); - if action_upper > lower_bound.load(Ordering::Relaxed) { - possible_states.lock().unwrap().push(action); - } - } - } - } - dbg!(i); -} diff --git a/src/day16.rs b/src/day16.rs index 2bbae5b..a1fc649 100644 --- a/src/day16.rs +++ b/src/day16.rs @@ -8,6 +8,8 @@ use itertools::Itertools; use lazy_static::lazy_static; use regex::Regex; +use crate::util; + const TOTAL_TIME: usize = 30; #[derive(Debug, Clone)] @@ -86,6 +88,7 @@ pub struct State { pub pressure_released: usize, interesting: HashSet, + history: Vec, } impl State { @@ -102,35 +105,14 @@ impl State { time_remaining: TOTAL_TIME, pressure_released: 0, interesting, + history: vec![0], } } +} - pub fn finished(&self) -> bool { - self.time_remaining == 0 || self.interesting.is_empty() - } - - pub fn lower_bound(&self) -> usize { - self.pressure_released + self.flow_rate * self.time_remaining - } - - pub fn upper_bound(&self, valves: &Vec, dists: &Vec>) -> usize { - let mut additional_flow = 0; - for i in &self.interesting { - let i = i.clone(); - if (self.opened & (1 << i)) != 0 { - continue; - } - let dist = dists[self.location][i]; - if dist < self.time_remaining { - let flow = valves[i].flow_rate; - additional_flow += flow * (self.time_remaining - dist - 1); - } - } - - self.lower_bound() + additional_flow - } - - pub fn possible_actions(&self, valves: &Vec, dists: &Vec>) -> Vec { +type ExtraArgs<'a> = (&'a Vec, &'a Vec>); +impl util::BnBState> for State { + fn possible_actions(&self, (valves, dists): &ExtraArgs) -> Vec { assert!(!self.finished()); let mut result = Vec::new(); @@ -158,11 +140,42 @@ impl State { moved.location = i; moved.pressure_released += moved.flow_rate * dist; moved.time_remaining -= dist; + moved.history.push(i); result.push(moved); } + let mut do_nothing = self.clone(); + do_nothing.pressure_released += do_nothing.flow_rate * self.time_remaining; + do_nothing.time_remaining = 0; + result.push(do_nothing); + result } + + fn finished(&self) -> bool { + self.time_remaining == 0 || self.interesting.is_empty() + } + + fn lower_bound(&self, _: &ExtraArgs) -> usize { + self.pressure_released + self.flow_rate * self.time_remaining + } + + fn upper_bound(&self, (valves, dists): &ExtraArgs) -> usize { + let mut additional_flow = 0; + for i in &self.interesting { + let i = i.clone(); + if (self.opened & (1 << i)) != 0 { + continue; + } + let dist = dists[self.location][i]; + if dist < self.time_remaining { + let flow = valves[i].flow_rate; + additional_flow += flow * (self.time_remaining - dist - 1); + } + } + + self.lower_bound(&(valves, dists)) + additional_flow + } } impl Hash for State { @@ -184,19 +197,3 @@ impl PartialEq for State { } impl Eq for State {} - -pub fn possible_actions(state: &State, valves: &Vec, dists: &Vec>) -> Vec { - lazy_static! { - static ref CACHE: Mutex>> = Mutex::new(HashMap::new()); - } - - let actions = { CACHE.lock().unwrap().get(state).cloned() }; - if let Some(actions) = actions { - // assert_eq!(actions, state.possible_actions(valves, dists)); - actions.clone() - } else { - let mut cache = CACHE.lock().unwrap(); - cache.insert(state.clone(), state.possible_actions(valves, dists)); - cache[state].clone() - } -}