day-14.rs (2900B)
1 use std::collections::HashMap;
2 use std::fs::File;
3 use std::io::prelude::*;
4 use std::io::BufReader;
5
6 fn main() {
7 let input = BufReader::new(File::open("input.txt").unwrap())
8 .lines()
9 .map(|line| {
10 let line = line.unwrap();
11 let mut line = line.split(" => ");
12 let mut material = line
13 .next()
14 .unwrap()
15 .split(", ")
16 .map(|term| {
17 let term = term.split(" ").collect::<Vec<_>>();
18 (term[1].to_string(), term[0].parse::<u64>().unwrap())
19 })
20 .collect::<HashMap<_, _>>();
21 let product = line.next().unwrap().split(" ").collect::<Vec<_>>();
22 let product = (product[1].to_string(), product[0].parse::<u64>().unwrap());
23 material.insert(product.0.clone(), product.1);
24 (product.0, material)
25 })
26 .collect::<HashMap<String, HashMap<String, u64>>>();
27 println!("Rust:");
28 println!("Part 1: {}", part_1(&input));
29 println!("Part 2: {}", part_2(&input));
30 }
31
32 fn calc_fuel_cost(recipes: &HashMap<String, HashMap<String, u64>>, fuel_count: u64) -> u64 {
33 let mut chemicals = HashMap::new();
34 chemicals.insert("FUEL".to_string(), fuel_count);
35 let mut leftovers = HashMap::new();
36 let mut ore_count = 0;
37 while !chemicals.is_empty() {
38 let target = chemicals.keys().next().unwrap().to_string();
39 let mut amount = chemicals.remove(&target).unwrap();
40 if target == "ORE" {
41 ore_count += amount;
42 continue;
43 }
44 // Check leftovers before commiting to reaction.
45 let leftover_amount = *leftovers.entry(target.clone()).or_insert(0);
46 *leftovers.get_mut(&target).unwrap() -= amount.min(leftover_amount);
47 amount -= amount.min(leftover_amount);
48 if amount == 0 {
49 continue;
50 }
51 // Initiate new reaction.
52 let recipe = &recipes[&target];
53 let reaction_count = (amount as f64 / recipe[&target] as f64).ceil() as u64;
54 for (k, v) in recipe {
55 if *k != target {
56 *chemicals.entry(k.clone()).or_insert(0) += v * reaction_count;
57 } else {
58 // Place excess product in leftovers.
59 *leftovers.entry(k.clone()).or_insert(0) += v * reaction_count - amount;
60 }
61 }
62 }
63 ore_count
64 }
65
66 fn part_1(input: &HashMap<String, HashMap<String, u64>>) -> u64 {
67 calc_fuel_cost(input, 1)
68 }
69
70 fn part_2(input: &HashMap<String, HashMap<String, u64>>) -> u64 {
71 // Binary search.
72 let ore_cargo = 1000000000000;
73 let mut lo = 1;
74 let mut hi = ore_cargo;
75 while lo + 1 < hi {
76 let mi = lo + (hi - lo) / 2;
77 if calc_fuel_cost(input, mi) > ore_cargo {
78 hi = mi;
79 } else {
80 lo = mi;
81 }
82 }
83 lo
84 }