day 16, but with a lot of pain
This commit is contained in:
185
Cargo.lock
generated
185
Cargo.lock
generated
@@ -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",
|
||||
]
|
||||
|
||||
@@ -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
55
inputs/day16.txt
Normal 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
8
src/bin/day16_1.rs
Normal 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
8
src/bin/day16_2.rs
Normal 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
189
src/day16.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -16,3 +16,4 @@ pub mod day12;
|
||||
pub mod day13;
|
||||
pub mod day14;
|
||||
pub mod day15;
|
||||
pub mod day16;
|
||||
|
||||
Reference in New Issue
Block a user