From c5a0ad16a10c8b50d9bb9c4563115ef82b410efe Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Fri, 16 Dec 2022 21:14:09 +0100 Subject: [PATCH] 2022 - Day 16 --- 2022/input/16/input | 61 ++++++++++++++ 2022/input/16/test-1 | 10 +++ 2022/src/bin/day16.rs | 180 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 251 insertions(+) create mode 100644 2022/input/16/input create mode 100644 2022/input/16/test-1 create mode 100644 2022/src/bin/day16.rs diff --git a/2022/input/16/input b/2022/input/16/input new file mode 100644 index 0000000..16182d2 --- /dev/null +++ b/2022/input/16/input @@ -0,0 +1,61 @@ +Valve KR has flow rate=17; tunnels lead to valves WA, JQ, JY, KI +Valve JN has flow rate=0; tunnels lead to valves XS, JQ +Valve JY has flow rate=0; tunnels lead to valves KR, AP +Valve WE has flow rate=0; tunnels lead to valves GY, XS +Valve HW has flow rate=0; tunnels lead to valves GP, AA +Valve QS has flow rate=0; tunnels lead to valves WW, MF +Valve MF has flow rate=15; tunnels lead to valves RJ, QS +Valve IM has flow rate=0; tunnels lead to valves WH, HS +Valve RJ has flow rate=0; tunnels lead to valves MF, PM +Valve IG has flow rate=0; tunnels lead to valves WX, ZY +Valve YL has flow rate=0; tunnels lead to valves GY, EB +Valve LI has flow rate=25; tunnels lead to valves YS, SI +Valve WW has flow rate=6; tunnels lead to valves PJ, QS +Valve QK has flow rate=0; tunnels lead to valves MV, AU +Valve AU has flow rate=20; tunnels lead to valves QK, BT, VK +Valve WH has flow rate=0; tunnels lead to valves MV, IM +Valve YS has flow rate=0; tunnels lead to valves ZL, LI +Valve FR has flow rate=0; tunnels lead to valves XS, AA +Valve NX has flow rate=0; tunnels lead to valves KI, NG +Valve OI has flow rate=5; tunnels lead to valves SU, OX, LW, JH, DK +Valve YJ has flow rate=0; tunnels lead to valves XK, XU +Valve DK has flow rate=0; tunnels lead to valves OI, IZ +Valve SU has flow rate=0; tunnels lead to valves OI, XU +Valve OH has flow rate=0; tunnels lead to valves CX, WX +Valve HS has flow rate=8; tunnels lead to valves UY, IM, WJ, XK, UC +Valve UY has flow rate=0; tunnels lead to valves HS, OX +Valve AP has flow rate=0; tunnels lead to valves JY, GY +Valve JQ has flow rate=0; tunnels lead to valves KR, JN +Valve XK has flow rate=0; tunnels lead to valves YJ, HS +Valve PM has flow rate=0; tunnels lead to valves RJ, ZY +Valve WJ has flow rate=0; tunnels lead to valves AA, HS +Valve VK has flow rate=0; tunnels lead to valves AU, SI +Valve OX has flow rate=0; tunnels lead to valves UY, OI +Valve ZL has flow rate=0; tunnels lead to valves YS, MV +Valve LW has flow rate=0; tunnels lead to valves TT, OI +Valve TT has flow rate=0; tunnels lead to valves LW, MV +Valve PJ has flow rate=0; tunnels lead to valves UC, WW +Valve UC has flow rate=0; tunnels lead to valves PJ, HS +Valve XU has flow rate=3; tunnels lead to valves EB, CW, SU, TL, YJ +Valve XS has flow rate=4; tunnels lead to valves IZ, CW, WE, JN, FR +Valve CW has flow rate=0; tunnels lead to valves XU, XS +Valve TF has flow rate=0; tunnels lead to valves AA, TL +Valve EB has flow rate=0; tunnels lead to valves XU, YL +Valve WA has flow rate=0; tunnels lead to valves KR, BT +Valve GY has flow rate=9; tunnels lead to valves GP, AP, YL, ZO, WE +Valve IZ has flow rate=0; tunnels lead to valves DK, XS +Valve KI has flow rate=0; tunnels lead to valves NX, KR +Valve AA has flow rate=0; tunnels lead to valves HW, TF, FR, JH, WJ +Valve ZO has flow rate=0; tunnels lead to valves GY, QM +Valve QM has flow rate=0; tunnels lead to valves ZO, CX +Valve SI has flow rate=0; tunnels lead to valves LI, VK +Valve BT has flow rate=0; tunnels lead to valves AU, WA +Valve BC has flow rate=0; tunnels lead to valves CX, ZY +Valve NG has flow rate=21; tunnel leads to valve NX +Valve WX has flow rate=16; tunnels lead to valves IG, OH +Valve GP has flow rate=0; tunnels lead to valves HW, GY +Valve JH has flow rate=0; tunnels lead to valves AA, OI +Valve CX has flow rate=13; tunnels lead to valves OH, BC, QM +Valve TL has flow rate=0; tunnels lead to valves TF, XU +Valve MV has flow rate=14; tunnels lead to valves QK, ZL, WH, TT +Valve ZY has flow rate=10; tunnels lead to valves PM, BC, IG diff --git a/2022/input/16/test-1 b/2022/input/16/test-1 new file mode 100644 index 0000000..9f30acc --- /dev/null +++ b/2022/input/16/test-1 @@ -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 diff --git a/2022/src/bin/day16.rs b/2022/src/bin/day16.rs new file mode 100644 index 0000000..4b08f19 --- /dev/null +++ b/2022/src/bin/day16.rs @@ -0,0 +1,180 @@ +#![feature(test)] +use std::{collections::{HashMap, VecDeque, HashSet}, str::FromStr}; + +use anyhow::Result; +use aoc::Solver; + +// -- Runners -- +fn main() -> Result<()> { + Day::solve() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn part1_test1() -> Result<()> { + Day::test(Day::part1, "test-1", 1651) + } + #[test] + fn part1_solution() -> Result<()> { + Day::test(Day::part1, "input", 1647) + } + #[test] + fn part2_test1() -> Result<()> { + Day::test(Day::part2, "test-1", 1707) + } + #[test] + fn part2_solution() -> Result<()> { + Day::test(Day::part2, "input", 2169) + } + + // Benchmarks + extern crate test; + #[bench] + #[ignore] + fn part1_bench(b: &mut test::Bencher) { + Day::benchmark(Day::part1, b) + } + #[bench] + #[ignore] + fn part2_bench(b: &mut test::Bencher) { + Day::benchmark(Day::part2, b) + } +} + +#[derive(Debug, Clone)] +struct Valve { + flowrate: i32, + connections: Vec, +} + +#[derive(Debug)] +struct Volcano { + valves: HashMap, +} + +impl FromStr for Volcano { + type Err = anyhow::Error; + + fn from_str(input: &str) -> Result { + let valves = input + .lines() + .map(|line| { + let mut iter = line.splitn(10, " "); + + let name = iter.nth(1).unwrap().into(); + let flowrate = iter.nth(2).unwrap().chars().filter(|c| c.is_digit(10)).collect::().parse().unwrap(); + + let connections = iter.nth(4).unwrap().split(", ").map(|name| name.into()).collect(); + + (name, Valve {flowrate, connections}) + }).collect(); + + Ok(Volcano { valves }) + } +} + +#[derive(Debug, Hash, PartialEq, Eq)] +struct State { + name: String, + time: i32, + opened: Vec, +} + +fn find_best(root: String, volcano: &Volcano, opened: Vec, time: i32) -> (i32, Vec) { + let mut queue = VecDeque::new(); + queue.push_back((State{name: root, time, opened}, 0)); + + let mut best = 0; + let mut best_opened = Vec::new(); + let mut evaluated = HashSet::new(); + loop { + // We are done now + if queue.is_empty() { + break; + } + + let mut state = queue.pop_front().unwrap(); + + // Check if we have run out of time + if state.0.time <= 1 { + if state.1 > best { + best = state.1; + best_opened = state.0.opened; + } + continue; + } + + if evaluated.contains(&state.0) { + continue; + } + + let current_valve = volcano.valves.get(&state.0.name).unwrap(); + + // Two options: + // 1: Open valve [Only if current valve is not opened and has a + // non-zero flowrate] + // 2: Move to other valve + + // Option 1 + if !state.0.opened.contains(&state.0.name) && current_valve.flowrate != 0 { + // Add the current valve to the list of opened valves + state.0.opened.push(state.0.name.clone()); + + let new_value = state.1 + (state.0.time-1) * current_valve.flowrate; + let ns = (State {name: state.0.name.to_owned(), time: state.0.time-1, opened: state.0.opened.clone()}, new_value); + queue.push_back(ns); + + state.0.opened.pop(); + } + + // Option 2 + for connection in current_valve.connections.iter() { + let ns = (State {name: connection.to_owned(), time: state.0.time-1, opened: state.0.opened.clone()}, state.1); + queue.push_back(ns); + } + + evaluated.insert(State{name: state.0.name.to_owned(), time: state.0.time, opened: state.0.opened.clone()}); + } + + return (best, best_opened); +} + +// -- Solution -- +pub struct Day; +impl aoc::Solver for Day { + type Output1 = i32; + type Output2 = i32; + + fn day() -> u8 { + 16 + } + + fn part1(input: &str) -> Self::Output1 { + let volcano = Volcano::from_str(input).unwrap(); + + find_best("AA".to_owned(), &volcano, Vec::new(), 30).0 + } + + fn part2(input: &str) -> Self::Output2 { + let volcano = Volcano::from_str(input).unwrap(); + + let time = 26; + + + // This solution is very much a hack + // In the 26 minutes we can not turn on all the valves + // So the player tries to go for the best possible solution before running out of time + // The elephant will then look at the remaining valves and find the best remaing solution + // Problem with this solution is that it assumes we run out of time before opening all + // non-zero valves + // However this is not the case in the example, so it will actually fail the example + // @TODO Implement a proper solution that can also solve the example + let player = find_best("AA".to_owned(), &volcano, Vec::new(), time); + let elephant = find_best("AA".to_owned(), &volcano, player.1, time); + + player.0 + elephant.0 + } +}