summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--inputs/day_14.txt102
-rw-r--r--src/bin/day_14.rs98
2 files changed, 200 insertions, 0 deletions
diff --git a/inputs/day_14.txt b/inputs/day_14.txt
new file mode 100644
index 0000000..e84aae5
--- /dev/null
+++ b/inputs/day_14.txt
@@ -0,0 +1,102 @@
+SNPVPFCPPKSBNSPSPSOF
+
+CF -> N
+NK -> B
+SF -> B
+HV -> P
+FN -> S
+VV -> F
+FO -> F
+VN -> V
+PV -> P
+FF -> P
+ON -> S
+PB -> S
+PK -> P
+OO -> P
+SP -> F
+VF -> H
+OV -> C
+BN -> P
+OH -> H
+NC -> F
+BH -> N
+CS -> C
+BC -> N
+OF -> N
+SN -> B
+FP -> F
+FV -> K
+HP -> H
+VB -> P
+FH -> F
+HF -> P
+BB -> O
+HH -> S
+PC -> O
+PP -> B
+VS -> B
+HC -> H
+NS -> N
+KF -> S
+BO -> V
+NP -> S
+NF -> K
+BS -> O
+KK -> O
+VC -> V
+KP -> K
+CK -> P
+HN -> F
+KN -> H
+KH -> N
+SB -> S
+NO -> K
+HK -> H
+BF -> V
+SV -> B
+CV -> P
+CO -> P
+FC -> O
+CP -> H
+CC -> N
+CN -> P
+SK -> V
+SS -> V
+VH -> B
+OS -> N
+FB -> H
+NB -> N
+SC -> K
+NV -> H
+HO -> S
+SO -> P
+PH -> C
+VO -> O
+OB -> O
+FK -> S
+PN -> P
+VK -> O
+NH -> N
+OC -> B
+BP -> O
+PF -> F
+KB -> K
+KV -> B
+PO -> N
+NN -> K
+CH -> O
+KC -> P
+OP -> V
+VP -> F
+OK -> P
+FS -> K
+CB -> S
+HB -> N
+KS -> O
+BK -> C
+BV -> O
+SH -> H
+PS -> N
+HS -> K
+KO -> N
diff --git a/src/bin/day_14.rs b/src/bin/day_14.rs
new file mode 100644
index 0000000..c534b8c
--- /dev/null
+++ b/src/bin/day_14.rs
@@ -0,0 +1,98 @@
+use nom::{
+ bytes::complete::tag,
+ character::complete::{alpha1, anychar, line_ending},
+ combinator::map,
+ multi::{many0, separated_list1},
+ sequence::tuple,
+ IResult,
+};
+use std::{collections::BTreeMap, fs};
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let input = fs::read_to_string("inputs/day_14.txt")?;
+ let mut polymer = parse_polymer_expansion(&input).unwrap().1;
+ for _ in 0..10 {
+ polymer.expand();
+ }
+ dbg!(polymer.most_common_element_count() - polymer.least_common_element_count());
+ for _ in 0..30 {
+ polymer.expand();
+ }
+ dbg!(polymer.most_common_element_count() - polymer.least_common_element_count());
+
+ Ok(())
+}
+
+#[derive(Debug)]
+struct PolymerExpansion {
+ polymer: Vec<char>,
+ rules: Rules,
+ element_counts: BTreeMap<char, u64>,
+}
+
+impl PolymerExpansion {
+ fn new(polymer: Vec<char>, rules: Rules) -> PolymerExpansion {
+ let mut element_counts = BTreeMap::new();
+ for c in &polymer {
+ *element_counts.entry(*c).or_insert(0) += 1;
+ }
+
+ PolymerExpansion {
+ polymer,
+ rules,
+ element_counts,
+ }
+ }
+
+ fn expand(&mut self) {
+ let mut next_polymer = Vec::new();
+ for i in 0..self.polymer.len() - 1 {
+ next_polymer.push(self.polymer[i]);
+ if let Some(extra) = self.rules.get(&[self.polymer[i], self.polymer[i + 1]]) {
+ next_polymer.push(extra);
+ *self.element_counts.entry(extra).or_insert(0) += 1;
+ }
+ }
+ next_polymer.push(self.polymer[self.polymer.len() - 1]);
+ self.polymer = next_polymer;
+ }
+
+ fn most_common_element_count(&self) -> u64 {
+ self.element_counts.values().max().cloned().unwrap_or(0)
+ }
+
+ fn least_common_element_count(&self) -> u64 {
+ self.element_counts.values().min().cloned().unwrap_or(0)
+ }
+}
+
+#[derive(Debug)]
+struct Rules {
+ rules: BTreeMap<[char; 2], char>,
+}
+
+impl Rules {
+ fn get(&self, key: &[char; 2]) -> Option<char> {
+ self.rules.get(key).cloned()
+ }
+}
+
+fn parse_polymer_expansion(input: &str) -> IResult<&str, PolymerExpansion> {
+ let (input, polymer) = map(alpha1, |s: &str| s.chars().collect())(input)?;
+ let (input, _) = many0(line_ending)(input)?;
+ let (input, rules) = parse_rules(input)?;
+ Ok((input, PolymerExpansion::new(polymer, rules)))
+}
+
+fn parse_rules(input: &str) -> IResult<&str, Rules> {
+ map(separated_list1(line_ending, parse_rule), |rules| Rules {
+ rules: rules.into_iter().collect(),
+ })(input)
+}
+
+fn parse_rule(input: &str) -> IResult<&str, ([char; 2], char)> {
+ map(
+ tuple((anychar, anychar, tag(" -> "), anychar)),
+ |(p1, p2, _, r)| ([p1, p2], r),
+ )(input)
+}