Last active
December 23, 2019 17:40
-
-
Save pr0g/e346b4f34d0a6724a3ca7437db278947 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashMap; | |
use std::fs; | |
#[derive(Debug)] | |
struct Quantity { | |
element: String, | |
count: i64, | |
} | |
#[derive(Debug)] | |
struct Reaction { | |
input: Vec<Quantity>, | |
output: Quantity, | |
} | |
#[derive(Debug, Default)] | |
struct OreDeposits { | |
total: i64, | |
in_use: i64 | |
} | |
impl Quantity { | |
fn new(element: String, count: i64) -> Self { | |
Quantity { element, count } | |
} | |
} | |
impl Reaction { | |
fn new(output: Quantity, input: Vec<Quantity>) -> Self { | |
Reaction { input, output } | |
} | |
} | |
type Buckets = HashMap<String, OreDeposits>; | |
fn main() { | |
let contents = fs::read_to_string("reactions.txt").expect("error"); | |
let reactions = contents | |
.trim() | |
.split('\n') | |
.collect::<Vec<_>>() | |
.iter() | |
.map(|str| str.trim()) | |
.map(|str| str.split("=>").collect::<Vec<_>>()) | |
.map(|vstr| (vstr[0].split(',').collect::<Vec<_>>(), vstr[1])) | |
.map(|tup| { | |
( | |
tup.0.iter().map(|str| str.trim()).collect::<Vec<_>>(), | |
tup.1.split(' ').filter(|x| !x.is_empty()).collect::<Vec<_>>(), | |
) | |
}) | |
.map(|tup| { | |
( | |
tup.0 | |
.iter() | |
.map(|str| str.split(' ').collect::<Vec<_>>()) | |
.collect::<Vec<_>>(), | |
tup.1, | |
) | |
}) | |
.map(|tup| { | |
( | |
tup.0 | |
.iter() | |
.map(|v| (v[0].parse::<i64>().unwrap(), v[1])) | |
.collect::<Vec<_>>(), | |
((tup.1)[0].parse::<i64>().unwrap(), (tup.1)[1]), | |
) | |
}) | |
.map(|tup| { | |
let output = Quantity::new((tup.1).1.to_string(), (tup.1).0); | |
let input = tup | |
.0 | |
.iter() | |
.map(|quantity| Quantity::new(quantity.1.to_string(), quantity.0)) | |
.collect::<Vec<_>>(); | |
Reaction::new(output, input) | |
}) | |
.collect::<Vec<_>>(); | |
fn ore_required( | |
reactions: &[Reaction], | |
element: &str, | |
buckets: &mut Buckets, | |
ore: &mut i64, | |
amount: i64, | |
) { | |
// find the reaction needed for the output | |
if let Some(reaction) = reactions | |
.iter() | |
.find(|&x| x.output.element.as_str() == element) | |
{ | |
for input in &reaction.input { | |
if let Some(b) = buckets.get_mut(&input.element) { | |
if let Some(input_reaction) = reactions | |
.iter() | |
.find(|&x| x.output.element.as_str() == input.element) | |
{ | |
let surplus = b.total - b.in_use; | |
let inputs_needed = input.count * amount - surplus; | |
let reactions_to_run = ((inputs_needed as f64 | |
/ input_reaction.output.count as f64) | |
.ceil()) as i64; | |
let inputs_produced = input_reaction.output.count * reactions_to_run; | |
b.total += inputs_produced; | |
b.in_use += inputs_needed + surplus; | |
if input_reaction.input[0].element.as_str() == "ORE" { | |
*ore += (reactions_to_run as i64) * input_reaction.input[0].count; | |
} else { | |
ore_required(reactions, &input.element, buckets, ore, reactions_to_run); | |
} | |
} | |
} | |
} | |
} | |
} | |
// part 1 | |
{ | |
let mut buckets = Buckets::new(); | |
for reaction in &reactions { | |
buckets.insert(reaction.output.element.to_string(), OreDeposits::default()); | |
} | |
let mut ore = 0; | |
ore_required(&reactions, "FUEL", &mut buckets, &mut ore, 1); | |
println!("part 1 - {:?}", ore); | |
} | |
// part 2 | |
{ | |
let target = 1_000_000_000_000; | |
let mut min_fuel = 1000; | |
let mut max_fuel = 10000000; | |
let mut fuel = 0; | |
// <= to return fuel for value smaller than one trillion | |
while min_fuel <= max_fuel { | |
// reset buckets | |
let mut buckets = Buckets::new(); | |
for reaction in &reactions { | |
buckets.insert(reaction.output.element.to_string(), OreDeposits::default()); | |
} | |
fuel = min_fuel + (max_fuel - min_fuel) / 2; | |
let mut ore = 0; | |
ore_required(&reactions, "FUEL", &mut buckets, &mut ore, fuel); | |
if fuel == ore { | |
break; | |
} | |
if ore < target { | |
min_fuel = fuel + 1; | |
} else { | |
max_fuel = fuel - 1 | |
} | |
} | |
println!("part 2 - {:?}", fuel); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment