Day 16, part 1 solved
This commit is contained in:
parent
0279edb249
commit
95e4095f32
@ -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<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 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<usize>,
|
||||
history: Vec<usize>,
|
||||
}
|
||||
|
||||
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<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> {
|
||||
type ExtraArgs<'a> = (&'a Vec<Valve>, &'a Vec<Vec<usize>>);
|
||||
impl util::BnBState<ExtraArgs<'_>> for State {
|
||||
fn possible_actions(&self, (valves, dists): &ExtraArgs) -> Vec<State> {
|
||||
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<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