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:
parent
ddff0d564d
commit
9c8f23161a
1 changed files with 29 additions and 25 deletions
|
@ -2,9 +2,14 @@ use std::collections::{HashMap, VecDeque};
|
|||
|
||||
type Chemical = usize;
|
||||
|
||||
struct Reagent {
|
||||
id: usize,
|
||||
amount: usize,
|
||||
}
|
||||
|
||||
struct Reaction {
|
||||
input: Vec<(usize, Chemical)>,
|
||||
output: (usize, Chemical),
|
||||
input: Vec<Reagent>,
|
||||
output: Reagent,
|
||||
}
|
||||
|
||||
impl Reaction {
|
||||
|
@ -22,9 +27,12 @@ impl Reaction {
|
|||
assert_eq!(in_components.len()%3, 0);
|
||||
let out_components: Vec<_> = out_str.split(' ').collect();
|
||||
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 {
|
||||
input,
|
||||
|
@ -40,7 +48,7 @@ pub fn run(input: &str) -> (usize, usize) {
|
|||
let ore = chemicals.iter().position(|chem| chem == &String::from("ORE")).unwrap();
|
||||
// dbg!(&chemicals);
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
let mut current = VecDeque::from([(amount, target)]);
|
||||
let mut current = VecDeque::from([Reagent {amount, id: target, }]);
|
||||
let mut leftovers = HashMap::new();
|
||||
|
||||
while !(current.len() == 1 && current[0].1 == raw) {
|
||||
let (next_count, next_chem): (usize, Chemical) = current.pop_front().unwrap();
|
||||
if next_chem == raw {
|
||||
current.push_back((next_count, next_chem));
|
||||
while !(current.len() == 1 && current[0].id == raw) {
|
||||
let next = current.pop_front().unwrap();
|
||||
if next.id == raw {
|
||||
current.push_back(next);
|
||||
continue;
|
||||
}
|
||||
// dbg!(next_chem);
|
||||
let reaction = reactions.iter().find(|r| r.output.1 == next_chem).unwrap();
|
||||
let multiplier = (next_count + reaction.output.0 - 1)/reaction.output.0;
|
||||
*leftovers.entry(next_chem).or_insert(0) += (reaction.output.0 * multiplier).saturating_sub(next_count);
|
||||
// eprintln!("Breaking down {next_count} {next_chem} into");
|
||||
for (input_count, input_chem) in &reaction.input {
|
||||
let mut required = input_count * multiplier;
|
||||
// eprintln!(" {required} {input_chem}");
|
||||
if let Some(left) = leftovers.get_mut(input_chem) {
|
||||
let reaction = reactions.iter().find(|r| r.output.id == next.id).unwrap();
|
||||
let multiplier = (next.amount + reaction.output.amount - 1)/reaction.output.amount;
|
||||
*leftovers.entry(next.id).or_insert(0) += (reaction.output.amount * multiplier).saturating_sub(next.amount);
|
||||
for input in &reaction.input {
|
||||
let mut required = input.amount * multiplier;
|
||||
if let Some(left) = leftovers.get_mut(&input.id) {
|
||||
let consumed = required.min(*left);
|
||||
required -= consumed;
|
||||
*left -= consumed;
|
||||
// eprintln!(" {required} after consuming leftovers. {left} left");
|
||||
}
|
||||
if required > 0 {
|
||||
if let Some(idx) = current.iter().position(|c| c.1 == *input_chem) {
|
||||
current[idx].0 += required;
|
||||
if let Some(idx) = current.iter().position(|c| c.id == input.id) {
|
||||
current[idx].amount += required;
|
||||
} else {
|
||||
current.push_back((required, *input_chem));
|
||||
current.push_back(Reagent { id: input.id, amount: required, });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
current[0].0
|
||||
current[0].amount
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -111,6 +115,6 @@ mod tests {
|
|||
#[test]
|
||||
fn test_challenge() {
|
||||
let challenge_input = read_file("tests/challenge_input");
|
||||
assert_eq!(run(&challenge_input), (1582325, 0));
|
||||
assert_eq!(run(&challenge_input), (1582325, 2267486));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue