2019: day14: finish
This commit is contained in:
parent
03d248cf9c
commit
aaaaadd901
|
@ -13,6 +13,7 @@ use aoc2019::day10;
|
||||||
use aoc2019::day11;
|
use aoc2019::day11;
|
||||||
use aoc2019::day12;
|
use aoc2019::day12;
|
||||||
use aoc2019::day13;
|
use aoc2019::day13;
|
||||||
|
use aoc2019::day14;
|
||||||
|
|
||||||
fn aoc2019_all(c: &mut Criterion) {
|
fn aoc2019_all(c: &mut Criterion) {
|
||||||
c.bench_function("day01", |b| b.iter(|| day01::run().unwrap()));
|
c.bench_function("day01", |b| b.iter(|| day01::run().unwrap()));
|
||||||
|
@ -28,6 +29,7 @@ fn aoc2019_all(c: &mut Criterion) {
|
||||||
c.bench_function("day11", |b| b.iter(|| day11::run().unwrap()));
|
c.bench_function("day11", |b| b.iter(|| day11::run().unwrap()));
|
||||||
c.bench_function("day12", |b| b.iter(|| day12::run().unwrap()));
|
c.bench_function("day12", |b| b.iter(|| day12::run().unwrap()));
|
||||||
c.bench_function("day13", |b| b.iter(|| day13::run().unwrap()));
|
c.bench_function("day13", |b| b.iter(|| day13::run().unwrap()));
|
||||||
|
c.bench_function("day14", |b| b.iter(|| day14::run().unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
criterion_group! {
|
criterion_group! {
|
||||||
|
|
62
aoc2019/input/day14.txt
Normal file
62
aoc2019/input/day14.txt
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
4 BFNQL => 9 LMCRF
|
||||||
|
2 XGWNS, 7 TCRNC => 5 TPZCH
|
||||||
|
4 RKHMQ, 1 QHRG, 5 JDSNJ => 4 XGWNS
|
||||||
|
6 HWTBC, 4 XGWNS => 6 CWCD
|
||||||
|
1 BKPZH, 2 FLZX => 9 HWFQG
|
||||||
|
1 GDVD, 2 HTSW => 8 CNQW
|
||||||
|
2 RMDG => 9 RKHMQ
|
||||||
|
3 RTLHZ => 3 MSKWT
|
||||||
|
1 QLNHG, 1 RJHCP => 3 GRDJ
|
||||||
|
10 DLSD, 2 SWKHJ, 15 HTSW => 1 TCRNC
|
||||||
|
4 SWKHJ, 24 ZHDSD, 2 DLSD => 3 CPGJ
|
||||||
|
1 SWKHJ => 1 THJHK
|
||||||
|
129 ORE => 8 KLSMQ
|
||||||
|
3 SLNKW, 4 RTLHZ => 4 LPVGC
|
||||||
|
1 SLNKW => 5 RLGFX
|
||||||
|
2 QHRG, 1 SGMK => 8 RJHCP
|
||||||
|
9 RGKCF, 7 QHRG => 6 ZHDSD
|
||||||
|
8 XGWNS, 1 CPGJ => 2 QLNHG
|
||||||
|
2 MQFJF, 7 TBVH, 7 FZXS => 2 WZMRW
|
||||||
|
13 ZHDSD, 11 SLNKW, 18 RJHCP => 2 CZJR
|
||||||
|
1 CNQW, 5 GRDJ, 3 GDVD => 4 FLZX
|
||||||
|
129 ORE => 4 RHSHR
|
||||||
|
2 HWTBC, 2 JDSNJ => 8 QPBHG
|
||||||
|
1 BKPZH, 8 SWKHJ => 6 WSWBV
|
||||||
|
8 RJHCP, 7 FRGJK => 1 GSDT
|
||||||
|
6 QPBHG => 4 BKPZH
|
||||||
|
17 PCRQV, 6 BFNQL, 9 GSDT, 10 MQDHX, 1 ZHDSD, 1 GRDJ, 14 BRGXB, 3 RTLHZ => 8 CFGK
|
||||||
|
8 RMDG => 6 SGMK
|
||||||
|
3 CZJR => 8 RTLHZ
|
||||||
|
3 BFRTV => 7 RGKCF
|
||||||
|
6 FRGJK, 8 CZJR, 4 GRDJ => 4 BRGXB
|
||||||
|
4 VRVGB => 7 PCRQV
|
||||||
|
4 TCRNC, 1 TBVH, 2 FZXS, 1 BQGM, 1 THJHK, 19 RLGFX => 2 CRJTJ
|
||||||
|
5 RDNJK => 6 SWKHJ
|
||||||
|
2 FLVC, 2 SLNKW, 30 HWTBC => 8 DLSD
|
||||||
|
6 TBVH, 3 ZHDSD => 5 BQGM
|
||||||
|
17 RLGFX => 4 SCZQN
|
||||||
|
8 SWKHJ => 6 FZXS
|
||||||
|
9 LZHZ => 3 QDCL
|
||||||
|
2 ZHDSD => 1 RDNJK
|
||||||
|
15 FZXS, 3 TPZCH => 6 MQFJF
|
||||||
|
12 RLGFX, 9 QPBHG, 6 HTSW => 1 BFNQL
|
||||||
|
150 ORE => 9 BFRTV
|
||||||
|
2 BFRTV, 2 KLSMQ => 2 RMDG
|
||||||
|
4 VFLNM, 30 RKHMQ, 4 CRJTJ, 24 CFGK, 21 SCZQN, 4 BMGBG, 9 HWFQG, 34 CWCD, 7 LPVGC, 10 QDCL, 2 WSWBV, 2 WTZX => 1 FUEL
|
||||||
|
6 RHSHR, 3 RGKCF, 1 QHRG => 6 JDSNJ
|
||||||
|
3 MQDHX, 2 XGWNS, 12 GRDJ => 9 LZHZ
|
||||||
|
128 ORE => 6 ZBWLC
|
||||||
|
9 JDSNJ, 7 RMDG => 8 FLVC
|
||||||
|
4 DLSD, 12 CZJR, 3 MSKWT => 4 MQDHX
|
||||||
|
2 BXNX, 4 ZBWLC => 3 QHRG
|
||||||
|
19 LMCRF, 3 JDSNJ => 2 BMGBG
|
||||||
|
1 RJHCP, 26 SGMK => 9 HTSW
|
||||||
|
2 QPBHG => 8 VFLNM
|
||||||
|
2 RGKCF => 9 SLNKW
|
||||||
|
3 LZHZ, 2 GRDJ => 2 TBVH
|
||||||
|
100 ORE => 2 BXNX
|
||||||
|
4 DLSD, 21 JDSNJ => 8 GDVD
|
||||||
|
2 QHRG => 2 HWTBC
|
||||||
|
1 LPVGC, 8 XGWNS => 8 FRGJK
|
||||||
|
9 FZXS => 7 VRVGB
|
||||||
|
7 WZMRW, 1 TBVH, 1 VFLNM, 8 CNQW, 15 LZHZ, 25 PCRQV, 2 BRGXB => 4 WTZX
|
227
aoc2019/src/day14.rs
Normal file
227
aoc2019/src/day14.rs
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
use aoc::err;
|
||||||
|
use aoc::Result;
|
||||||
|
|
||||||
|
const INPUT: &str = include_str!("../input/day14.txt");
|
||||||
|
|
||||||
|
pub fn run() -> Result<String> {
|
||||||
|
let mut res = String::with_capacity(128);
|
||||||
|
|
||||||
|
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||||
|
writeln!(res, "part 2: {}", part2(INPUT)?)?;
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_recipes(input: &str) -> Result<HashMap<String, Recipe>> {
|
||||||
|
let mut recipes = HashMap::new();
|
||||||
|
|
||||||
|
for line in input.lines() {
|
||||||
|
let arrow = line
|
||||||
|
.find(" => ")
|
||||||
|
.ok_or_else(|| err!("couldn't find arrow in line: {}", line))?;
|
||||||
|
|
||||||
|
let elems = &line[..arrow];
|
||||||
|
let elems = elems
|
||||||
|
.split(", ")
|
||||||
|
.map(|elem| {
|
||||||
|
let space = elem
|
||||||
|
.find(' ')
|
||||||
|
.ok_or_else(|| err!("couldn't find separator for elem {}", elem))?;
|
||||||
|
let amount = elem[..space].parse()?;
|
||||||
|
let name = &elem[(space + 1)..];
|
||||||
|
|
||||||
|
Ok(RecipeElem {
|
||||||
|
name: name.to_string(),
|
||||||
|
amount,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
|
||||||
|
let result = &line[(arrow + 4)..].trim_end();
|
||||||
|
let space = result
|
||||||
|
.find(' ')
|
||||||
|
.ok_or_else(|| err!("couldn't find separator for result {}", result))?;
|
||||||
|
let result_amount = result[..space].parse()?;
|
||||||
|
let result_name = &result[(space + 1)..];
|
||||||
|
|
||||||
|
recipes.insert(
|
||||||
|
result_name.to_string(),
|
||||||
|
Recipe {
|
||||||
|
produced: result_amount,
|
||||||
|
elems,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(recipes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ore_cost(
|
||||||
|
material: String,
|
||||||
|
quantity: u64,
|
||||||
|
recipes: &HashMap<String, Recipe>,
|
||||||
|
inventory: &mut HashMap<String, u64>,
|
||||||
|
) -> Result<u64> {
|
||||||
|
if material == "ORE" {
|
||||||
|
return Ok(quantity);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut total = 0;
|
||||||
|
|
||||||
|
let mut in_stock = *inventory.entry(material.clone()).or_default();
|
||||||
|
if in_stock < quantity {
|
||||||
|
let recipe = recipes
|
||||||
|
.get(&material)
|
||||||
|
.ok_or_else(|| err!("couldn't find recipe for {}", material))?;
|
||||||
|
|
||||||
|
let needed = quantity - in_stock;
|
||||||
|
let num_reactions = (needed + recipe.produced - 1) / recipe.produced;
|
||||||
|
for elem in recipe.elems.iter() {
|
||||||
|
total += get_ore_cost(
|
||||||
|
elem.name.clone(),
|
||||||
|
elem.amount * num_reactions,
|
||||||
|
recipes,
|
||||||
|
inventory,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
in_stock += num_reactions * recipe.produced;
|
||||||
|
}
|
||||||
|
|
||||||
|
inventory.insert(material.clone(), in_stock - quantity);
|
||||||
|
|
||||||
|
Ok(total)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(input: &str) -> Result<u64> {
|
||||||
|
let recipes = parse_recipes(input)?;
|
||||||
|
let mut inventory = HashMap::new();
|
||||||
|
|
||||||
|
get_ore_cost("FUEL".to_string(), 1, &recipes, &mut inventory)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2(input: &str) -> Result<u64> {
|
||||||
|
let mut begin: u64 = 0;
|
||||||
|
let mut end: u64 = 1_000_000_000_000;
|
||||||
|
|
||||||
|
let recipes = parse_recipes(input)?;
|
||||||
|
|
||||||
|
while begin <= end {
|
||||||
|
let mid = begin + (end - begin) / 2;
|
||||||
|
let mut inventory = HashMap::new();
|
||||||
|
|
||||||
|
let ore_cost = get_ore_cost("FUEL".to_string(), mid, &recipes, &mut inventory)?;
|
||||||
|
match ore_cost.cmp(&1_000_000_000_000) {
|
||||||
|
Ordering::Greater => end = mid - 1,
|
||||||
|
Ordering::Less => begin = mid + 1,
|
||||||
|
Ordering::Equal => return Ok(mid),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(end)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RecipeElem {
|
||||||
|
name: String,
|
||||||
|
amount: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Recipe {
|
||||||
|
produced: u64,
|
||||||
|
elems: Vec<RecipeElem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const PROVIDED1: &str = "10 ORE => 10 A
|
||||||
|
1 ORE => 1 B
|
||||||
|
7 A, 1 B => 1 C
|
||||||
|
7 A, 1 C => 1 D
|
||||||
|
7 A, 1 D => 1 E
|
||||||
|
7 A, 1 E => 1 FUEL
|
||||||
|
";
|
||||||
|
|
||||||
|
const PROVIDED2: &str = "9 ORE => 2 A
|
||||||
|
8 ORE => 3 B
|
||||||
|
7 ORE => 5 C
|
||||||
|
3 A, 4 B => 1 AB
|
||||||
|
5 B, 7 C => 1 BC
|
||||||
|
4 C, 1 A => 1 CA
|
||||||
|
2 AB, 3 BC, 4 CA => 1 FUEL
|
||||||
|
";
|
||||||
|
|
||||||
|
const PROVIDED3: &str = "157 ORE => 5 NZVS
|
||||||
|
165 ORE => 6 DCFZ
|
||||||
|
44 XJWVT, 5 KHKGT, 1 QDVJ, 29 NZVS, 9 GPVTF, 48 HKGWZ => 1 FUEL
|
||||||
|
12 HKGWZ, 1 GPVTF, 8 PSHF => 9 QDVJ
|
||||||
|
179 ORE => 7 PSHF
|
||||||
|
177 ORE => 5 HKGWZ
|
||||||
|
7 DCFZ, 7 PSHF => 2 XJWVT
|
||||||
|
165 ORE => 2 GPVTF
|
||||||
|
3 DCFZ, 7 NZVS, 5 HKGWZ, 10 PSHF => 8 KHKGT
|
||||||
|
";
|
||||||
|
|
||||||
|
const PROVIDED4: &str = "2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG
|
||||||
|
17 NVRVD, 3 JNWZP => 8 VPVL
|
||||||
|
53 STKFG, 6 MNCFX, 46 VJHF, 81 HVMC, 68 CXFTF, 25 GNMV => 1 FUEL
|
||||||
|
22 VJHF, 37 MNCFX => 5 FWMGM
|
||||||
|
139 ORE => 4 NVRVD
|
||||||
|
144 ORE => 7 JNWZP
|
||||||
|
5 MNCFX, 7 RFSQX, 2 FWMGM, 2 VPVL, 19 CXFTF => 3 HVMC
|
||||||
|
5 VJHF, 7 MNCFX, 9 VPVL, 37 CXFTF => 6 GNMV
|
||||||
|
145 ORE => 6 MNCFX
|
||||||
|
1 NVRVD => 8 CXFTF
|
||||||
|
1 VJHF, 6 MNCFX => 4 RFSQX
|
||||||
|
176 ORE => 6 VJHF
|
||||||
|
";
|
||||||
|
|
||||||
|
const PROVIDED5: &str = "171 ORE => 8 CNZTR
|
||||||
|
7 ZLQW, 3 BMBT, 9 XCVML, 26 XMNCP, 1 WPTQ, 2 MZWV, 1 RJRHP => 4 PLWSL
|
||||||
|
114 ORE => 4 BHXH
|
||||||
|
14 VRPVC => 6 BMBT
|
||||||
|
6 BHXH, 18 KTJDG, 12 WPTQ, 7 PLWSL, 31 FHTLT, 37 ZDVW => 1 FUEL
|
||||||
|
6 WPTQ, 2 BMBT, 8 ZLQW, 18 KTJDG, 1 XMNCP, 6 MZWV, 1 RJRHP => 6 FHTLT
|
||||||
|
15 XDBXC, 2 LTCX, 1 VRPVC => 6 ZLQW
|
||||||
|
13 WPTQ, 10 LTCX, 3 RJRHP, 14 XMNCP, 2 MZWV, 1 ZLQW => 1 ZDVW
|
||||||
|
5 BMBT => 4 WPTQ
|
||||||
|
189 ORE => 9 KTJDG
|
||||||
|
1 MZWV, 17 XDBXC, 3 XCVML => 2 XMNCP
|
||||||
|
12 VRPVC, 27 CNZTR => 2 XDBXC
|
||||||
|
15 KTJDG, 12 BHXH => 5 XCVML
|
||||||
|
3 BHXH, 2 VRPVC => 7 MZWV
|
||||||
|
121 ORE => 7 VRPVC
|
||||||
|
7 XCVML => 6 RJRHP
|
||||||
|
5 BHXH, 4 VRPVC => 5 LTCX
|
||||||
|
";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_provided() {
|
||||||
|
assert_eq!(part1(PROVIDED1).unwrap(), 31);
|
||||||
|
assert_eq!(part1(PROVIDED2).unwrap(), 165);
|
||||||
|
assert_eq!(part1(PROVIDED3).unwrap(), 13312);
|
||||||
|
assert_eq!(part1(PROVIDED4).unwrap(), 180697);
|
||||||
|
assert_eq!(part1(PROVIDED5).unwrap(), 2210736);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_real() {
|
||||||
|
assert_eq!(part1(INPUT).unwrap(), 532506);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_provided() {
|
||||||
|
assert_eq!(part2(PROVIDED3).unwrap(), 82892753);
|
||||||
|
assert_eq!(part2(PROVIDED4).unwrap(), 5586022);
|
||||||
|
assert_eq!(part2(PROVIDED5).unwrap(), 460664);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_real() {
|
||||||
|
assert_eq!(part2(INPUT).unwrap(), 2595245);
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,3 +13,4 @@ pub mod day10;
|
||||||
pub mod day11;
|
pub mod day11;
|
||||||
pub mod day12;
|
pub mod day12;
|
||||||
pub mod day13;
|
pub mod day13;
|
||||||
|
pub mod day14;
|
||||||
|
|
|
@ -14,6 +14,7 @@ use aoc2019::day10;
|
||||||
use aoc2019::day11;
|
use aoc2019::day11;
|
||||||
use aoc2019::day12;
|
use aoc2019::day12;
|
||||||
use aoc2019::day13;
|
use aoc2019::day13;
|
||||||
|
use aoc2019::day14;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let days: &[DayFunc] = &[
|
let days: &[DayFunc] = &[
|
||||||
|
@ -30,6 +31,7 @@ fn main() -> Result<()> {
|
||||||
day11::run,
|
day11::run,
|
||||||
day12::run,
|
day12::run,
|
||||||
day13::run,
|
day13::run,
|
||||||
|
day14::run,
|
||||||
];
|
];
|
||||||
|
|
||||||
aoc::run(days)
|
aoc::run(days)
|
||||||
|
|
Loading…
Reference in a new issue