day 14 task 1
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
mod tasks;
|
||||
|
||||
fn main() {
|
||||
tasks::day13::run();
|
||||
tasks::day14::run();
|
||||
}
|
||||
|
||||
84
src/tasks/day14.rs
Normal file
84
src/tasks/day14.rs
Normal 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);
|
||||
@@ -10,3 +10,4 @@ pub mod day10;
|
||||
pub mod day11;
|
||||
pub mod day12;
|
||||
pub mod day13;
|
||||
pub mod day14;
|
||||
|
||||
Reference in New Issue
Block a user