2019 day 14 cleanup: introduced a proper data type for amount-chemical pairs; removed debug instructions; inserted the correct result in the challenge test

This commit is contained in:
Chris Alge 2023-03-13 17:25:10 +01:00
parent ddff0d564d
commit 9c8f23161a

View file

@ -2,9 +2,14 @@ use std::collections::{HashMap, VecDeque};
type Chemical = usize; type Chemical = usize;
struct Reagent {
id: usize,
amount: usize,
}
struct Reaction { struct Reaction {
input: Vec<(usize, Chemical)>, input: Vec<Reagent>,
output: (usize, Chemical), output: Reagent,
} }
impl Reaction { impl Reaction {
@ -22,9 +27,12 @@ impl Reaction {
assert_eq!(in_components.len()%3, 0); assert_eq!(in_components.len()%3, 0);
let out_components: Vec<_> = out_str.split(' ').collect(); let out_components: Vec<_> = out_str.split(' ').collect();
assert_eq!(out_components.len(), 2); assert_eq!(out_components.len(), 2);
let output = (out_components[0].parse().unwrap(), get_chemical(out_components[1])); let output = Reagent {
id: get_chemical(out_components[1]),
amount: out_components[0].parse().unwrap(),
};
let input = in_components.chunks(3).map(|c| (c[0].parse::<usize>().unwrap(), get_chemical(c[1]))).collect(); let input = in_components.chunks(3).map(|c| Reagent { id: get_chemical(c[1]), amount: c[0].parse::<usize>().unwrap(), }).collect();
Self { Self {
input, input,
@ -40,7 +48,7 @@ pub fn run(input: &str) -> (usize, usize) {
let ore = chemicals.iter().position(|chem| chem == &String::from("ORE")).unwrap(); let ore = chemicals.iter().position(|chem| chem == &String::from("ORE")).unwrap();
// dbg!(&chemicals); // dbg!(&chemicals);
let first = break_down(&reactions, fuel, ore, 1); let first = break_down(&reactions, fuel, ore, 1);
let second = bisection_find(1000000000000/first, 10000000000000/first, &reactions, fuel, ore, 1000000000000); let second = bisection_find(1_000_000_000_000/first, 10_000_000_000_000/first, &reactions, fuel, ore, 1_000_000_000_000);
(first, second) (first, second)
} }
@ -58,39 +66,35 @@ fn bisection_find(lower: usize, upper: usize, reactions: &[Reaction], target: us
} }
fn break_down(reactions: &[Reaction], target: Chemical, raw: Chemical, amount: usize) -> usize { fn break_down(reactions: &[Reaction], target: Chemical, raw: Chemical, amount: usize) -> usize {
let mut current = VecDeque::from([(amount, target)]); let mut current = VecDeque::from([Reagent {amount, id: target, }]);
let mut leftovers = HashMap::new(); let mut leftovers = HashMap::new();
while !(current.len() == 1 && current[0].1 == raw) { while !(current.len() == 1 && current[0].id == raw) {
let (next_count, next_chem): (usize, Chemical) = current.pop_front().unwrap(); let next = current.pop_front().unwrap();
if next_chem == raw { if next.id == raw {
current.push_back((next_count, next_chem)); current.push_back(next);
continue; continue;
} }
// dbg!(next_chem); let reaction = reactions.iter().find(|r| r.output.id == next.id).unwrap();
let reaction = reactions.iter().find(|r| r.output.1 == next_chem).unwrap(); let multiplier = (next.amount + reaction.output.amount - 1)/reaction.output.amount;
let multiplier = (next_count + reaction.output.0 - 1)/reaction.output.0; *leftovers.entry(next.id).or_insert(0) += (reaction.output.amount * multiplier).saturating_sub(next.amount);
*leftovers.entry(next_chem).or_insert(0) += (reaction.output.0 * multiplier).saturating_sub(next_count); for input in &reaction.input {
// eprintln!("Breaking down {next_count} {next_chem} into"); let mut required = input.amount * multiplier;
for (input_count, input_chem) in &reaction.input { if let Some(left) = leftovers.get_mut(&input.id) {
let mut required = input_count * multiplier;
// eprintln!(" {required} {input_chem}");
if let Some(left) = leftovers.get_mut(input_chem) {
let consumed = required.min(*left); let consumed = required.min(*left);
required -= consumed; required -= consumed;
*left -= consumed; *left -= consumed;
// eprintln!(" {required} after consuming leftovers. {left} left");
} }
if required > 0 { if required > 0 {
if let Some(idx) = current.iter().position(|c| c.1 == *input_chem) { if let Some(idx) = current.iter().position(|c| c.id == input.id) {
current[idx].0 += required; current[idx].amount += required;
} else { } else {
current.push_back((required, *input_chem)); current.push_back(Reagent { id: input.id, amount: required, });
} }
} }
} }
} }
current[0].0 current[0].amount
} }
#[cfg(test)] #[cfg(test)]
@ -111,6 +115,6 @@ mod tests {
#[test] #[test]
fn test_challenge() { fn test_challenge() {
let challenge_input = read_file("tests/challenge_input"); let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input), (1582325, 0)); assert_eq!(run(&challenge_input), (1582325, 2267486));
} }
} }