Day 16, part 1 solved
This commit is contained in:
parent
0279edb249
commit
95e4095f32
@ -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);
|
|
||||||
}
|
|
||||||
|
81
src/day16.rs
81
src/day16.rs
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user