Completed day 14 part 1

This commit is contained in:
Tyler Hallada 2020-01-15 01:08:26 -05:00
parent f8e836f780
commit 9667e214b9
9 changed files with 481 additions and 0 deletions

59
day14/Cargo.lock generated Normal file
View File

@ -0,0 +1,59 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "day14"
version = "0.1.0"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "regex"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "thread_local"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata]
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223"
"checksum regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b5508c1941e4e7cb19965abef075d35a9a8b5cdf0846f30b4050e9b55dc55e87"
"checksum regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e734e891f5b408a29efbf8309e656876276f49ab6a6ac208600b4419bd893d90"
"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"

11
day14/Cargo.toml Normal file
View File

@ -0,0 +1,11 @@
[package]
name = "day14"
version = "0.1.0"
authors = ["Tyler Hallada <tyler@hallada.net>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
lazy_static = "1.4.0"
regex = "1.3.3"

62
day14/input/input.txt Normal file
View File

@ -0,0 +1,62 @@
1 HJDM, 1 BMPDP, 8 DRCX, 2 TCTBL, 1 KGWDJ, 16 BRLF, 2 LWPB, 7 KDFQ => 6 ZSPL
1 PVRCK, 3 RSLR, 4 JBZD => 6 LCHRC
10 FCBVC, 1 TSJSJ, 20 SQCQ => 9 PNQLP
1 MBVL => 6 TSZJ
1 HWGQF => 4 ZSLVH
1 TBDSC, 13 TSZJ => 1 HRZH
1 RSLR, 1 LJWM => 3 RSFJR
1 VMZFB => 2 MBVL
4 DSTHJ, 2 TSZJ, 13 MBVL => 4 ZWLGK
1 MKTZ, 18 RVFJB, 1 RSLR, 2 HRZH, 14 ZWLGK, 4 RJFTV => 1 ZCVL
6 KDFQ, 1 PNQLP, 1 HRZH => 9 DLPMH
1 DSVT, 22 DRCX, 18 RJFTV, 2 MKTZ, 13 FVZBX, 15 SLTNZ, 7 ZSLVH => 5 GWJC
2 JZSJ, 3 ZSLVH, 6 HNRXC => 8 RJFTV
1 TSZJ => 7 GFVG
5 VMZFB => 4 JBZD
1 PBFZ, 23 JBZD, 2 LJWM => 1 TSJSJ
7 ZPQD => 7 VMZFB
2 LCHRC => 8 PXHK
2 TSZJ, 1 KCXMF, 1 FKJGC => 6 HWGQF
4 PBFZ => 1 FCBVC
1 GMWHM, 4 JQBKW => 8 SQCQ
5 SHMP => 5 PVRCK
10 KCXMF => 3 DRCX
15 VMZFB, 2 RSFJR => 6 KDFQ
35 HNRXC => 2 CJLG
8 MKTZ, 1 FCBVC, 12 HJDM => 9 BRLF
171 ORE => 8 GMWHM
8 RVFJB, 3 CJLG, 9 SLTNZ => 3 LWPB
1 PXHK, 2 RSFJR => 3 FVZBX
1 CJLG, 1 HRZH, 10 MKTZ => 8 KGWDJ
1 RSFJR => 3 FKJGC
1 NXCZM, 31 FKJGC => 2 MKTZ
18 XLWBP => 6 MBLWL
22 HNRXC => 8 FTGK
3 KGWDJ, 1 MLBJ, 5 HJDM => 7 DSVT
9 KDFQ => 5 NXCZM
2 RVFJB, 4 LGDKL, 1 PXHK => 5 CVTR
1 RSFJR, 6 GMWHM, 20 TSJSJ => 9 LGDKL
5 KCXMF => 9 RBDP
6 GWJC, 16 ZCVL, 29 JZSJ, 1 ZSPL, 35 MBLWL, 30 BWFRH, 2 MSFDB, 13 BMPDP, 11 FTGK, 1 ZWLGK => 1 FUEL
6 GFVG, 2 TVQP => 8 HJDM
1 CJLG, 13 PBFZ => 6 JZSJ
3 CVTR => 3 BMPDP
16 FPKMV, 1 ZSLVH => 8 MSFDB
9 JBZD, 12 LCHRC => 8 TBDSC
133 ORE => 3 LJWM
107 ORE => 7 SHMP
1 KDFQ, 1 LJWM => 9 FPKMV
3 PXHK => 4 BWFRH
123 ORE => 4 JQBKW
2 FVZBX, 1 JZSJ => 8 XLWBP
117 ORE => 2 ZPQD
7 NXCZM => 7 HNRXC
1 MLBJ, 22 RSLR => 8 KCXMF
2 TBDSC => 8 RVFJB
1 KDFQ, 23 DSTHJ => 7 SLTNZ
3 RSFJR => 6 MLBJ
5 PVRCK, 2 SQCQ => 9 RSLR
1 LGDKL, 17 MBVL, 6 PNQLP => 5 TVQP
3 RBDP => 6 TCTBL
1 DLPMH, 1 GFVG, 3 MBVL => 2 DSTHJ
21 VMZFB, 2 LJWM => 1 PBFZ

6
day14/input/test1.txt Normal file
View File

@ -0,0 +1,6 @@
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

7
day14/input/test2.txt Normal file
View File

@ -0,0 +1,7 @@
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

9
day14/input/test3.txt Normal file
View File

@ -0,0 +1,9 @@
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

12
day14/input/test4.txt Normal file
View File

@ -0,0 +1,12 @@
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

17
day14/input/test5.txt Normal file
View File

@ -0,0 +1,17 @@
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

298
day14/src/main.rs Normal file
View File

@ -0,0 +1,298 @@
#[macro_use]
extern crate lazy_static;
use std::collections::HashMap;
use std::error::Error;
use std::fs::read_to_string;
use std::result;
use std::str::FromStr;
use regex::Regex;
type Result<T> = result::Result<T, Box<dyn Error>>;
const INPUT: &str = "input/input.txt";
#[derive(Debug, PartialEq)]
struct Reactions {
reactions: HashMap<String, Reaction>,
}
#[derive(Debug, PartialEq)]
struct Reaction {
output: ChemicalAmount,
inputs: Vec<ChemicalAmount>,
}
#[derive(Debug, Hash, PartialEq, Eq)]
struct ChemicalAmount {
chemical: String,
amount: u32,
}
impl FromStr for Reactions {
type Err = Box<dyn Error>;
fn from_str(s: &str) -> Result<Reactions> {
lazy_static! {
static ref SOURCE_CHEMICALS: Regex =
Regex::new(concat!(r"(?P<input_amount>\d+) (?P<input_chemical>\w+),? ",)).unwrap();
static ref OUTPUT_CHEMICAL: Regex = Regex::new(concat!(
r"=> (?P<output_amount>\d+) (?P<output_chemical>\w+)"
))
.unwrap();
}
let mut reactions = HashMap::new();
for line in s.trim().split('\n') {
let mut inputs: Vec<ChemicalAmount> = vec![];
for captures in SOURCE_CHEMICALS.captures_iter(line) {
inputs.push(ChemicalAmount {
chemical: captures["input_chemical"].to_string(),
amount: captures["input_amount"].parse()?,
});
}
match OUTPUT_CHEMICAL.captures(line) {
None => {
return Err(From::from(
"Malformed reactions, no output chemical could be found",
));
}
Some(captures) => {
let output = ChemicalAmount {
chemical: captures["output_chemical"].to_string(),
amount: captures["output_amount"].parse()?,
};
reactions.insert(output.chemical.clone(), Reaction { inputs, output });
}
};
}
Ok(Reactions { reactions })
}
}
impl Reactions {
fn new() -> Reactions {
Reactions {
reactions: HashMap::new(),
}
}
}
fn calculate_ore_required(
reactions: &Reactions,
produced_chemical: &ChemicalAmount,
left_overs: &mut HashMap<String, u32>,
) -> u32 {
let reaction = &reactions.reactions[&produced_chemical.chemical];
let mut needed_amount = produced_chemical.amount;
let mut left_over = 0;
if let Some(left_over_amount) = left_overs.get(&produced_chemical.chemical) {
left_over = *left_over_amount;
}
if left_over > 0 {
if left_over >= needed_amount {
left_overs.insert(
produced_chemical.chemical.clone(),
left_over - needed_amount,
);
return 0;
} else {
left_overs.insert(produced_chemical.chemical.clone(), 0);
needed_amount -= left_over;
}
}
let ratio: f32 = needed_amount as f32 / reaction.output.amount as f32;
let production_count = ratio.ceil() as u32;
left_overs.insert(
produced_chemical.chemical.clone(),
(reaction.output.amount * production_count) - needed_amount,
);
if reaction.inputs.len() == 1 && reaction.inputs[0].chemical == "ORE" {
return reaction.inputs[0].amount * production_count;
} else {
return reaction
.inputs
.iter()
.map(|input| {
calculate_ore_required(
reactions,
&ChemicalAmount {
chemical: input.chemical.clone(),
amount: input.amount * production_count,
},
left_overs,
)
})
.sum();
}
}
fn read_reactions(filename: &str) -> Result<Reactions> {
let reactions = read_to_string(filename)?.parse()?;
Ok(reactions)
}
fn solve_part1(filename: &str) -> Result<u32> {
let reactions = read_reactions(filename)?;
let mut left_overs = HashMap::new();
Ok(calculate_ore_required(
&reactions,
&ChemicalAmount {
chemical: "FUEL".to_string(),
amount: 1,
},
&mut left_overs,
))
}
fn solve_part2(filename: &str) -> Result<u64> {
Ok(1)
}
fn main() -> Result<()> {
println!("Part 1: {}", solve_part1(INPUT)?);
println!("Part 2: {}", solve_part2(INPUT)?);
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
const TEST_INPUT1: &str = "input/test1.txt";
const TEST_INPUT2: &str = "input/test2.txt";
const TEST_INPUT3: &str = "input/test3.txt";
const TEST_INPUT4: &str = "input/test4.txt";
const TEST_INPUT5: &str = "input/test5.txt";
fn reactions_1() -> Reactions {
Reactions {
reactions: vec![
(
"E".to_string(),
Reaction {
output: ChemicalAmount {
chemical: "E".to_string(),
amount: 1,
},
inputs: vec![
ChemicalAmount {
chemical: "A".to_string(),
amount: 7,
},
ChemicalAmount {
chemical: "D".to_string(),
amount: 1,
},
],
},
),
(
"A".to_string(),
Reaction {
output: ChemicalAmount {
chemical: "A".to_string(),
amount: 10,
},
inputs: vec![ChemicalAmount {
chemical: "ORE".to_string(),
amount: 10,
}],
},
),
(
"D".to_string(),
Reaction {
output: ChemicalAmount {
chemical: "D".to_string(),
amount: 1,
},
inputs: vec![
ChemicalAmount {
chemical: "A".to_string(),
amount: 7,
},
ChemicalAmount {
chemical: "C".to_string(),
amount: 1,
},
],
},
),
(
"FUEL".to_string(),
Reaction {
output: ChemicalAmount {
chemical: "FUEL".to_string(),
amount: 1,
},
inputs: vec![
ChemicalAmount {
chemical: "A".to_string(),
amount: 7,
},
ChemicalAmount {
chemical: "E".to_string(),
amount: 1,
},
],
},
),
(
"B".to_string(),
Reaction {
output: ChemicalAmount {
chemical: "B".to_string(),
amount: 1,
},
inputs: vec![ChemicalAmount {
chemical: "ORE".to_string(),
amount: 1,
}],
},
),
(
"C".to_string(),
Reaction {
output: ChemicalAmount {
chemical: "C".to_string(),
amount: 1,
},
inputs: vec![
ChemicalAmount {
chemical: "A".to_string(),
amount: 7,
},
ChemicalAmount {
chemical: "B".to_string(),
amount: 1,
},
],
},
),
]
.into_iter()
.collect(),
}
}
#[test]
fn reads_reactions() {
assert_eq!(read_reactions(TEST_INPUT1).unwrap(), reactions_1());
}
#[test]
fn solves_part1() {
assert_eq!(solve_part1(TEST_INPUT1).unwrap(), 31);
assert_eq!(solve_part1(TEST_INPUT2).unwrap(), 165);
assert_eq!(solve_part1(TEST_INPUT3).unwrap(), 13312);
assert_eq!(solve_part1(TEST_INPUT4).unwrap(), 180697);
assert_eq!(solve_part1(TEST_INPUT5).unwrap(), 2210736);
}
}