Browse Source

Completed day 14 part 1

Tyler Hallada 4 years ago
parent
commit
9667e214b9

+ 59 - 0
day14/Cargo.lock

@@ -0,0 +1,59 @@
1
+# This file is automatically @generated by Cargo.
2
+# It is not intended for manual editing.
3
+[[package]]
4
+name = "aho-corasick"
5
+version = "0.7.6"
6
+source = "registry+https://github.com/rust-lang/crates.io-index"
7
+dependencies = [
8
+ "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
9
+]
10
+
11
+[[package]]
12
+name = "day14"
13
+version = "0.1.0"
14
+dependencies = [
15
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
16
+ "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
17
+]
18
+
19
+[[package]]
20
+name = "lazy_static"
21
+version = "1.4.0"
22
+source = "registry+https://github.com/rust-lang/crates.io-index"
23
+
24
+[[package]]
25
+name = "memchr"
26
+version = "2.3.0"
27
+source = "registry+https://github.com/rust-lang/crates.io-index"
28
+
29
+[[package]]
30
+name = "regex"
31
+version = "1.3.3"
32
+source = "registry+https://github.com/rust-lang/crates.io-index"
33
+dependencies = [
34
+ "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
35
+ "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
36
+ "regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
37
+ "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
38
+]
39
+
40
+[[package]]
41
+name = "regex-syntax"
42
+version = "0.6.13"
43
+source = "registry+https://github.com/rust-lang/crates.io-index"
44
+
45
+[[package]]
46
+name = "thread_local"
47
+version = "1.0.1"
48
+source = "registry+https://github.com/rust-lang/crates.io-index"
49
+dependencies = [
50
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
51
+]
52
+
53
+[metadata]
54
+"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
55
+"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
56
+"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223"
57
+"checksum regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b5508c1941e4e7cb19965abef075d35a9a8b5cdf0846f30b4050e9b55dc55e87"
58
+"checksum regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e734e891f5b408a29efbf8309e656876276f49ab6a6ac208600b4419bd893d90"
59
+"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"

+ 11 - 0
day14/Cargo.toml

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

+ 62 - 0
day14/input/input.txt

@@ -0,0 +1,62 @@
1
+1 HJDM, 1 BMPDP, 8 DRCX, 2 TCTBL, 1 KGWDJ, 16 BRLF, 2 LWPB, 7 KDFQ => 6 ZSPL
2
+1 PVRCK, 3 RSLR, 4 JBZD => 6 LCHRC
3
+10 FCBVC, 1 TSJSJ, 20 SQCQ => 9 PNQLP
4
+1 MBVL => 6 TSZJ
5
+1 HWGQF => 4 ZSLVH
6
+1 TBDSC, 13 TSZJ => 1 HRZH
7
+1 RSLR, 1 LJWM => 3 RSFJR
8
+1 VMZFB => 2 MBVL
9
+4 DSTHJ, 2 TSZJ, 13 MBVL => 4 ZWLGK
10
+1 MKTZ, 18 RVFJB, 1 RSLR, 2 HRZH, 14 ZWLGK, 4 RJFTV => 1 ZCVL
11
+6 KDFQ, 1 PNQLP, 1 HRZH => 9 DLPMH
12
+1 DSVT, 22 DRCX, 18 RJFTV, 2 MKTZ, 13 FVZBX, 15 SLTNZ, 7 ZSLVH => 5 GWJC
13
+2 JZSJ, 3 ZSLVH, 6 HNRXC => 8 RJFTV
14
+1 TSZJ => 7 GFVG
15
+5 VMZFB => 4 JBZD
16
+1 PBFZ, 23 JBZD, 2 LJWM => 1 TSJSJ
17
+7 ZPQD => 7 VMZFB
18
+2 LCHRC => 8 PXHK
19
+2 TSZJ, 1 KCXMF, 1 FKJGC => 6 HWGQF
20
+4 PBFZ => 1 FCBVC
21
+1 GMWHM, 4 JQBKW => 8 SQCQ
22
+5 SHMP => 5 PVRCK
23
+10 KCXMF => 3 DRCX
24
+15 VMZFB, 2 RSFJR => 6 KDFQ
25
+35 HNRXC => 2 CJLG
26
+8 MKTZ, 1 FCBVC, 12 HJDM => 9 BRLF
27
+171 ORE => 8 GMWHM
28
+8 RVFJB, 3 CJLG, 9 SLTNZ => 3 LWPB
29
+1 PXHK, 2 RSFJR => 3 FVZBX
30
+1 CJLG, 1 HRZH, 10 MKTZ => 8 KGWDJ
31
+1 RSFJR => 3 FKJGC
32
+1 NXCZM, 31 FKJGC => 2 MKTZ
33
+18 XLWBP => 6 MBLWL
34
+22 HNRXC => 8 FTGK
35
+3 KGWDJ, 1 MLBJ, 5 HJDM => 7 DSVT
36
+9 KDFQ => 5 NXCZM
37
+2 RVFJB, 4 LGDKL, 1 PXHK => 5 CVTR
38
+1 RSFJR, 6 GMWHM, 20 TSJSJ => 9 LGDKL
39
+5 KCXMF => 9 RBDP
40
+6 GWJC, 16 ZCVL, 29 JZSJ, 1 ZSPL, 35 MBLWL, 30 BWFRH, 2 MSFDB, 13 BMPDP, 11 FTGK, 1 ZWLGK => 1 FUEL
41
+6 GFVG, 2 TVQP => 8 HJDM
42
+1 CJLG, 13 PBFZ => 6 JZSJ
43
+3 CVTR => 3 BMPDP
44
+16 FPKMV, 1 ZSLVH => 8 MSFDB
45
+9 JBZD, 12 LCHRC => 8 TBDSC
46
+133 ORE => 3 LJWM
47
+107 ORE => 7 SHMP
48
+1 KDFQ, 1 LJWM => 9 FPKMV
49
+3 PXHK => 4 BWFRH
50
+123 ORE => 4 JQBKW
51
+2 FVZBX, 1 JZSJ => 8 XLWBP
52
+117 ORE => 2 ZPQD
53
+7 NXCZM => 7 HNRXC
54
+1 MLBJ, 22 RSLR => 8 KCXMF
55
+2 TBDSC => 8 RVFJB
56
+1 KDFQ, 23 DSTHJ => 7 SLTNZ
57
+3 RSFJR => 6 MLBJ
58
+5 PVRCK, 2 SQCQ => 9 RSLR
59
+1 LGDKL, 17 MBVL, 6 PNQLP => 5 TVQP
60
+3 RBDP => 6 TCTBL
61
+1 DLPMH, 1 GFVG, 3 MBVL => 2 DSTHJ
62
+21 VMZFB, 2 LJWM => 1 PBFZ

+ 6 - 0
day14/input/test1.txt

@@ -0,0 +1,6 @@
1
+10 ORE => 10 A
2
+1 ORE => 1 B
3
+7 A, 1 B => 1 C
4
+7 A, 1 C => 1 D
5
+7 A, 1 D => 1 E
6
+7 A, 1 E => 1 FUEL

+ 7 - 0
day14/input/test2.txt

@@ -0,0 +1,7 @@
1
+9 ORE => 2 A
2
+8 ORE => 3 B
3
+7 ORE => 5 C
4
+3 A, 4 B => 1 AB
5
+5 B, 7 C => 1 BC
6
+4 C, 1 A => 1 CA
7
+2 AB, 3 BC, 4 CA => 1 FUEL

+ 9 - 0
day14/input/test3.txt

@@ -0,0 +1,9 @@
1
+157 ORE => 5 NZVS
2
+165 ORE => 6 DCFZ
3
+44 XJWVT, 5 KHKGT, 1 QDVJ, 29 NZVS, 9 GPVTF, 48 HKGWZ => 1 FUEL
4
+12 HKGWZ, 1 GPVTF, 8 PSHF => 9 QDVJ
5
+179 ORE => 7 PSHF
6
+177 ORE => 5 HKGWZ
7
+7 DCFZ, 7 PSHF => 2 XJWVT
8
+165 ORE => 2 GPVTF
9
+3 DCFZ, 7 NZVS, 5 HKGWZ, 10 PSHF => 8 KHKGT

+ 12 - 0
day14/input/test4.txt

@@ -0,0 +1,12 @@
1
+2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG
2
+17 NVRVD, 3 JNWZP => 8 VPVL
3
+53 STKFG, 6 MNCFX, 46 VJHF, 81 HVMC, 68 CXFTF, 25 GNMV => 1 FUEL
4
+22 VJHF, 37 MNCFX => 5 FWMGM
5
+139 ORE => 4 NVRVD
6
+144 ORE => 7 JNWZP
7
+5 MNCFX, 7 RFSQX, 2 FWMGM, 2 VPVL, 19 CXFTF => 3 HVMC
8
+5 VJHF, 7 MNCFX, 9 VPVL, 37 CXFTF => 6 GNMV
9
+145 ORE => 6 MNCFX
10
+1 NVRVD => 8 CXFTF
11
+1 VJHF, 6 MNCFX => 4 RFSQX
12
+176 ORE => 6 VJHF

+ 17 - 0
day14/input/test5.txt

@@ -0,0 +1,17 @@
1
+171 ORE => 8 CNZTR
2
+7 ZLQW, 3 BMBT, 9 XCVML, 26 XMNCP, 1 WPTQ, 2 MZWV, 1 RJRHP => 4 PLWSL
3
+114 ORE => 4 BHXH
4
+14 VRPVC => 6 BMBT
5
+6 BHXH, 18 KTJDG, 12 WPTQ, 7 PLWSL, 31 FHTLT, 37 ZDVW => 1 FUEL
6
+6 WPTQ, 2 BMBT, 8 ZLQW, 18 KTJDG, 1 XMNCP, 6 MZWV, 1 RJRHP => 6 FHTLT
7
+15 XDBXC, 2 LTCX, 1 VRPVC => 6 ZLQW
8
+13 WPTQ, 10 LTCX, 3 RJRHP, 14 XMNCP, 2 MZWV, 1 ZLQW => 1 ZDVW
9
+5 BMBT => 4 WPTQ
10
+189 ORE => 9 KTJDG
11
+1 MZWV, 17 XDBXC, 3 XCVML => 2 XMNCP
12
+12 VRPVC, 27 CNZTR => 2 XDBXC
13
+15 KTJDG, 12 BHXH => 5 XCVML
14
+3 BHXH, 2 VRPVC => 7 MZWV
15
+121 ORE => 7 VRPVC
16
+7 XCVML => 6 RJRHP
17
+5 BHXH, 4 VRPVC => 5 LTCX

+ 298 - 0
day14/src/main.rs

@@ -0,0 +1,298 @@
1
+#[macro_use]
2
+extern crate lazy_static;
3
+
4
+use std::collections::HashMap;
5
+use std::error::Error;
6
+use std::fs::read_to_string;
7
+use std::result;
8
+use std::str::FromStr;
9
+
10
+use regex::Regex;
11
+
12
+type Result<T> = result::Result<T, Box<dyn Error>>;
13
+
14
+const INPUT: &str = "input/input.txt";
15
+
16
+#[derive(Debug, PartialEq)]
17
+struct Reactions {
18
+    reactions: HashMap<String, Reaction>,
19
+}
20
+
21
+#[derive(Debug, PartialEq)]
22
+struct Reaction {
23
+    output: ChemicalAmount,
24
+    inputs: Vec<ChemicalAmount>,
25
+}
26
+
27
+#[derive(Debug, Hash, PartialEq, Eq)]
28
+struct ChemicalAmount {
29
+    chemical: String,
30
+    amount: u32,
31
+}
32
+
33
+impl FromStr for Reactions {
34
+    type Err = Box<dyn Error>;
35
+
36
+    fn from_str(s: &str) -> Result<Reactions> {
37
+        lazy_static! {
38
+            static ref SOURCE_CHEMICALS: Regex =
39
+                Regex::new(concat!(r"(?P<input_amount>\d+) (?P<input_chemical>\w+),? ",)).unwrap();
40
+            static ref OUTPUT_CHEMICAL: Regex = Regex::new(concat!(
41
+                r"=> (?P<output_amount>\d+) (?P<output_chemical>\w+)"
42
+            ))
43
+            .unwrap();
44
+        }
45
+
46
+        let mut reactions = HashMap::new();
47
+        for line in s.trim().split('\n') {
48
+            let mut inputs: Vec<ChemicalAmount> = vec![];
49
+            for captures in SOURCE_CHEMICALS.captures_iter(line) {
50
+                inputs.push(ChemicalAmount {
51
+                    chemical: captures["input_chemical"].to_string(),
52
+                    amount: captures["input_amount"].parse()?,
53
+                });
54
+            }
55
+            match OUTPUT_CHEMICAL.captures(line) {
56
+                None => {
57
+                    return Err(From::from(
58
+                        "Malformed reactions, no output chemical could be found",
59
+                    ));
60
+                }
61
+                Some(captures) => {
62
+                    let output = ChemicalAmount {
63
+                        chemical: captures["output_chemical"].to_string(),
64
+                        amount: captures["output_amount"].parse()?,
65
+                    };
66
+                    reactions.insert(output.chemical.clone(), Reaction { inputs, output });
67
+                }
68
+            };
69
+        }
70
+
71
+        Ok(Reactions { reactions })
72
+    }
73
+}
74
+
75
+impl Reactions {
76
+    fn new() -> Reactions {
77
+        Reactions {
78
+            reactions: HashMap::new(),
79
+        }
80
+    }
81
+}
82
+
83
+fn calculate_ore_required(
84
+    reactions: &Reactions,
85
+    produced_chemical: &ChemicalAmount,
86
+    left_overs: &mut HashMap<String, u32>,
87
+) -> u32 {
88
+    let reaction = &reactions.reactions[&produced_chemical.chemical];
89
+    let mut needed_amount = produced_chemical.amount;
90
+    let mut left_over = 0;
91
+    if let Some(left_over_amount) = left_overs.get(&produced_chemical.chemical) {
92
+        left_over = *left_over_amount;
93
+    }
94
+
95
+    if left_over > 0 {
96
+        if left_over >= needed_amount {
97
+            left_overs.insert(
98
+                produced_chemical.chemical.clone(),
99
+                left_over - needed_amount,
100
+            );
101
+            return 0;
102
+        } else {
103
+            left_overs.insert(produced_chemical.chemical.clone(), 0);
104
+            needed_amount -= left_over;
105
+        }
106
+    }
107
+
108
+    let ratio: f32 = needed_amount as f32 / reaction.output.amount as f32;
109
+    let production_count = ratio.ceil() as u32;
110
+    left_overs.insert(
111
+        produced_chemical.chemical.clone(),
112
+        (reaction.output.amount * production_count) - needed_amount,
113
+    );
114
+
115
+    if reaction.inputs.len() == 1 && reaction.inputs[0].chemical == "ORE" {
116
+        return reaction.inputs[0].amount * production_count;
117
+    } else {
118
+        return reaction
119
+            .inputs
120
+            .iter()
121
+            .map(|input| {
122
+                calculate_ore_required(
123
+                    reactions,
124
+                    &ChemicalAmount {
125
+                        chemical: input.chemical.clone(),
126
+                        amount: input.amount * production_count,
127
+                    },
128
+                    left_overs,
129
+                )
130
+            })
131
+            .sum();
132
+    }
133
+}
134
+
135
+fn read_reactions(filename: &str) -> Result<Reactions> {
136
+    let reactions = read_to_string(filename)?.parse()?;
137
+    Ok(reactions)
138
+}
139
+
140
+fn solve_part1(filename: &str) -> Result<u32> {
141
+    let reactions = read_reactions(filename)?;
142
+    let mut left_overs = HashMap::new();
143
+    Ok(calculate_ore_required(
144
+        &reactions,
145
+        &ChemicalAmount {
146
+            chemical: "FUEL".to_string(),
147
+            amount: 1,
148
+        },
149
+        &mut left_overs,
150
+    ))
151
+}
152
+
153
+fn solve_part2(filename: &str) -> Result<u64> {
154
+    Ok(1)
155
+}
156
+
157
+fn main() -> Result<()> {
158
+    println!("Part 1: {}", solve_part1(INPUT)?);
159
+    println!("Part 2: {}", solve_part2(INPUT)?);
160
+
161
+    Ok(())
162
+}
163
+
164
+#[cfg(test)]
165
+mod tests {
166
+    use super::*;
167
+
168
+    const TEST_INPUT1: &str = "input/test1.txt";
169
+    const TEST_INPUT2: &str = "input/test2.txt";
170
+    const TEST_INPUT3: &str = "input/test3.txt";
171
+    const TEST_INPUT4: &str = "input/test4.txt";
172
+    const TEST_INPUT5: &str = "input/test5.txt";
173
+
174
+    fn reactions_1() -> Reactions {
175
+        Reactions {
176
+            reactions: vec![
177
+                (
178
+                    "E".to_string(),
179
+                    Reaction {
180
+                        output: ChemicalAmount {
181
+                            chemical: "E".to_string(),
182
+                            amount: 1,
183
+                        },
184
+                        inputs: vec![
185
+                            ChemicalAmount {
186
+                                chemical: "A".to_string(),
187
+                                amount: 7,
188
+                            },
189
+                            ChemicalAmount {
190
+                                chemical: "D".to_string(),
191
+                                amount: 1,
192
+                            },
193
+                        ],
194
+                    },
195
+                ),
196
+                (
197
+                    "A".to_string(),
198
+                    Reaction {
199
+                        output: ChemicalAmount {
200
+                            chemical: "A".to_string(),
201
+                            amount: 10,
202
+                        },
203
+                        inputs: vec![ChemicalAmount {
204
+                            chemical: "ORE".to_string(),
205
+                            amount: 10,
206
+                        }],
207
+                    },
208
+                ),
209
+                (
210
+                    "D".to_string(),
211
+                    Reaction {
212
+                        output: ChemicalAmount {
213
+                            chemical: "D".to_string(),
214
+                            amount: 1,
215
+                        },
216
+                        inputs: vec![
217
+                            ChemicalAmount {
218
+                                chemical: "A".to_string(),
219
+                                amount: 7,
220
+                            },
221
+                            ChemicalAmount {
222
+                                chemical: "C".to_string(),
223
+                                amount: 1,
224
+                            },
225
+                        ],
226
+                    },
227
+                ),
228
+                (
229
+                    "FUEL".to_string(),
230
+                    Reaction {
231
+                        output: ChemicalAmount {
232
+                            chemical: "FUEL".to_string(),
233
+                            amount: 1,
234
+                        },
235
+                        inputs: vec![
236
+                            ChemicalAmount {
237
+                                chemical: "A".to_string(),
238
+                                amount: 7,
239
+                            },
240
+                            ChemicalAmount {
241
+                                chemical: "E".to_string(),
242
+                                amount: 1,
243
+                            },
244
+                        ],
245
+                    },
246
+                ),
247
+                (
248
+                    "B".to_string(),
249
+                    Reaction {
250
+                        output: ChemicalAmount {
251
+                            chemical: "B".to_string(),
252
+                            amount: 1,
253
+                        },
254
+                        inputs: vec![ChemicalAmount {
255
+                            chemical: "ORE".to_string(),
256
+                            amount: 1,
257
+                        }],
258
+                    },
259
+                ),
260
+                (
261
+                    "C".to_string(),
262
+                    Reaction {
263
+                        output: ChemicalAmount {
264
+                            chemical: "C".to_string(),
265
+                            amount: 1,
266
+                        },
267
+                        inputs: vec![
268
+                            ChemicalAmount {
269
+                                chemical: "A".to_string(),
270
+                                amount: 7,
271
+                            },
272
+                            ChemicalAmount {
273
+                                chemical: "B".to_string(),
274
+                                amount: 1,
275
+                            },
276
+                        ],
277
+                    },
278
+                ),
279
+            ]
280
+            .into_iter()
281
+            .collect(),
282
+        }
283
+    }
284
+
285
+    #[test]
286
+    fn reads_reactions() {
287
+        assert_eq!(read_reactions(TEST_INPUT1).unwrap(), reactions_1());
288
+    }
289
+
290
+    #[test]
291
+    fn solves_part1() {
292
+        assert_eq!(solve_part1(TEST_INPUT1).unwrap(), 31);
293
+        assert_eq!(solve_part1(TEST_INPUT2).unwrap(), 165);
294
+        assert_eq!(solve_part1(TEST_INPUT3).unwrap(), 13312);
295
+        assert_eq!(solve_part1(TEST_INPUT4).unwrap(), 180697);
296
+        assert_eq!(solve_part1(TEST_INPUT5).unwrap(), 2210736);
297
+    }
298
+}