2022 day 16
This commit is contained in:
parent
a581dd4f44
commit
5412d52f9b
|
@ -2,7 +2,6 @@ use std::cmp::Ordering;
|
||||||
use std::collections::{BinaryHeap, HashMap, HashSet};
|
use std::collections::{BinaryHeap, HashMap, HashSet};
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
use rayon::prelude::*;
|
|
||||||
|
|
||||||
pub fn run() -> () {
|
pub fn run() -> () {
|
||||||
let lines = utils::read_lines(utils::Source::Day(16));
|
let lines = utils::read_lines(utils::Source::Day(16));
|
||||||
|
@ -20,6 +19,10 @@ struct Valve {
|
||||||
next: Vec<usize>,
|
next: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start, valves, distances
|
||||||
|
type Data = (usize, Vec<Valve>, HashMap<(usize, usize), u32>);
|
||||||
|
|
||||||
|
|
||||||
#[derive(Eq, PartialEq)]
|
#[derive(Eq, PartialEq)]
|
||||||
struct State {
|
struct State {
|
||||||
name: usize,
|
name: usize,
|
||||||
|
@ -152,103 +155,86 @@ fn move_to_open(
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_max_for_start(valves: &[Valve], start: usize, limit: u32) -> u32 {
|
fn solve1((start, valves, distances): &Data) -> u32 {
|
||||||
move_to_open(&valves, &find_distances(&valves), MoveState {
|
move_to_open(&valves, distances, MoveState {
|
||||||
current: start,
|
current: *start,
|
||||||
time_left: limit + 1,
|
time_left: 31,
|
||||||
closed: &closed_valves(valves)
|
closed: &closed_valves(valves)
|
||||||
}, &mut HashMap::new())
|
}, &mut HashMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn solve1((map, data): &(HashMap<&str, usize>, Vec<Valve>)) -> u32 {
|
fn bitmap_to_set(valves: &[Valve], bitmap: u16) -> HashSet<usize> {
|
||||||
let start = *map.get("AA").unwrap();
|
let mut set = HashSet::new();
|
||||||
find_max_for_start(data, start, 30)
|
for valve in valves {
|
||||||
}
|
if bitmap & (1 << valve.name) != 0 {
|
||||||
|
set.insert(valve.name);
|
||||||
// Pray this doesn't blow the stack
|
}
|
||||||
struct ParallelMoveState {
|
|
||||||
p_curr: usize,
|
|
||||||
p_next: usize,
|
|
||||||
p_progress: u32,
|
|
||||||
e_curr: usize,
|
|
||||||
e_next: usize,
|
|
||||||
e_progress: u32,
|
|
||||||
time_left: u32,
|
|
||||||
released: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parallel_to_open(
|
|
||||||
valves: &[Valve],
|
|
||||||
distances: &HashMap<(usize, usize), u32>,
|
|
||||||
closed: &HashSet<usize>,
|
|
||||||
opened: &HashSet<usize>,
|
|
||||||
state: ParallelMoveState,
|
|
||||||
) -> u32 {
|
|
||||||
let p_distance_left = *distances.get(&(state.p_curr, state.p_next)).unwrap() - state.p_progress;
|
|
||||||
let e_distance_left = *distances.get(&(state.e_curr, state.e_next)).unwrap() - state.e_progress;
|
|
||||||
let distance = state.time_left.min(p_distance_left).min(e_distance_left);
|
|
||||||
let released = state.released + distance * release_pressure(valves, opened);
|
|
||||||
if distance == state.time_left { return released };
|
|
||||||
|
|
||||||
// opening
|
|
||||||
let released = released + release_pressure(valves, opened);
|
|
||||||
let (closed, opened) = {
|
|
||||||
let mut closed = closed.clone();
|
|
||||||
let mut opened = opened.clone();
|
|
||||||
if distance == p_distance_left { closed.remove(&state.p_next); opened.insert(state.p_next); };
|
|
||||||
if distance == e_distance_left { closed.remove(&state.e_next); opened.insert(state.e_next); };
|
|
||||||
(closed, opened)
|
|
||||||
};
|
|
||||||
let time_left = state.time_left - distance - 1;
|
|
||||||
|
|
||||||
match (distance == p_distance_left, distance == e_distance_left) {
|
|
||||||
(true, true) => closed.iter()
|
|
||||||
.flat_map(|p_next| closed.iter()
|
|
||||||
.filter(move |&e_next| e_next != p_next)
|
|
||||||
.map(|e_next| parallel_to_open(valves, distances, &closed, &opened, ParallelMoveState {
|
|
||||||
p_curr: state.p_next, p_next: *p_next, p_progress: 0,
|
|
||||||
e_curr: state.e_next, e_next: *e_next, e_progress: 0,
|
|
||||||
time_left, released,
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
.max()
|
|
||||||
.unwrap_or_else(|| released + release_pressure(valves, &opened) * time_left),
|
|
||||||
(true, false) => closed.iter()
|
|
||||||
.map(|&next| parallel_to_open(valves, distances, &closed, &opened, ParallelMoveState {
|
|
||||||
p_curr: state.p_next, p_next: next, p_progress: 0,
|
|
||||||
e_curr: state.e_curr, e_next: state.e_next, e_progress: state.e_progress + distance + 1,
|
|
||||||
time_left, released,
|
|
||||||
}))
|
|
||||||
.max()
|
|
||||||
.unwrap_or_else(|| released + release_pressure(valves, &opened) * time_left),
|
|
||||||
(false, true) => closed.iter()
|
|
||||||
.map(|&next| parallel_to_open(valves, distances, &closed, &opened, ParallelMoveState {
|
|
||||||
p_curr: state.p_curr, p_next: state.p_next, p_progress: state.p_progress + distance + 1,
|
|
||||||
e_curr: state.e_next, e_next: next, e_progress: 0,
|
|
||||||
time_left, released,
|
|
||||||
}))
|
|
||||||
.max()
|
|
||||||
.unwrap_or_else(|| released + release_pressure(valves, &opened) * time_left),
|
|
||||||
_ => unreachable!()
|
|
||||||
}
|
}
|
||||||
|
set
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parallel_max_for_start(valves: &[Valve], start: usize, limit: u32) -> u32 {
|
fn solve2((start, valves, distances): &Data) -> u32 {
|
||||||
let start_state = ParallelMoveState {
|
let mut results: HashMap<u16, u32> = HashMap::new();
|
||||||
p_curr: start, p_next: start, p_progress: 0,
|
let mut cache = HashMap::new();
|
||||||
e_curr: start, e_next: start, e_progress: 0,
|
let all_set = 0b01111111_11111111_u16;
|
||||||
time_left: limit + 1, released: 0
|
|
||||||
};
|
for bitmap in 1..u16::MAX {
|
||||||
parallel_to_open(valves, &find_distances(&valves), &closed_valves(valves), &HashSet::new(), start_state)
|
if bitmap.count_ones() < 4 { continue }
|
||||||
|
let closed = bitmap_to_set(valves, bitmap);
|
||||||
|
|
||||||
|
let result = move_to_open(&valves, &distances, MoveState {
|
||||||
|
current: *start,
|
||||||
|
time_left: 27,
|
||||||
|
closed: &closed,
|
||||||
|
}, &mut cache);
|
||||||
|
|
||||||
|
results.insert(bitmap, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
results.keys()
|
||||||
|
.flat_map(|&key_p| results.keys()
|
||||||
|
.filter(move |&key_e| key_p ^ key_e == all_set)
|
||||||
|
.map(move |&key_e| (key_p, key_e))
|
||||||
|
)
|
||||||
|
.map(|(key_p, key_e)| results[&key_p] + results[&key_e])
|
||||||
|
.max()
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn solve2((map, data): &(HashMap<&str, usize>, Vec<Valve>)) -> u32 {
|
|
||||||
|
fn compress(data: &[Valve], preserve: usize) -> (HashMap<usize, usize>, Vec<Valve>) {
|
||||||
|
let (translation, filtered) = data.iter()
|
||||||
|
.filter(|valve| valve.rate > 0 || valve.name == preserve )
|
||||||
|
.enumerate()
|
||||||
|
.fold((HashMap::new(), vec![]), |(mut map, mut valves), (new_idx, valve)| {
|
||||||
|
map.insert(valve.name, new_idx);
|
||||||
|
valves.push(valve);
|
||||||
|
(map, valves)
|
||||||
|
});
|
||||||
|
let valves = filtered.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(name, old)| Valve {
|
||||||
|
name, rate: old.rate, next: vec![],
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
(translation, valves)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn translate(map: HashMap<&str, usize>, data: Vec<Valve>) -> (usize, Vec<Valve>, HashMap<(usize, usize), u32>) {
|
||||||
let start = *map.get("AA").unwrap();
|
let start = *map.get("AA").unwrap();
|
||||||
parallel_max_for_start(data, start, 26)
|
let distances = find_distances(&data);
|
||||||
|
let (tl, valves) = compress(&data, start);
|
||||||
|
let distances = distances.into_iter()
|
||||||
|
.filter_map(|((a, b), dist)| match tl.contains_key(&a) && tl.contains_key(&b) {
|
||||||
|
true => Some(((tl[&a], tl[&b]), dist)),
|
||||||
|
false => None,
|
||||||
|
})
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
|
(tl[&start], valves, distances)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_data<T: AsRef<str>>(data: &[T]) -> (usize, Vec<Valve>, HashMap<(usize, usize), u32>) {
|
||||||
fn parse_data<T: AsRef<str>>(data: &[T]) -> (HashMap<&str, usize>, Vec<Valve>) {
|
|
||||||
let valves = data.iter()
|
let valves = data.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(index, line)| {
|
.map(|(index, line)| {
|
||||||
|
@ -272,7 +258,8 @@ fn parse_data<T: AsRef<str>>(data: &[T]) -> (HashMap<&str, usize>, Vec<Valve>) {
|
||||||
name, rate, next: next.iter().map(|&next| *map.get(next).unwrap()).collect(),
|
name, rate, next: next.iter().map(|&next| *map.get(next).unwrap()).collect(),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
(map, valves)
|
|
||||||
|
translate(map, valves)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue