day 14 task 1

This commit is contained in:
Johannes
2019-12-14 21:29:36 +01:00
parent 9a2531b982
commit 83dce003d8
4 changed files with 140 additions and 1 deletions

View File

@@ -1,5 +1,5 @@
mod tasks;
fn main() {
tasks::day13::run();
tasks::day14::run();
}

84
src/tasks/day14.rs Normal file
View File

@@ -0,0 +1,84 @@
use itertools::Itertools;
use std::collections::HashMap;
pub fn run() {
fn parser(s: &str) -> Chemical {
let (n, t) = s.split(" ").collect_tuple().unwrap();
Chemical(n.parse().unwrap(), t)
}
let text = std::fs::read_to_string("input/day14.txt").unwrap();
// maps from a chemical to the chemicals required to create it
let rules: HashMap<_, _> = text
.lines()
.map(|line| {
let (left, right) = line
.split("=>")
.map(|it| it.trim())
.collect_tuple()
.unwrap();
(
parser(right).1,
(
parser(right).0,
left.split(",").map(|it| parser(it.trim())).collect_vec(),
),
)
})
.collect();
/*
The idea is: the rules create a DAG of requirements.
We store for every chemical a list of the chemicals that rely on it.
We create a mapping from the chemicals to the amount of the chemicals needed
by its already processed ancestors in the rule DAG.
Then we process all chemicals C, starting with "FUEL", of which all ancestors are already
processed. That means, that our mapping of the amounts stores the correct sum of what is
needed of the chemical (we round that up, so it matches the amount given on the right
hand rule side). We then calculate, using the rules, how much of other chemicals C' we need
to produce the desired amount. We add up the amount of the required children C' in
`requirements`. We then remove C from the chem_used_by list of C'.
Once a chemical has an empty used_by list it is ready for processing.
*/
// maps for every chemical to the ones using it
let mut chem_used_by: HashMap<&str, Vec<&str>> =
rules
.iter()
.fold(HashMap::new(), |mut map, (result, (_, ingredients))| {
ingredients.iter().for_each(|Chemical(_, ingredient)| {
map.entry(&ingredient).or_insert(vec![]).push(result)
});
map
});
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);
while let Some((name, amount)) = requirements
.iter()
.find(|(name, _)| chem_used_by[*name].is_empty() && **name != "ORE")
{
// needed to remove immutable borrow of `requirements` from above
let name = *name;
let amount = *amount;
let (reaction_size, req_vec) = &rules
.get(&name)
.expect(&format!("unknown chemical in rules: {}", name));
let demand = if amount % reaction_size == 0 {
amount / reaction_size
} else {
amount / reaction_size + 1
};
for Chemical(req_amount, req_name) in req_vec {
chem_used_by
.get_mut(req_name)
.unwrap()
.retain(|x| *x != name);
*requirements.entry(req_name).or_insert(0) += demand * req_amount;
}
requirements.remove(name);
}
println!("Task 1: {} ORE is needed", requirements["ORE"]);
}
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
struct Chemical<'a>(usize, &'a str);

View File

@@ -10,3 +10,4 @@ pub mod day10;
pub mod day11;
pub mod day12;
pub mod day13;
pub mod day14;