Compare commits
2 Commits
ccc4301d62
...
0d60232b6f
Author | SHA1 | Date | |
---|---|---|---|
0d60232b6f | |||
a194cb2d6c |
7
day16/Cargo.lock
generated
Normal file
7
day16/Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day16"
|
||||||
|
version = "0.1.0"
|
8
day16/Cargo.toml
Normal file
8
day16/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "day16"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
52
day16/input.txt
Normal file
52
day16/input.txt
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
Valve AP has flow rate=0; tunnels lead to valves AA, ON
|
||||||
|
Valve QN has flow rate=21; tunnels lead to valves RI, CG
|
||||||
|
Valve LK has flow rate=0; tunnels lead to valves XM, AA
|
||||||
|
Valve HA has flow rate=0; tunnels lead to valves WH, KF
|
||||||
|
Valve DS has flow rate=16; tunnel leads to valve II
|
||||||
|
Valve KD has flow rate=0; tunnels lead to valves KG, QB
|
||||||
|
Valve JW has flow rate=0; tunnels lead to valves AD, KF
|
||||||
|
Valve HU has flow rate=0; tunnels lead to valves UK, CO
|
||||||
|
Valve AE has flow rate=10; tunnels lead to valves IR, PT, UV
|
||||||
|
Valve XA has flow rate=0; tunnels lead to valves CG, EU
|
||||||
|
Valve SE has flow rate=17; tunnels lead to valves YR, AD
|
||||||
|
Valve TR has flow rate=0; tunnels lead to valves AL, CS
|
||||||
|
Valve BS has flow rate=0; tunnels lead to valves YH, XM
|
||||||
|
Valve IJ has flow rate=24; tunnels lead to valves XN, WE
|
||||||
|
Valve AA has flow rate=0; tunnels lead to valves LK, AP, IZ, PC, QD
|
||||||
|
Valve KG has flow rate=0; tunnels lead to valves KD, CS
|
||||||
|
Valve QV has flow rate=0; tunnels lead to valves XM, II
|
||||||
|
Valve PC has flow rate=0; tunnels lead to valves AA, YF
|
||||||
|
Valve GJ has flow rate=20; tunnel leads to valve RI
|
||||||
|
Valve UV has flow rate=0; tunnels lead to valves UK, AE
|
||||||
|
Valve IR has flow rate=0; tunnels lead to valves EU, AE
|
||||||
|
Valve EU has flow rate=13; tunnels lead to valves IR, DT, XA, ON
|
||||||
|
Valve ED has flow rate=0; tunnels lead to valves XN, CO
|
||||||
|
Valve DT has flow rate=0; tunnels lead to valves EU, UK
|
||||||
|
Valve YE has flow rate=0; tunnels lead to valves XM, WS
|
||||||
|
Valve AD has flow rate=0; tunnels lead to valves JW, SE
|
||||||
|
Valve WE has flow rate=0; tunnels lead to valves IJ, NA
|
||||||
|
Valve UK has flow rate=5; tunnels lead to valves UV, DT, QD, HU
|
||||||
|
Valve YR has flow rate=0; tunnels lead to valves OS, SE
|
||||||
|
Valve II has flow rate=0; tunnels lead to valves QV, DS
|
||||||
|
Valve GT has flow rate=0; tunnels lead to valves CS, MN
|
||||||
|
Valve YH has flow rate=0; tunnels lead to valves BS, QB
|
||||||
|
Valve BQ has flow rate=0; tunnels lead to valves XM, KF
|
||||||
|
Valve OS has flow rate=0; tunnels lead to valves YR, NA
|
||||||
|
Valve WH has flow rate=0; tunnels lead to valves QB, HA
|
||||||
|
Valve QB has flow rate=4; tunnels lead to valves WH, KD, YH, IZ
|
||||||
|
Valve ON has flow rate=0; tunnels lead to valves AP, EU
|
||||||
|
Valve IZ has flow rate=0; tunnels lead to valves AA, QB
|
||||||
|
Valve MN has flow rate=25; tunnel leads to valve GT
|
||||||
|
Valve CG has flow rate=0; tunnels lead to valves XA, QN
|
||||||
|
Valve QD has flow rate=0; tunnels lead to valves UK, AA
|
||||||
|
Valve AL has flow rate=0; tunnels lead to valves KF, TR
|
||||||
|
Valve XN has flow rate=0; tunnels lead to valves ED, IJ
|
||||||
|
Valve WS has flow rate=0; tunnels lead to valves YE, CS
|
||||||
|
Valve CO has flow rate=18; tunnels lead to valves ED, PT, HU
|
||||||
|
Valve PT has flow rate=0; tunnels lead to valves CO, AE
|
||||||
|
Valve RI has flow rate=0; tunnels lead to valves QN, GJ
|
||||||
|
Valve CS has flow rate=9; tunnels lead to valves YF, GT, WS, TR, KG
|
||||||
|
Valve YF has flow rate=0; tunnels lead to valves PC, CS
|
||||||
|
Valve NA has flow rate=23; tunnels lead to valves OS, WE
|
||||||
|
Valve KF has flow rate=12; tunnels lead to valves HA, AL, JW, BQ
|
||||||
|
Valve XM has flow rate=3; tunnels lead to valves LK, QV, YE, BS, BQ
|
157
day16/src/main.rs
Normal file
157
day16/src/main.rs
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufReader, BufRead};
|
||||||
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
|
use std::cmp::max;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
|
const TIME: u64 = 26;
|
||||||
|
|
||||||
|
fn parse_str<T: FromStr>(str: &str) -> Result<(T, usize), <T as FromStr>::Err> {
|
||||||
|
let mut iter = str.chars().peekable();
|
||||||
|
let mut prefix = String::new();
|
||||||
|
|
||||||
|
while let Some(c) = iter.peek() {
|
||||||
|
if !c.to_string().parse::<T>().is_ok() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prefix.push(iter.next().unwrap());
|
||||||
|
}
|
||||||
|
Ok((prefix.parse::<T>()?, prefix.len()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Valve {
|
||||||
|
rate: u64,
|
||||||
|
links: Vec<(String, u64)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_input(fname: &String) -> Result<HashMap<String, Valve>, <u64 as FromStr>::Err> {
|
||||||
|
let file = File::open(fname).expect("cannot open input file");
|
||||||
|
let lines = BufReader::new(file).lines();
|
||||||
|
let mut valves = HashMap::new();
|
||||||
|
for line in lines.flatten() {
|
||||||
|
let name = String::from(&line[6..=7]);
|
||||||
|
let (rate, rate_len) = parse_str::<u64>(&line[23..])?;
|
||||||
|
let links_str = &line[23 + rate_len + 24..];
|
||||||
|
let mut link = String::new();
|
||||||
|
let mut links = Vec::new();
|
||||||
|
let mut iter = links_str.chars();
|
||||||
|
loop {
|
||||||
|
match iter.next() {
|
||||||
|
Some(' ') | Some(',') => continue,
|
||||||
|
None => break,
|
||||||
|
Some(c) => {
|
||||||
|
link.push(c);
|
||||||
|
link.push(iter.next().unwrap());
|
||||||
|
links.push((link.clone(), 1));
|
||||||
|
link = String::new();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
valves.insert(name, Valve { rate, links });
|
||||||
|
}
|
||||||
|
Ok(valves)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn routes_from(valve: &String, valves: &HashMap<String, Valve>) -> Valve {
|
||||||
|
let mut visited = HashSet::from([valve.clone()]);
|
||||||
|
let mut queue = VecDeque::from([(valve.clone(), 0)]);
|
||||||
|
let mut links = Vec::new();
|
||||||
|
while !queue.is_empty() {
|
||||||
|
let (current_valve, current_cost) = queue.pop_front().unwrap();
|
||||||
|
if current_valve != *valve && valves[¤t_valve].rate > 0 {
|
||||||
|
// +1 because it takes 1min to open a valve
|
||||||
|
links.push((current_valve.clone(), current_cost + 1));
|
||||||
|
}
|
||||||
|
for (next_valve, _) in &valves[¤t_valve].links {
|
||||||
|
if !visited.contains(next_valve) {
|
||||||
|
queue.push_back((next_valve.clone(), current_cost + 1));
|
||||||
|
visited.insert(next_valve.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Valve { rate: valves[valve].rate, links: links }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_map<T1: Debug, T2: Debug>(map: &HashMap<T1, T2>) {
|
||||||
|
for (k, v) in map {
|
||||||
|
println!("{:?}: {:?}", k, v);
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
struct Visited {
|
||||||
|
set: HashSet<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for Visited {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
let l = &mut self.set.iter()
|
||||||
|
.filter(|x| *x != "AA")
|
||||||
|
.cloned().collect::<Vec<String>>();
|
||||||
|
l.sort();
|
||||||
|
l.join("");
|
||||||
|
l.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_pressure_map(valves: &HashMap<String, Valve>) -> HashMap<Visited, u64> {
|
||||||
|
let mut max_pressure: HashMap<Visited, u64> = HashMap::new();
|
||||||
|
let mut queue: VecDeque<(String, u64, u64, Visited)> =
|
||||||
|
VecDeque::from([(
|
||||||
|
String::from("AA"), 0, 0,
|
||||||
|
Visited { set: HashSet::new() },
|
||||||
|
)]);
|
||||||
|
while !queue.is_empty() {
|
||||||
|
let (valve, cost, pressure, visited) = queue.pop_front().unwrap();
|
||||||
|
// println!("{}: {}, {}, {:?}", valve, cost, pressure, visited);
|
||||||
|
if let Some(last_max) = max_pressure.get_mut(&visited) {
|
||||||
|
*last_max = max(*last_max, pressure);
|
||||||
|
} else {
|
||||||
|
max_pressure.insert(visited.clone(), pressure);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (hop, hop_cost) in &valves[&valve].links {
|
||||||
|
let new_cost = cost + hop_cost;
|
||||||
|
if new_cost >= TIME || visited.set.contains(hop) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let new_pressure = pressure + (TIME - new_cost)*valves[hop].rate;
|
||||||
|
let mut new_visited = visited.clone();
|
||||||
|
new_visited.set.insert(hop.clone());
|
||||||
|
queue.push_back((hop.clone(), new_cost, new_pressure, new_visited));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
max_pressure
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let input_fname = env::args().nth(1).expect("need input file");
|
||||||
|
let valves = read_input(&input_fname).expect("parse error");
|
||||||
|
let mut good_valves: HashMap<String, Valve> = HashMap::new();
|
||||||
|
for (name, valve) in &valves {
|
||||||
|
if valve.rate > 0 || name == "AA" {
|
||||||
|
good_valves.insert(name.clone(), routes_from(name, &valves));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print_map(&good_valves);
|
||||||
|
|
||||||
|
let pressure_map = get_pressure_map(&good_valves);
|
||||||
|
// print_map(&pressure_map);
|
||||||
|
println!("pressure_map.len(): {}", pressure_map.len());
|
||||||
|
|
||||||
|
let mut max_pressure = 0;
|
||||||
|
for (visited1, pressure1) in &pressure_map {
|
||||||
|
for (visited2, pressure2) in &pressure_map {
|
||||||
|
if visited1.set.is_disjoint(&visited2.set) {
|
||||||
|
max_pressure = max(max_pressure, pressure1 + pressure2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!(">> {} <<", max_pressure);
|
||||||
|
}
|
||||||
|
|
103
day16/src/main1.rs
Normal file
103
day16/src/main1.rs
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufReader, BufRead};
|
||||||
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
|
use std::cmp::max;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
fn parse_str<T: FromStr>(str: &str) -> Result<(T, usize), <T as FromStr>::Err> {
|
||||||
|
let mut iter = str.chars().peekable();
|
||||||
|
let mut prefix = String::new();
|
||||||
|
|
||||||
|
while let Some(c) = iter.peek() {
|
||||||
|
if !c.to_string().parse::<T>().is_ok() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prefix.push(iter.next().unwrap());
|
||||||
|
}
|
||||||
|
Ok((prefix.parse::<T>()?, prefix.len()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Valve {
|
||||||
|
rate: u64,
|
||||||
|
links: Vec<(String, u64)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_input(fname: &String) -> Result<HashMap<String, Valve>, <u64 as FromStr>::Err> {
|
||||||
|
let file = File::open(fname).expect("cannot open input file");
|
||||||
|
let lines = BufReader::new(file).lines();
|
||||||
|
let mut valves = HashMap::new();
|
||||||
|
for line in lines.flatten() {
|
||||||
|
let name = String::from(&line[6..=7]);
|
||||||
|
let (rate, rate_len) = parse_str::<u64>(&line[23..])?;
|
||||||
|
let links_str = &line[23 + rate_len + 24..];
|
||||||
|
let mut link = String::new();
|
||||||
|
let mut links = Vec::new();
|
||||||
|
let mut iter = links_str.chars();
|
||||||
|
loop {
|
||||||
|
match iter.next() {
|
||||||
|
Some(' ') | Some(',') => continue,
|
||||||
|
None => break,
|
||||||
|
Some(c) => {
|
||||||
|
link.push(c);
|
||||||
|
link.push(iter.next().unwrap());
|
||||||
|
links.push((link.clone(), 1));
|
||||||
|
link = String::new();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
valves.insert(name, Valve { rate, links });
|
||||||
|
}
|
||||||
|
Ok(valves)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn routes_from(valve: &String, valves: &HashMap<String, Valve>) -> Valve {
|
||||||
|
let mut visited = HashSet::from([valve.clone()]);
|
||||||
|
let mut queue = VecDeque::from([(valve.clone(), 0)]);
|
||||||
|
let mut links = Vec::new();
|
||||||
|
while !queue.is_empty() {
|
||||||
|
let (current_valve, current_cost) = queue.pop_front().unwrap();
|
||||||
|
if current_valve != *valve && valves[¤t_valve].rate > 0 {
|
||||||
|
// +1 because it takes 1min to open a valve
|
||||||
|
links.push((current_valve.clone(), current_cost + 1));
|
||||||
|
}
|
||||||
|
for (next_valve, _) in &valves[¤t_valve].links {
|
||||||
|
if !visited.contains(next_valve) {
|
||||||
|
queue.push_back((next_valve.clone(), current_cost + 1));
|
||||||
|
visited.insert(next_valve.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Valve { rate: valves[valve].rate, links: links }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let input_fname = env::args().nth(1).expect("need input file");
|
||||||
|
let valves = read_input(&input_fname).expect("parse error");
|
||||||
|
let mut good_valves = HashMap::new();
|
||||||
|
for (valve_name, valve) in &valves {
|
||||||
|
if valve.rate > 0 || valve_name == "AA" {
|
||||||
|
good_valves.insert(valve_name, routes_from(valve_name, &valves));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut max_pressure = 0;
|
||||||
|
let mut queue: VecDeque<(String, u64, u64, HashSet<_>)> = VecDeque::from([(
|
||||||
|
String::from("AA"), 0, 0, HashSet::from([String::from("AA")]))]);
|
||||||
|
while !queue.is_empty() {
|
||||||
|
let (valve, cost, pressure, visited) = queue.pop_front().unwrap();
|
||||||
|
max_pressure = max(max_pressure, pressure);
|
||||||
|
for (hop, hop_cost) in &good_valves[&valve].links {
|
||||||
|
if cost + hop_cost >= 30 || visited.contains(hop) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let new_cost = cost + hop_cost;
|
||||||
|
let new_pressure = pressure + (30 - new_cost)*valves[hop].rate;
|
||||||
|
let mut new_visited = visited.clone();
|
||||||
|
new_visited.insert(hop.clone());
|
||||||
|
queue.push_back((hop.clone(), new_cost, new_pressure, new_visited));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("Max pressure: {}", max_pressure);
|
||||||
|
}
|
10
day16/test.txt
Normal file
10
day16/test.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
|
Loading…
Reference in New Issue
Block a user