mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Non-functional implementation of 2022 day 16 part 1
This commit is contained in:
50
2022/inputs/16.txt
Normal file
50
2022/inputs/16.txt
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
Valve QJ has flow rate=11; tunnels lead to valves HB, GL
|
||||||
|
Valve VZ has flow rate=10; tunnel leads to valve NE
|
||||||
|
Valve TX has flow rate=19; tunnels lead to valves MG, OQ, HM
|
||||||
|
Valve ZI has flow rate=5; tunnels lead to valves BY, ON, RU, LF, JR
|
||||||
|
Valve IH has flow rate=0; tunnels lead to valves YB, QS
|
||||||
|
Valve QS has flow rate=22; tunnel leads to valve IH
|
||||||
|
Valve QB has flow rate=0; tunnels lead to valves QX, ES
|
||||||
|
Valve NX has flow rate=0; tunnels lead to valves UH, OP
|
||||||
|
Valve PJ has flow rate=0; tunnels lead to valves OC, UH
|
||||||
|
Valve OR has flow rate=6; tunnels lead to valves QH, BH, HB, JD
|
||||||
|
Valve OC has flow rate=7; tunnels lead to valves IZ, JR, TA, ZH, PJ
|
||||||
|
Valve UC has flow rate=0; tunnels lead to valves AA, BY
|
||||||
|
Valve QX has flow rate=0; tunnels lead to valves AA, QB
|
||||||
|
Valve IZ has flow rate=0; tunnels lead to valves OC, SX
|
||||||
|
Valve AG has flow rate=13; tunnels lead to valves NW, GL, SM
|
||||||
|
Valve ON has flow rate=0; tunnels lead to valves MO, ZI
|
||||||
|
Valve XT has flow rate=18; tunnels lead to valves QZ, PG
|
||||||
|
Valve AX has flow rate=0; tunnels lead to valves UH, MO
|
||||||
|
Valve JD has flow rate=0; tunnels lead to valves OR, SM
|
||||||
|
Valve HM has flow rate=0; tunnels lead to valves TX, QH
|
||||||
|
Valve LF has flow rate=0; tunnels lead to valves ZI, UH
|
||||||
|
Valve QH has flow rate=0; tunnels lead to valves OR, HM
|
||||||
|
Valve RT has flow rate=21; tunnel leads to valve PG
|
||||||
|
Valve NE has flow rate=0; tunnels lead to valves VZ, TA
|
||||||
|
Valve OQ has flow rate=0; tunnels lead to valves TX, GE
|
||||||
|
Valve AA has flow rate=0; tunnels lead to valves QZ, UC, OP, QX, EH
|
||||||
|
Valve UH has flow rate=17; tunnels lead to valves PJ, NX, AX, LF
|
||||||
|
Valve GE has flow rate=0; tunnels lead to valves YB, OQ
|
||||||
|
Valve EH has flow rate=0; tunnels lead to valves AA, MO
|
||||||
|
Valve MG has flow rate=0; tunnels lead to valves TX, NW
|
||||||
|
Valve YB has flow rate=20; tunnels lead to valves IH, GE, XG
|
||||||
|
Valve MO has flow rate=15; tunnels lead to valves EH, ON, AX, ZH, CB
|
||||||
|
Valve JR has flow rate=0; tunnels lead to valves ZI, OC
|
||||||
|
Valve GL has flow rate=0; tunnels lead to valves AG, QJ
|
||||||
|
Valve SM has flow rate=0; tunnels lead to valves JD, AG
|
||||||
|
Valve HB has flow rate=0; tunnels lead to valves OR, QJ
|
||||||
|
Valve TA has flow rate=0; tunnels lead to valves OC, NE
|
||||||
|
Valve PG has flow rate=0; tunnels lead to valves RT, XT
|
||||||
|
Valve XG has flow rate=0; tunnels lead to valves CB, YB
|
||||||
|
Valve ES has flow rate=9; tunnels lead to valves QB, FL
|
||||||
|
Valve BH has flow rate=0; tunnels lead to valves RU, OR
|
||||||
|
Valve FL has flow rate=0; tunnels lead to valves SX, ES
|
||||||
|
Valve CB has flow rate=0; tunnels lead to valves MO, XG
|
||||||
|
Valve QZ has flow rate=0; tunnels lead to valves AA, XT
|
||||||
|
Valve BY has flow rate=0; tunnels lead to valves UC, ZI
|
||||||
|
Valve ZH has flow rate=0; tunnels lead to valves MO, OC
|
||||||
|
Valve OP has flow rate=0; tunnels lead to valves NX, AA
|
||||||
|
Valve NW has flow rate=0; tunnels lead to valves MG, AG
|
||||||
|
Valve RU has flow rate=0; tunnels lead to valves ZI, BH
|
||||||
|
Valve SX has flow rate=16; tunnels lead to valves IZ, FL
|
||||||
@@ -1,9 +1,246 @@
|
|||||||
use anyhow::Result;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
pub fn part1(_input: &[u8]) -> Result<String> {
|
use ahash::AHashMap;
|
||||||
anyhow::bail!("not implemented")
|
use ahash::AHashSet;
|
||||||
|
use anyhow::Result;
|
||||||
|
use nom::branch::alt;
|
||||||
|
use nom::bytes::complete::tag;
|
||||||
|
use nom::character::complete::alpha1;
|
||||||
|
use nom::character::complete::newline;
|
||||||
|
use nom::combinator::into;
|
||||||
|
use nom::multi::fold_many1;
|
||||||
|
use nom::multi::separated_list1;
|
||||||
|
use nom::sequence::preceded;
|
||||||
|
use nom::sequence::terminated;
|
||||||
|
use nom::sequence::tuple;
|
||||||
|
use nom::IResult;
|
||||||
|
|
||||||
|
use crate::common::parse_input;
|
||||||
|
|
||||||
|
type ParsedNetwork<'a> = AHashMap<&'a [u8], ParsedValve<'a>>;
|
||||||
|
|
||||||
|
struct ParsedValve<'a> {
|
||||||
|
connected: Vec<&'a [u8]>,
|
||||||
|
flow: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct SimpleNetwork {
|
||||||
|
valves: Vec<SimpleValve>,
|
||||||
|
start: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct SimpleValve {
|
||||||
|
connected: Vec<(usize, u8)>,
|
||||||
|
flow: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParsedNetwork<'_>> for SimpleNetwork {
|
||||||
|
fn from(parsed: ParsedNetwork) -> Self {
|
||||||
|
let mapping: AHashMap<_, _> = parsed
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(&k, v)| (v.flow > 0 || k == b"AA").then_some(k))
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, v)| (v, i))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut todo = VecDeque::new();
|
||||||
|
let mut seen = AHashSet::new();
|
||||||
|
|
||||||
|
let mut network = Vec::with_capacity(mapping.len());
|
||||||
|
|
||||||
|
for (&key, valve_data) in &parsed {
|
||||||
|
if valve_data.flow == 0 && key != b"AA" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
todo.extend(valve_data.connected.iter().map(|&valve| (valve, 1)));
|
||||||
|
|
||||||
|
let mut connected = Vec::new();
|
||||||
|
|
||||||
|
seen.clear();
|
||||||
|
while let Some((valve, dist)) = todo.pop_front() {
|
||||||
|
if seen.insert(valve) {
|
||||||
|
let data = &parsed[&valve];
|
||||||
|
|
||||||
|
if data.flow != 0 {
|
||||||
|
connected.push((mapping[valve], dist));
|
||||||
|
}
|
||||||
|
for &other in &data.connected {
|
||||||
|
if other != key {
|
||||||
|
todo.push_back((other, dist + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
network.push(SimpleValve {
|
||||||
|
flow: valve_data.flow,
|
||||||
|
connected,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
valves: network,
|
||||||
|
start: mapping[&b"AA"[..]],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_network(input: &[u8]) -> IResult<&[u8], ParsedNetwork> {
|
||||||
|
let parse_network = terminated(
|
||||||
|
tuple((
|
||||||
|
// Parse the name of the valve
|
||||||
|
preceded(tag("Valve "), alpha1),
|
||||||
|
// Parse the flow of the valve
|
||||||
|
preceded(tag(" has flow rate="), nom::character::complete::u32),
|
||||||
|
// Parse the connections
|
||||||
|
preceded(
|
||||||
|
// Did you really have to distinguish plural
|
||||||
|
alt((
|
||||||
|
tag("; tunnels lead to valves "),
|
||||||
|
tag("; tunnel leads to valve "),
|
||||||
|
)),
|
||||||
|
separated_list1(tag(", "), alpha1),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
newline,
|
||||||
|
);
|
||||||
|
|
||||||
|
fold_many1(
|
||||||
|
parse_network,
|
||||||
|
ParsedNetwork::new,
|
||||||
|
|mut map, (valve, flow, connected)| {
|
||||||
|
map.insert(valve, ParsedValve { flow, connected });
|
||||||
|
|
||||||
|
map
|
||||||
|
},
|
||||||
|
)(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Hash, Debug, Clone)]
|
||||||
|
struct State {
|
||||||
|
pos: usize,
|
||||||
|
valves_open: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
fn open(&self) -> Option<State> {
|
||||||
|
let bit = 1 << self.pos;
|
||||||
|
if (self.valves_open & bit) == 0 {
|
||||||
|
Some(State {
|
||||||
|
pos: self.pos,
|
||||||
|
valves_open: self.valves_open | bit,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_open(&self, pos: usize) -> bool {
|
||||||
|
(self.valves_open & (1 << pos)) != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for State {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
// Reversed because having fewer valves with the same score gives more opportunities for gains
|
||||||
|
self.valves_open
|
||||||
|
.count_ones()
|
||||||
|
.cmp(&other.valves_open.count_ones())
|
||||||
|
// Compare open valves and pos. Shouldn't really matter but required for a total order.
|
||||||
|
.then(self.valves_open.cmp(&other.valves_open))
|
||||||
|
.then(self.pos.cmp(&other.pos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for State {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part1(input: &[u8]) -> Result<String> {
|
||||||
|
let network: SimpleNetwork = parse_input(input, into(parse_network))?;
|
||||||
|
|
||||||
|
let mut best = AHashMap::new();
|
||||||
|
|
||||||
|
let initial_state = State {
|
||||||
|
valves_open: 0,
|
||||||
|
pos: network.start,
|
||||||
|
};
|
||||||
|
|
||||||
|
best.insert(initial_state.clone(), 0);
|
||||||
|
|
||||||
|
let mut todo = VecDeque::new();
|
||||||
|
|
||||||
|
todo.push_back((0, 0, initial_state));
|
||||||
|
|
||||||
|
let mut best_score = 0;
|
||||||
|
|
||||||
|
while let Some((score, minute, state)) = todo.pop_front() {
|
||||||
|
if best[&state] > score {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut enqueue = |score, minute, state: State| {
|
||||||
|
if minute >= 29
|
||||||
|
|| best
|
||||||
|
.get(&state)
|
||||||
|
.map(|&previous| previous >= score)
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
best.insert(state.clone(), score);
|
||||||
|
todo.push_back((score, minute, state));
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(new_state) = state.open() {
|
||||||
|
let pos = new_state.pos;
|
||||||
|
let valve_strength = network.valves[pos].flow;
|
||||||
|
let time_remaining = 29 - minute;
|
||||||
|
let new_score = score + time_remaining as u32 * network.valves[pos].flow;
|
||||||
|
|
||||||
|
println!("Opening valve {pos} for {valve_strength} for {time_remaining} minutes: {new_score} ({best_score})");
|
||||||
|
|
||||||
|
best_score = best_score.max(new_score);
|
||||||
|
|
||||||
|
enqueue(new_score, minute + 1, new_state)
|
||||||
|
}
|
||||||
|
|
||||||
|
for &(other, dist) in &network.valves[state.pos].connected {
|
||||||
|
if state.is_open(other) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_state = State {
|
||||||
|
pos: other,
|
||||||
|
valves_open: state.valves_open,
|
||||||
|
};
|
||||||
|
|
||||||
|
enqueue(score, minute + dist, new_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guesses: 1802 (too low)
|
||||||
|
Ok(best_score.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part2(_input: &[u8]) -> Result<String> {
|
pub fn part2(_input: &[u8]) -> Result<String> {
|
||||||
anyhow::bail!("not implemented")
|
anyhow::bail!("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const SAMPLE: &[u8] = include_bytes!("samples/16.txt");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_part1() {
|
||||||
|
assert_eq!(part1(SAMPLE).unwrap(), "1651");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
10
2022/src/samples/16.txt
Normal file
10
2022/src/samples/16.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
|
||||||
|
Valve BB has flow rate=13; tunnels lead to valves CC, AA
|
||||||
|
Valve CC has flow rate=2; tunnels lead to valves DD, BB
|
||||||
|
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
|
||||||
|
Valve EE has flow rate=3; tunnels lead to valves FF, DD
|
||||||
|
Valve FF has flow rate=0; tunnels lead to valves EE, GG
|
||||||
|
Valve GG has flow rate=0; tunnels lead to valves FF, HH
|
||||||
|
Valve HH has flow rate=22; tunnel leads to valve GG
|
||||||
|
Valve II has flow rate=0; tunnels lead to valves AA, JJ
|
||||||
|
Valve JJ has flow rate=21; tunnel leads to valve II
|
||||||
Reference in New Issue
Block a user