day 16, but with a lot of pain

This commit is contained in:
2022-12-17 14:59:38 +01:00
parent 075817691c
commit 628e556063
7 changed files with 449 additions and 0 deletions

185
Cargo.lock generated
View File

@@ -6,9 +6,12 @@ version = 3
name = "aoc2022"
version = "0.1.0"
dependencies = [
"bitvec",
"itertools",
"nom",
"num",
"petgraph",
"rayon",
]
[[package]]
@@ -17,12 +20,110 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitvec"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crossbeam-channel"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
dependencies = [
"cfg-if",
]
[[package]]
name = "either"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "fixedbitset"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "indexmap"
version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "itertools"
version = "0.10.5"
@@ -32,12 +133,27 @@ dependencies = [
"either",
]
[[package]]
name = "libc"
version = "0.2.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memoffset"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
dependencies = [
"autocfg",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
@@ -129,3 +245,72 @@ checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "petgraph"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
name = "rayon"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"num_cpus",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "wyz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [
"tap",
]

View File

@@ -6,6 +6,9 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bitvec = "1.0.1"
itertools = "0.10.5"
nom = "7.1.1"
num = "0.4.0"
petgraph = "0.6.2"
rayon = "1.6.1"

55
inputs/day16.txt Normal file
View File

@@ -0,0 +1,55 @@
Valve NA has flow rate=0; tunnels lead to valves MU, PH
Valve NW has flow rate=0; tunnels lead to valves KB, MH
Valve MR has flow rate=0; tunnels lead to valves GC, FI
Valve XD has flow rate=0; tunnels lead to valves UN, CN
Valve HK has flow rate=0; tunnels lead to valves AA, IF
Valve JL has flow rate=0; tunnels lead to valves IF, WB
Valve RQ has flow rate=13; tunnels lead to valves BL, DJ
Valve AB has flow rate=0; tunnels lead to valves BO, RU
Valve PE has flow rate=0; tunnels lead to valves AZ, IF
Valve QF has flow rate=0; tunnels lead to valves TD, AZ
Valve BA has flow rate=0; tunnels lead to valves RF, GU
Valve SY has flow rate=0; tunnels lead to valves MH, MU
Valve NT has flow rate=0; tunnels lead to valves DJ, UN
Valve GU has flow rate=21; tunnels lead to valves VJ, BA, YP
Valve AZ has flow rate=12; tunnels lead to valves QF, PI, AS, PE
Valve WQ has flow rate=23; tunnels lead to valves VJ, UM, CN
Valve DR has flow rate=0; tunnels lead to valves GA, CQ
Valve UM has flow rate=0; tunnels lead to valves IE, WQ
Valve XI has flow rate=0; tunnels lead to valves IE, IF
Valve SS has flow rate=0; tunnels lead to valves CQ, MH
Valve IE has flow rate=22; tunnels lead to valves YP, UM, XI, XA
Valve BT has flow rate=24; tunnels lead to valves KB, BL, GA
Valve GA has flow rate=0; tunnels lead to valves DR, BT
Valve AR has flow rate=0; tunnels lead to valves IF, FI
Valve DJ has flow rate=0; tunnels lead to valves RQ, NT
Valve PI has flow rate=0; tunnels lead to valves FI, AZ
Valve WB has flow rate=0; tunnels lead to valves TD, JL
Valve OQ has flow rate=0; tunnels lead to valves ME, TD
Valve RU has flow rate=19; tunnel leads to valve AB
Valve IF has flow rate=7; tunnels lead to valves AR, JL, HK, PE, XI
Valve BO has flow rate=0; tunnels lead to valves ME, AB
Valve CN has flow rate=0; tunnels lead to valves WQ, XD
Valve HH has flow rate=0; tunnels lead to valves AA, FS
Valve AS has flow rate=0; tunnels lead to valves AA, AZ
Valve FS has flow rate=0; tunnels lead to valves HH, MH
Valve PQ has flow rate=0; tunnels lead to valves TD, AA
Valve AA has flow rate=0; tunnels lead to valves HH, CO, AS, HK, PQ
Valve ME has flow rate=18; tunnels lead to valves OQ, BO, PH
Valve RF has flow rate=0; tunnels lead to valves UN, BA
Valve MH has flow rate=8; tunnels lead to valves FS, NW, SS, SY
Valve YP has flow rate=0; tunnels lead to valves IE, GU
Valve FI has flow rate=11; tunnels lead to valves PI, MR, AR, CO, DI
Valve UU has flow rate=0; tunnels lead to valves CQ, MU
Valve CO has flow rate=0; tunnels lead to valves AA, FI
Valve TD has flow rate=16; tunnels lead to valves QF, GC, OQ, WB, PQ
Valve MU has flow rate=15; tunnels lead to valves SY, UU, NA
Valve BL has flow rate=0; tunnels lead to valves BT, RQ
Valve PH has flow rate=0; tunnels lead to valves ME, NA
Valve XA has flow rate=0; tunnels lead to valves IE, DI
Valve GC has flow rate=0; tunnels lead to valves TD, MR
Valve KB has flow rate=0; tunnels lead to valves BT, NW
Valve DI has flow rate=0; tunnels lead to valves XA, FI
Valve CQ has flow rate=9; tunnels lead to valves UU, DR, SS
Valve VJ has flow rate=0; tunnels lead to valves WQ, GU
Valve UN has flow rate=20; tunnels lead to valves NT, XD, RF

8
src/bin/day16_1.rs Normal file
View File

@@ -0,0 +1,8 @@
use std::fs;
use aoc2022::day16::process_part_1;
fn main() {
let file = fs::read_to_string("./inputs/day16.txt").unwrap();
println!("{}", process_part_1(&file));
}

8
src/bin/day16_2.rs Normal file
View File

@@ -0,0 +1,8 @@
use std::fs;
use aoc2022::day16::process_part_2;
fn main() {
let file = fs::read_to_string("./inputs/day16.txt").unwrap();
println!("{}", process_part_2(&file));
}

189
src/day16.rs Normal file
View File

@@ -0,0 +1,189 @@
use std::collections::HashMap;
use bitvec::prelude::BitArray;
use itertools::Itertools;
use nom::branch::alt;
use nom::bytes::complete::{tag, take};
use nom::character::complete;
use nom::character::complete::newline;
use nom::multi::separated_list1;
use nom::sequence::preceded;
use nom::IResult;
use petgraph::algo::floyd_warshall;
use petgraph::prelude::{NodeIndex, UnGraph};
use rayon::prelude::*;
pub fn process_part_1(input: &str) -> usize {
let data = parse_input(input).unwrap().1;
let distances = floyd_warshall(&data.graph, |_| 1).unwrap();
let targets = data.targets();
max_released(
&data.graph,
&distances,
data.start,
30,
&targets,
BitArray::ZERO,
)
}
pub fn process_part_2(input: &str) -> usize {
let data = parse_input(input).unwrap().1;
let distances = floyd_warshall(&data.graph, |_| 1).unwrap();
let targets = data.targets();
// Split targets about evenly. Human takes (i) nodes, leaving (|targets| - i) nodes for the elephant
(1..=targets.len() / 2)
.into_par_iter()
.flat_map(|n| targets.iter().copied().combinations(n).collect_vec())
.map(|human_nodes| {
let elephant_nodes = targets
.iter()
.copied()
.filter(|n| !human_nodes.contains(n))
.collect();
let max_human = max_released(
&data.graph,
&distances,
data.start,
26,
&human_nodes,
BitArray::ZERO,
);
let max_elephant = max_released(
&data.graph,
&distances,
data.start,
26,
&elephant_nodes,
BitArray::ZERO,
);
max_human + max_elephant
})
.max()
.unwrap()
}
fn max_released(
graph: &UnGraph<usize, u8>,
distances: &HashMap<(NodeIndex, NodeIndex), i32>,
start: NodeIndex,
remaining_time: usize,
targets: &Vec<NodeIndex>,
opened: BitArray<u64>,
) -> usize {
let mut max = 0;
// If we are out of time, or if we have opened all valves
if remaining_time == 0 || opened.count_ones() == targets.len() {
return 0;
}
for &valve in targets.iter().filter(|&n| !opened[n.index()]) {
let distance = distances[&(start, valve)].unsigned_abs() as usize;
if remaining_time <= distance {
continue;
}
let mut opened = opened;
opened.set(valve.index(), true);
let next_time_remaining = remaining_time.saturating_sub(distance).saturating_sub(1);
let next_released = max_released(
graph,
distances,
valve,
next_time_remaining,
targets,
opened,
);
let flow = *graph.node_weight(valve).unwrap() * next_time_remaining;
if flow + next_released > max {
max = flow + next_released;
}
}
max
}
#[derive(Debug, Clone)]
struct Data {
graph: UnGraph<usize, u8>,
start: NodeIndex,
}
impl Data {
fn targets(&self) -> Vec<NodeIndex> {
self.graph
.node_indices()
.filter(|&n| *self.graph.node_weight(n).unwrap() > 0)
.collect()
}
}
fn parse_input(input: &str) -> IResult<&str, Data> {
let (input, parsed_valves) = separated_list1(newline, parse_line)(input)?;
let mut graph = UnGraph::new_undirected();
let mut valves = HashMap::new();
let mut valves_by_index = HashMap::new();
// generate graph nodes
for valve in &parsed_valves {
let node = graph.add_node(valve.1);
valves.insert(valve.0, node);
valves_by_index.insert(node, valve.0);
}
// generate graph edges
for valve in &parsed_valves {
let valve_node = valves.get(valve.0).unwrap();
for &neighbor in &valve.2 {
let neighbor_node = valves.get(neighbor).unwrap();
graph.add_edge(*valve_node, *neighbor_node, 1);
}
}
let start = *valves.get("AA").unwrap();
Ok((input, Data { graph, start }))
}
fn parse_line(input: &str) -> IResult<&str, (&str, usize, Vec<&str>)> {
let (input, valve_name) = preceded(tag("Valve "), take(2usize))(input)?;
let (input, flow) = preceded(tag(" has flow rate="), complete::u32)(input)?;
let (input, neighbors) = preceded(
alt((
tag("; tunnels lead to valves "),
tag("; tunnel leads to valve "),
)),
separated_list1(tag(", "), take(2usize)),
)(input)?;
Ok((input, (valve_name, flow as usize, neighbors)))
}
#[cfg(test)]
mod tests {
use super::*;
const INPUT: &str = "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";
#[test]
fn day1() {
assert_eq!(process_part_1(INPUT), 1651);
}
#[test]
fn day2() {
assert_eq!(process_part_2(INPUT), 1707);
}
}

View File

@@ -16,3 +16,4 @@ pub mod day12;
pub mod day13;
pub mod day14;
pub mod day15;
pub mod day16;