diff --git a/day16/src/main.rs b/day16/src/main.rs index 17b2a27..2d47ced 100644 --- a/day16/src/main.rs +++ b/day16/src/main.rs @@ -4,6 +4,10 @@ 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(str: &str) -> Result<(T, usize), ::Err> { let mut iter = str.chars().peekable(); @@ -72,32 +76,82 @@ fn routes_from(valve: &String, valves: &HashMap) -> Valve { 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)); - } +fn print_map(map: &HashMap) { + for (k, v) in map { + println!("{:?}: {:?}", k, v); } + println!(""); +} - 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")]))]); +#[derive(Debug, Eq, PartialEq, Clone)] +struct Visited { + set: HashSet, +} + +impl Hash for Visited { + fn hash(&self, state: &mut H) { + let l = &mut self.set.iter() + .filter(|x| *x != "AA") + .cloned().collect::>(); + l.sort(); + l.join(""); + l.hash(state); + } +} + +fn get_pressure_map(valves: &HashMap) -> HashMap { + let mut max_pressure: HashMap = 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(); - max_pressure = max(max_pressure, pressure); - for (hop, hop_cost) in &good_valves[&valve].links { - if cost + hop_cost >= 30 || visited.contains(hop) { + // 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_cost = cost + hop_cost; - let new_pressure = pressure + (30 - new_cost)*valves[hop].rate; + let new_pressure = pressure + (TIME - new_cost)*valves[hop].rate; let mut new_visited = visited.clone(); - new_visited.insert(hop.clone()); + new_visited.set.insert(hop.clone()); queue.push_back((hop.clone(), new_cost, new_pressure, new_visited)); } } - println!("Max pressure: {}", max_pressure); + 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 = 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); +} + diff --git a/day16/src/main1.rs b/day16/src/main1.rs new file mode 100644 index 0000000..17b2a27 --- /dev/null +++ b/day16/src/main1.rs @@ -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(str: &str) -> Result<(T, usize), ::Err> { + let mut iter = str.chars().peekable(); + let mut prefix = String::new(); + + while let Some(c) = iter.peek() { + if !c.to_string().parse::().is_ok() { + break; + } + prefix.push(iter.next().unwrap()); + } + Ok((prefix.parse::()?, prefix.len())) +} + +#[derive(Debug)] +struct Valve { + rate: u64, + links: Vec<(String, u64)>, +} + +fn read_input(fname: &String) -> Result, ::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::(&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) -> 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); +}