aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs196
1 files changed, 195 insertions, 1 deletions
diff --git a/src/main.rs b/src/main.rs
index 9b7e3f7..a8e6819 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1209,8 +1209,129 @@ fn day13() {
println!("13b: {}", arcade.score);
}
+struct Reaction {
+ result: String,
+ amount: isize,
+ resources: HashMap<String, isize>,
+}
+
+impl Reaction {
+ fn split_amount_material(input: &str) -> (isize, String) {
+ let splitted: Vec<&str> = input.split(' ').collect();
+ assert_eq!(splitted.len(), 2);
+ (splitted[0].parse::<isize>().unwrap(), splitted[1].to_string())
+ }
+
+ fn parse(input: &str) -> Reaction {
+ let reaction: Vec<&str> = input.split(" => ").collect();
+ let (amount, result) = Reaction::split_amount_material(reaction[1]);
+ let required = reaction[0].split(", ");
+ let mut resources = HashMap::new();
+ for resource in required {
+ let (amount, material) = Reaction::split_amount_material(resource);
+ resources.insert(material, amount);
+ }
+
+ Reaction {
+ result,
+ amount,
+ resources,
+ }
+ }
+}
+
+struct Reactions {
+ reactions: HashMap<String, Reaction>,
+}
+
+impl Reactions {
+ const ORE_LIMIT: isize = 1_000_000_000_000;
+
+ fn parse(input: &str) -> Reactions {
+ let mut reactions = HashMap::new();
+ let input = input.trim_end();
+
+ for line in input.split('\n') {
+ let reaction = Reaction::parse(line);
+ reactions.insert(reaction.result.clone(), reaction);
+ }
+ Reactions { reactions }
+ }
+
+ fn count_material_(&self, amount_requested: isize, output: &str, leftovers: &mut HashMap<String, isize>, total_ore_count: &mut isize) -> Result<isize, ()> {
+ if output == "ORE" {
+ if *total_ore_count + amount_requested > Reactions::ORE_LIMIT {
+ return Err(());
+ }
+ *total_ore_count += amount_requested;
+ return Ok(amount_requested);
+ }
+ let mut amount_requested = amount_requested;
+
+ /* use up leftover materials first */
+ let leftover = *leftovers.entry(output.to_string()).or_insert(0);
+ if leftover >= amount_requested {
+ leftovers.insert(output.to_string(), leftover - amount_requested);
+ /* no additional reaction needed, can satisfy with leftovers */
+ return Ok(0);
+ } else {
+ leftovers.insert(output.to_string(), 0);
+ amount_requested -= leftover;
+ }
+
+ let reaction = self.reactions.get(output).unwrap();
+ let mut factor = amount_requested / reaction.amount;
+ if amount_requested % reaction.amount > 0 {
+ factor += 1;
+ }
+ let produced = factor * reaction.amount;
+ leftovers.insert(output.to_string(), produced - amount_requested);
+
+ let mut ore_count = 0;
+ for resource in reaction.resources.keys() {
+ let amount = *reaction.resources.get(resource).unwrap();
+ ore_count += self.count_material_(amount * factor, &resource, leftovers, total_ore_count)?;
+ }
+
+ Ok(ore_count)
+ }
+
+ fn count_material(&self, amount_requested: isize, output: &str, ) -> isize {
+ let mut ore_count = 0;
+ self.count_material_(amount_requested, output, &mut HashMap::new(), &mut ore_count).unwrap()
+ }
+
+ fn possible_fuel(&self) -> isize {
+ let mut leftovers = HashMap::new();
+ let mut ore_count = 0;
+
+ let mut fuel_count = 1;
+ let ore_per_fuel = self.count_material_(1, "FUEL", &mut leftovers, &mut ore_count).unwrap();
+
+ fuel_count += Reactions::ORE_LIMIT / ore_per_fuel;
+ self.count_material_(Reactions::ORE_LIMIT / ore_per_fuel, "FUEL", &mut leftovers, &mut ore_count).unwrap();
+ loop {
+ match self.count_material_(1, "FUEL", &mut leftovers, &mut ore_count) {
+ Ok(_) => fuel_count += 1,
+ Err(_) => break,
+ };
+ }
+ fuel_count
+ }
+
+}
+
+fn day14() {
+ let input = read_file("input14");
+ let reactions = Reactions::parse(&input);
+
+ println!("14a: {}", reactions.count_material(1, "FUEL"));
+
+ println!("14b: {}", reactions.possible_fuel());
+}
+
fn main() {
- day13();
+ day14();
}
#[cfg(test)]
@@ -1415,4 +1536,77 @@ mod tests {
assert_eq!(asteroid_map.vaporized(max.0, 200), Point { x: 8, y: 2 });
}
+
+ #[test]
+ fn test_day14() {
+ let input = "10 ORE => 10 A\n\
+ 1 ORE => 1 B\n\
+ 7 A, 1 B => 1 C\n\
+ 7 A, 1 C => 1 D\n\
+ 7 A, 1 D => 1 E\n\
+ 7 A, 1 E => 1 FUEL";
+ let reactions = Reactions::parse(input);
+ assert_eq!(reactions.count_material(1, "FUEL"), 31);
+
+ let input = "9 ORE => 2 A\n\
+ 8 ORE => 3 B\n\
+ 7 ORE => 5 C\n\
+ 3 A, 4 B => 1 AB\n\
+ 5 B, 7 C => 1 BC\n\
+ 4 C, 1 A => 1 CA\n\
+ 2 AB, 3 BC, 4 CA => 1 FUEL";
+ let reactions = Reactions::parse(input);
+ assert_eq!(reactions.count_material(1, "FUEL"), 165);
+
+
+ let input = "157 ORE => 5 NZVS\n\
+ 165 ORE => 6 DCFZ\n\
+ 44 XJWVT, 5 KHKGT, 1 QDVJ, 29 NZVS, 9 GPVTF, 48 HKGWZ => 1 FUEL\n\
+ 12 HKGWZ, 1 GPVTF, 8 PSHF => 9 QDVJ\n\
+ 179 ORE => 7 PSHF\n\
+ 177 ORE => 5 HKGWZ\n\
+ 7 DCFZ, 7 PSHF => 2 XJWVT\n\
+ 165 ORE => 2 GPVTF\n\
+ 3 DCFZ, 7 NZVS, 5 HKGWZ, 10 PSHF => 8 KHKGT";
+ let reactions = Reactions::parse(input);
+ assert_eq!(reactions.count_material(1, "FUEL"), 13312);
+ //assert_eq!(reactions.possible_fuel(), 82892753);
+
+ let input = "2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG\n\
+ 17 NVRVD, 3 JNWZP => 8 VPVL\n\
+ 53 STKFG, 6 MNCFX, 46 VJHF, 81 HVMC, 68 CXFTF, 25 GNMV => 1 FUEL\n\
+ 22 VJHF, 37 MNCFX => 5 FWMGM\n\
+ 139 ORE => 4 NVRVD\n\
+ 144 ORE => 7 JNWZP\n\
+ 5 MNCFX, 7 RFSQX, 2 FWMGM, 2 VPVL, 19 CXFTF => 3 HVMC\n\
+ 5 VJHF, 7 MNCFX, 9 VPVL, 37 CXFTF => 6 GNMV\n\
+ 145 ORE => 6 MNCFX\n\
+ 1 NVRVD => 8 CXFTF\n\
+ 1 VJHF, 6 MNCFX => 4 RFSQX\n\
+ 176 ORE => 6 VJHF";
+ let reactions = Reactions::parse(input);
+ assert_eq!(reactions.count_material(1, "FUEL"), 180697);
+ //assert_eq!(reactions.possible_fuel(), 5586022);
+
+ let input = "171 ORE => 8 CNZTR\n\
+ 7 ZLQW, 3 BMBT, 9 XCVML, 26 XMNCP, 1 WPTQ, 2 MZWV, 1 RJRHP => 4 PLWSL\n\
+ 114 ORE => 4 BHXH\n\
+ 14 VRPVC => 6 BMBT\n\
+ 6 BHXH, 18 KTJDG, 12 WPTQ, 7 PLWSL, 31 FHTLT, 37 ZDVW => 1 FUEL\n\
+ 6 WPTQ, 2 BMBT, 8 ZLQW, 18 KTJDG, 1 XMNCP, 6 MZWV, 1 RJRHP => 6 FHTLT\n\
+ 15 XDBXC, 2 LTCX, 1 VRPVC => 6 ZLQW\n\
+ 13 WPTQ, 10 LTCX, 3 RJRHP, 14 XMNCP, 2 MZWV, 1 ZLQW => 1 ZDVW\n\
+ 5 BMBT => 4 WPTQ\n\
+ 189 ORE => 9 KTJDG\n\
+ 1 MZWV, 17 XDBXC, 3 XCVML => 2 XMNCP\n\
+ 12 VRPVC, 27 CNZTR => 2 XDBXC\n\
+ 15 KTJDG, 12 BHXH => 5 XCVML\n\
+ 3 BHXH, 2 VRPVC => 7 MZWV\n\
+ 121 ORE => 7 VRPVC\n\
+ 7 XCVML => 6 RJRHP\n\
+ 5 BHXH, 4 VRPVC => 5 LTCX";
+ let reactions = Reactions::parse(input);
+ assert_eq!(reactions.count_material(1, "FUEL"), 2210736);
+ //assert_eq!(reactions.possible_fuel(), 460664);
+ }
}