|
1 |
| -use ::day_14::{parse_input, Item}; |
2 |
| -use std::collections::{HashMap, LinkedList}; |
| 1 | +use ::day_14::{parse_input, to_map, Item, Output}; |
| 2 | +use std::{collections::HashMap, mem::replace}; |
3 | 3 |
|
4 |
| -#[derive(Clone, Eq, PartialEq, Hash, Debug)] |
5 |
| -struct Output { |
6 |
| - pub quantity: u8, |
7 |
| - pub required: Vec<Item>, |
8 |
| -} |
| 4 | +fn get_requirements(reactions: &HashMap<String, Output>, quantity: i64) -> i64 { |
| 5 | + let mut reserves: HashMap<String, i64> = HashMap::new(); |
| 6 | + let mut required = HashMap::new(); |
| 7 | + required.insert("FUEL".to_owned(), quantity.to_owned()); |
9 | 8 |
|
10 |
| -fn to_map(input: &Vec<(Item, Vec<Item>)>) -> HashMap<String, Output> { |
11 |
| - let mut map = HashMap::new(); |
12 |
| - |
13 |
| - for (key, value) in input { |
14 |
| - map.insert( |
15 |
| - key.0.to_owned(), |
16 |
| - Output { |
17 |
| - quantity: key.1, |
18 |
| - required: value.to_owned(), |
19 |
| - }, |
20 |
| - ); |
21 |
| - } |
| 9 | + while required.len() != 1 || !required.contains_key("ORE") { |
| 10 | + let mut new_rec = HashMap::new(); |
22 | 11 |
|
23 |
| - map |
24 |
| -} |
| 12 | + for (chemical, quantity) in required.clone() { |
| 13 | + if chemical == "ORE" { |
| 14 | + *new_rec.entry("ORE".to_owned()).or_insert(0) += quantity.to_owned(); |
| 15 | + continue; |
| 16 | + } |
| 17 | + |
| 18 | + let quantity = quantity as f64; |
| 19 | + let reaction = reactions.get(&chemical).unwrap(); |
| 20 | + let reaction_quantity = reaction.quantity.to_owned() as f64; |
| 21 | + let reserve_ref = reserves.entry(chemical.to_owned()).or_insert(0); |
| 22 | + let reserve = reserve_ref.to_owned() as f64; |
| 23 | + let reaction_count = (quantity - reserve) / reaction_quantity; |
| 24 | + let reaction_count = reaction_count.ceil() as f64; |
25 | 25 |
|
26 |
| -fn get_requirements(map: &HashMap<String, Output>) -> Vec<Vec<String>> { |
27 |
| - let fuel = &map.get("FUEL").unwrap(); |
28 |
| - let mut paths = vec![]; |
29 |
| - for item in &fuel.required { |
30 |
| - let mut req = LinkedList::new(); |
31 |
| - req.push_front((item.clone(), vec![item.0.to_owned()])); |
32 |
| - while req.len() > 0 { |
33 |
| - if let Some(((key, _value), tree)) = req.pop_back() { |
34 |
| - match map.get(&key) { |
35 |
| - Some(item) => { |
36 |
| - for required in &item.required { |
37 |
| - let mut tree = tree.clone(); |
38 |
| - if !tree.contains(&key) { |
39 |
| - tree.insert(0, key.to_owned()); |
40 |
| - } |
41 |
| - if !tree.contains(&required.0) { |
42 |
| - tree.insert(0, required.0.to_owned()); |
43 |
| - } |
44 |
| - req.push_back((required.clone(), tree.to_owned())); |
45 |
| - } |
46 |
| - } |
47 |
| - None => paths.push(tree.clone()), |
48 |
| - }; |
49 |
| - }; |
| 26 | + for (ingredient, amount) in &reaction.required { |
| 27 | + let ingredient_ref = new_rec.entry(ingredient.to_owned()).or_insert(0); |
| 28 | + let ingredient_pre = ingredient_ref.to_owned() as f64; |
| 29 | + let amount = amount.to_owned() as f64; |
| 30 | + |
| 31 | + *ingredient_ref = (ingredient_pre + reaction_count * amount) as i64; |
| 32 | + } |
| 33 | + |
| 34 | + *reserve_ref = (reserve + reaction_count * reaction_quantity - quantity).ceil() as i64; |
50 | 35 | }
|
| 36 | + |
| 37 | + required = replace(&mut new_rec, HashMap::new()); |
51 | 38 | }
|
52 | 39 |
|
53 |
| - paths |
| 40 | + required.entry("ORE".to_owned()).or_insert(0).to_owned() |
54 | 41 | }
|
55 | 42 |
|
56 |
| -fn part_01(input: &Vec<(Item, Vec<Item>)>) -> u32 { |
57 |
| - let map = to_map(input); |
58 |
| - let requirements = get_requirements(&map); |
| 43 | +type Input = Vec<(Item, Vec<Item>)>; |
59 | 44 |
|
60 |
| - for req in requirements { |
61 |
| - println!("{:?}", req); |
| 45 | +fn part_01(input: &Input) -> i64 { |
| 46 | + get_requirements(&to_map(input), 1) |
| 47 | +} |
| 48 | + |
| 49 | +fn part_02(input: &Input) -> i64 { |
| 50 | + let map = to_map(input); |
| 51 | + let total_ore: i64 = 1_000_000_000_000; |
| 52 | + let mut new_estimate = ((total_ore as f64) / (get_requirements(&map, 1) as f64)).floor() as i64; |
| 53 | + let mut estimate = 0; |
| 54 | + while new_estimate > estimate { |
| 55 | + estimate = new_estimate.to_owned(); |
| 56 | + let needed = get_requirements(&map, estimate.to_owned()); |
| 57 | + new_estimate = ((estimate as f64) * (total_ore as f64) / (needed as f64)).floor() as i64; |
62 | 58 | }
|
63 |
| - 0 |
| 59 | + |
| 60 | + estimate |
64 | 61 | }
|
65 | 62 |
|
66 | 63 | fn main() {
|
67 | 64 | let input = parse_input(include_str!("../../input/day_14"));
|
68 | 65 | println!("part_01: {}", part_01(&input));
|
| 66 | + println!("part_02: {:?}", part_02(&input)); |
69 | 67 | }
|
70 | 68 |
|
71 | 69 | #[cfg(test)]
|
@@ -137,4 +135,11 @@ mod tests {
|
137 | 135 | assert_eq!(part_01(&parse_input(&EXAMPLE_03)), 180697);
|
138 | 136 | assert_eq!(part_01(&parse_input(&EXAMPLE_04)), 2210736);
|
139 | 137 | }
|
| 138 | + |
| 139 | + #[test] |
| 140 | + fn it_gets_same_same_results_as_the_second_part() { |
| 141 | + assert_eq!(part_02(&parse_input(&EXAMPLE_02)), 82892753); |
| 142 | + assert_eq!(part_02(&parse_input(&EXAMPLE_03)), 5586022); |
| 143 | + assert_eq!(part_02(&parse_input(&EXAMPLE_04)), 460664); |
| 144 | + } |
140 | 145 | }
|
0 commit comments