Day 16, part 1 solved

This commit is contained in:
jazzpi 2022-12-21 19:33:17 +01:00
parent 0279edb249
commit 95e4095f32
2 changed files with 46 additions and 105 deletions

View File

@ -1,73 +1,17 @@
use std::{ use aoc22::{
sync::{ day16,
atomic::{AtomicUsize, Ordering}, util::{self, BnBState},
Arc, Mutex,
},
thread,
}; };
use aoc22::{day16, util};
pub fn main() { pub fn main() {
let valves = Arc::new(day16::parse_valves(&util::parse_input())); let valves = day16::parse_valves(&util::parse_input());
let dists = Arc::new(day16::calc_dists(&valves)); let dists = day16::calc_dists(&valves);
let state = day16::State::new(&valves); let state = day16::State::new(&valves);
let possible_states = Arc::new(Mutex::new(Vec::new())); let score = util::maximize(&state, &(&valves, &dists));
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();
}
println!( println!(
"Most pressure released is {}", "Most pressure released is {}",
lower_bound.load(Ordering::Relaxed) score.lower_bound(&(&valves, &dists))
); );
} }
pub fn check_states(
possible_states: Arc<Mutex<Vec<day16::State>>>,
lower_bound: Arc<AtomicUsize>,
valves: Arc<Vec<day16::Valve>>,
dists: Arc<Vec<Vec<usize>>>,
) {
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);
}

View File

@ -8,6 +8,8 @@ use itertools::Itertools;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use regex::Regex; use regex::Regex;
use crate::util;
const TOTAL_TIME: usize = 30; const TOTAL_TIME: usize = 30;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -86,6 +88,7 @@ pub struct State {
pub pressure_released: usize, pub pressure_released: usize,
interesting: HashSet<usize>, interesting: HashSet<usize>,
history: Vec<usize>,
} }
impl State { impl State {
@ -102,35 +105,14 @@ impl State {
time_remaining: TOTAL_TIME, time_remaining: TOTAL_TIME,
pressure_released: 0, pressure_released: 0,
interesting, interesting,
history: vec![0],
} }
} }
}
pub fn finished(&self) -> bool { type ExtraArgs<'a> = (&'a Vec<Valve>, &'a Vec<Vec<usize>>);
self.time_remaining == 0 || self.interesting.is_empty() impl util::BnBState<ExtraArgs<'_>> for State {
} fn possible_actions(&self, (valves, dists): &ExtraArgs) -> Vec<State> {
pub fn lower_bound(&self) -> usize {
self.pressure_released + self.flow_rate * self.time_remaining
}
pub fn upper_bound(&self, valves: &Vec<Valve>, dists: &Vec<Vec<usize>>) -> 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<Valve>, dists: &Vec<Vec<usize>>) -> Vec<State> {
assert!(!self.finished()); assert!(!self.finished());
let mut result = Vec::new(); let mut result = Vec::new();
@ -158,11 +140,42 @@ impl State {
moved.location = i; moved.location = i;
moved.pressure_released += moved.flow_rate * dist; moved.pressure_released += moved.flow_rate * dist;
moved.time_remaining -= dist; moved.time_remaining -= dist;
moved.history.push(i);
result.push(moved); 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 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 { impl Hash for State {
@ -184,19 +197,3 @@ impl PartialEq for State {
} }
impl Eq for State {} impl Eq for State {}
pub fn possible_actions(state: &State, valves: &Vec<Valve>, dists: &Vec<Vec<usize>>) -> Vec<State> {
lazy_static! {
static ref CACHE: Mutex<HashMap<State, Vec<State>>> = 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()
}
}