advent-of-code

Perserverance, or the lack thereof

git clone git://git.shimmy1996.com/advent-of-code.git

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 }