diff --git a/src/tasks/day14.rs b/src/tasks/day14.rs index af0d8cd..a51cc14 100644 --- a/src/tasks/day14.rs +++ b/src/tasks/day14.rs @@ -1,6 +1,7 @@ use itertools::Itertools; use std::collections::HashMap; +#[allow(dead_code)] pub fn run() { fn parser(s: &str) -> Chemical { let (n, t) = s.split(" ").collect_tuple().unwrap(); @@ -25,6 +26,36 @@ pub fn run() { ) }) .collect(); + task1(&rules); + task2(&rules); +} + +fn task1(rules: &HashMap<&str, (usize, Vec)>) { + println!("Task 1: {} ORE is needed", calc_ore_for_fuel(1, rules)); +} + +fn task2(rules: &HashMap<&str, (usize, Vec)>) { + const ORE_STORAGE: usize = 1_000_000_000_000; + // binary search max fuel + let (max_fuel, _) = std::iter::successors(Some((1, ORE_STORAGE)), |(min, max)| { + if max - min > 1 { + let middle = (max + min) / 2; + let ore = calc_ore_for_fuel(middle, rules); + if ore > ORE_STORAGE { + Some((*min, middle)) + } else { + Some((middle, *max)) + } + } else { + None + } + }) + .last() + .unwrap(); + println!("Task 2: the maximum amount of fuel is {}", max_fuel); +} + +fn calc_ore_for_fuel(fuel: usize, rules: &HashMap<&str, (usize, Vec)>) -> usize { /* The idea is: the rules create a DAG of requirements. We store for every chemical a list of the chemicals that rely on it. @@ -52,7 +83,7 @@ pub fn run() { chem_used_by.insert("FUEL", vec![]); // the amount of a not processed chemical C, which is needed by the chemicals that rely on C let mut requirements = HashMap::<&str, usize>::new(); - requirements.insert("FUEL", 1); + requirements.insert("FUEL", fuel); while let Some((name, amount)) = requirements .iter() .find(|(name, _)| chem_used_by[*name].is_empty() && **name != "ORE") @@ -77,7 +108,7 @@ pub fn run() { } requirements.remove(name); } - println!("Task 1: {} ORE is needed", requirements["ORE"]); + requirements["ORE"] } #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]