day 16 done

This commit is contained in:
Dylan Thies
2023-09-06 17:02:04 -04:00
parent c675a63f90
commit 33b71e77f7
5 changed files with 325 additions and 0 deletions

12
day16/Cargo.toml Normal file
View File

@@ -0,0 +1,12 @@
[package]
name = "day16"
version.workspace = true
edition.workspace = true
authors.workspace = true
repository.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nom.workspace = true
itertools.workspace = true

57
day16/input.txt Normal file
View File

@@ -0,0 +1,57 @@
Valve RU has flow rate=0; tunnels lead to valves YH, ID
Valve QK has flow rate=24; tunnels lead to valves PQ, PP
Valve RP has flow rate=11; tunnels lead to valves RM, BA, RI, EM
Valve BX has flow rate=0; tunnels lead to valves ZX, VK
Valve JL has flow rate=0; tunnels lead to valves ID, LC
Valve DC has flow rate=25; tunnel leads to valve ST
Valve HX has flow rate=0; tunnels lead to valves DH, FE
Valve KJ has flow rate=0; tunnels lead to valves ZK, XN
Valve EM has flow rate=0; tunnels lead to valves AW, RP
Valve XN has flow rate=7; tunnels lead to valves LH, KJ, KU, AO
Valve DH has flow rate=9; tunnels lead to valves SY, CC, QL, LH, HX
Valve LH has flow rate=0; tunnels lead to valves XN, DH
Valve PP has flow rate=0; tunnels lead to valves QK, TA
Valve AO has flow rate=0; tunnels lead to valves AA, XN
Valve SY has flow rate=0; tunnels lead to valves DH, AA
Valve MZ has flow rate=0; tunnels lead to valves JT, PF
Valve AA has flow rate=0; tunnels lead to valves JN, UN, WG, SY, AO
Valve RM has flow rate=0; tunnels lead to valves XL, RP
Valve BA has flow rate=0; tunnels lead to valves RP, YP
Valve AD has flow rate=12; tunnels lead to valves LK, ZX, AW
Valve ZN has flow rate=0; tunnels lead to valves EQ, HL
Valve EX has flow rate=18; tunnel leads to valve RB
Valve CR has flow rate=0; tunnels lead to valves TA, ST
Valve WG has flow rate=0; tunnels lead to valves AA, TA
Valve UN has flow rate=0; tunnels lead to valves WK, AA
Valve VE has flow rate=0; tunnels lead to valves JA, KW
Valve JA has flow rate=19; tunnels lead to valves PQ, VE
Valve AW has flow rate=0; tunnels lead to valves AD, EM
Valve XL has flow rate=0; tunnels lead to valves RM, PF
Valve OD has flow rate=0; tunnels lead to valves VK, RI
Valve FE has flow rate=0; tunnels lead to valves JT, HX
Valve PQ has flow rate=0; tunnels lead to valves JA, QK
Valve RB has flow rate=0; tunnels lead to valves CC, EX
Valve JT has flow rate=3; tunnels lead to valves RF, MZ, ZK, FE, DD
Valve YP has flow rate=0; tunnels lead to valves ID, BA
Valve ID has flow rate=14; tunnels lead to valves JL, RU, YP
Valve YH has flow rate=0; tunnels lead to valves RU, VK
Valve TA has flow rate=21; tunnels lead to valves WG, KU, PP, RF, CR
Valve LK has flow rate=0; tunnels lead to valves PF, AD
Valve DD has flow rate=0; tunnels lead to valves JN, JT
Valve HL has flow rate=0; tunnels lead to valves ZN, DW
Valve VK has flow rate=22; tunnels lead to valves OD, KW, BX, YH
Valve RF has flow rate=0; tunnels lead to valves JT, TA
Valve CC has flow rate=0; tunnels lead to valves RB, DH
Valve KW has flow rate=0; tunnels lead to valves VE, VK
Valve PF has flow rate=10; tunnels lead to valves WK, MZ, QL, XL, LK
Valve ZX has flow rate=0; tunnels lead to valves AD, BX
Valve JN has flow rate=0; tunnels lead to valves DD, AA
Valve ST has flow rate=0; tunnels lead to valves CR, DC
Valve WK has flow rate=0; tunnels lead to valves PF, UN
Valve DW has flow rate=13; tunnels lead to valves LC, HL
Valve ZK has flow rate=0; tunnels lead to valves KJ, JT
Valve QL has flow rate=0; tunnels lead to valves DH, PF
Valve RI has flow rate=0; tunnels lead to valves OD, RP
Valve EQ has flow rate=23; tunnel leads to valve ZN
Valve LC has flow rate=0; tunnels lead to valves JL, DW
Valve KU has flow rate=0; tunnels lead to valves XN, TA

247
day16/src/main.rs Normal file
View File

@@ -0,0 +1,247 @@
use std::{
collections::{HashMap, VecDeque},
fs,
};
use itertools::Itertools;
use nom::{
branch::alt,
bytes::complete::tag,
character::complete::{self, newline},
error::Error,
multi::{separated_list0, separated_list1},
sequence::preceded,
Parser,
};
#[derive(Debug, Clone, Default)]
struct Valve {
pub label: String,
pub release: usize,
pub connected_to: Vec<String>,
}
impl<'a> Parser<&'a str, Self, Error<&'a str>> for Valve {
fn parse(&mut self, input: &'a str) -> nom::IResult<&'a str, Self, Error<&'a str>> {
let (input, label) =
preceded(tag("Valve "), complete::alpha1.map(|s: &str| s.to_owned()))(input)?;
let (input, release) =
preceded(tag(" has flow rate="), complete::u128.map(|s| s as usize))(input)?;
let (input, connected_to) = preceded(
alt((
tag("; tunnels lead to valves "),
tag("; tunnel leads to valve "),
)),
separated_list1(tag(", "), complete::alpha1.map(|s: &str| s.to_owned())),
)(input)?;
self.label = label;
self.release = release;
self.connected_to = connected_to.clone();
Ok((input, self.clone()))
}
}
//* nom parser to take string input and turn it in to a hashmaps of valves */
fn parse_input(input: &str) -> nom::IResult<&str, HashMap<String, Valve>> {
let (input, valves) = separated_list0(newline, Valve::default())(input)?;
Ok((
input,
valves
.iter()
.map(|x| (x.label.clone(), x.clone()))
.collect(),
))
}
#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
struct SimpleValve {
pub _label: String,
pub release: usize,
pub connected_to: Vec<(usize, usize)>,
}
//* takes a map of valves represented by strings and removes the unnexasrray steps and will create a complete graph of the connected */
fn convert_to_distance(board: &HashMap<String, Valve>) -> Vec<SimpleValve> {
let care_about = board
.iter()
.filter(|(pos, valve)| valve.release != 0 || *pos == "AA")
.collect::<Vec<_>>();
let mut distances: HashMap<(&str, &str), usize> = HashMap::new();
//get the distance for each possible connection
care_about.iter().for_each(|(from_pos, from_valve)| {
let mut queue = VecDeque::from([(0_usize, *from_valve)]);
while let Some((dist, check)) = queue.pop_front() {
let dist = dist + 1;
for v in check.connected_to.iter().filter_map(|i| board.get(i)) {
if let Some(d) = distances.get(&(from_pos, &v.label)) {
if dist >= *d {
continue;
}
}
distances.insert((from_pos, &v.label), dist);
queue.push_back((dist, v));
}
}
});
//makeing distances immutable
let distances = distances;
let holder = care_about
.iter()
.sorted_by(|(a, _), (b, _)| (*a).cmp(*b))
.map(|(a, _)| (*a).clone())
.enumerate()
.map(|(i, a)| (a, i))
.collect::<HashMap<_, _>>();
care_about
.iter()
.map(|(pos, valve)| {
let connected_to = care_about
.iter()
.filter(|(key, _)| "AA" != *key && **pos != **key)
.map(|(to_pos, _)| {
(
*holder.get(*to_pos).unwrap(),
*distances.get(&(pos, *to_pos)).unwrap(),
)
})
.collect();
(
(*pos).clone(),
SimpleValve {
_label: valve.label.clone(),
release: valve.release,
connected_to,
},
)
})
.sorted_by(|(a, _), (b, _)| a.cmp(b))
.map(|(_, a)| a)
.collect()
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct StructKey(
/*step*/ usize,
/*valve*/ usize,
/*pathmask*/ Pathmask,
);
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct Pathmask {
pub mask: usize,
}
impl From<usize> for Pathmask {
fn from(mask: usize) -> Self {
Self { mask }
}
}
impl From<Pathmask> for usize {
fn from(mask: Pathmask) -> Self {
mask.mask
}
}
fn recurse(
board: &Vec<SimpleValve>,
vavle_index: usize,
path: Pathmask,
steps: usize,
score: usize,
cache: &mut HashMap<StructKey, usize>,
) -> usize {
//has this been cached?
if let Some(sc) = cache.get(&StructKey(steps, vavle_index, path)) {
println!("choo");
return *sc;
}
let valve = board.get(vavle_index).unwrap();
let new_path =
Pathmask::from(std::convert::Into::<usize>::into(path) | (1_usize << vavle_index));
let Some(v) = valve
.connected_to
.iter()
.filter(|x| std::convert::Into::<usize>::into(path) & (1 << x.0) == 0 && steps > x.1 + 1)
.map(|(next, new_dist)| {
let new_steps = steps - 1 - new_dist;
let score = score + board.get(*next).unwrap().release * new_steps;
recurse(board, *next, new_path, new_steps, score, cache)
})
.fold(None, |acc: Option<usize>, new_spot: usize| {
if acc.is_none() || new_spot > acc.unwrap() {
Some(new_spot)
} else {
acc
}
})
else {
return score;
};
cache.insert(StructKey(steps, score, path), v);
v
}
fn part1(input: &str) -> String {
//explore graph
let board = convert_to_distance(&parse_input(input).unwrap().1);
let cache = &mut HashMap::new();
let r = recurse(&board, 0, 0.into(), 30, 0, cache);
r.to_string()
}
fn part2(input: &str) -> String {
let board = convert_to_distance(&parse_input(input).unwrap().1);
let cache = &mut HashMap::new();
let top_mask: usize = (1 << board.len()) - 1;
(0..=((top_mask + 1) / 2))
.map(|i| {
recurse(&board, 0, Pathmask::from(i), 26, 0, cache)
+ recurse(&board, 0, Pathmask::from(top_mask ^ i), 26, 0, cache)
})
.max()
.unwrap()
.to_string()
}
//if open don't close
fn main() {
let file = fs::read_to_string("input.txt").unwrap();
println!("Part 1: {}", part1(&file));
println!("Part 2: {}", part2(&file));
}
#[cfg(test)]
mod test {
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 part1_works() {
assert_eq!(part1(INPUT), "1651")
}
#[test]
fn part2_works() {
assert_eq!(part2(INPUT), "1707")
}
#[test]
fn testssss() {
let board = convert_to_distance(&parse_input(INPUT).unwrap().1);
let top_mask: usize = (1 << board.len()) - 1;
(0..=((top_mask + 1) / 2)).for_each(|i| {
let other = i ^ top_mask;
let test = i | other;
assert_eq!(test, top_mask, "{i}");
});
}
}