diff --git a/Cargo.toml b/Cargo.toml index 6044e5e..878e8fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,3 +54,7 @@ path = "src/day12.rs" [[bin]] name = "day13" path = "src/day13.rs" + +[[bin]] +name = "day14" +path = "src/day14.rs" diff --git a/inputs/day14.txt b/inputs/day14.txt new file mode 100644 index 0000000..ec9b021 --- /dev/null +++ b/inputs/day14.txt @@ -0,0 +1,102 @@ +CNBPHFBOPCSPKOFNHVKV + +CS -> S +FB -> F +VK -> V +HO -> F +SO -> K +FK -> B +VS -> C +PS -> H +HH -> P +KH -> V +PV -> V +CB -> N +BB -> N +HB -> B +HV -> O +NC -> H +NF -> B +HP -> B +HK -> S +SF -> O +ON -> K +VN -> V +SB -> H +SK -> H +VH -> N +KN -> C +CC -> N +BF -> H +SN -> N +KP -> B +FO -> N +KO -> V +BP -> O +OK -> F +HC -> B +NH -> O +SP -> O +OO -> S +VC -> O +PC -> F +VB -> O +FF -> S +BS -> F +KS -> F +OV -> P +NB -> O +CF -> F +SS -> V +KV -> K +FP -> F +KC -> C +PF -> C +OS -> C +PN -> B +OP -> C +FN -> F +OF -> C +NP -> C +CK -> N +BN -> K +BO -> K +OH -> S +BH -> O +SH -> N +CH -> K +PO -> V +CN -> N +BV -> F +FV -> B +VP -> V +FS -> O +NV -> P +PH -> C +HN -> P +VV -> C +NK -> K +CO -> N +NS -> P +VO -> P +CP -> V +OC -> S +PK -> V +NN -> F +SC -> P +BK -> F +BC -> P +FH -> B +OB -> O +FC -> N +PB -> N +VF -> N +PP -> S +HS -> O +HF -> N +KK -> C +KB -> N +SV -> N +KF -> K +CV -> N +NO -> P diff --git a/src/day14.rs b/src/day14.rs new file mode 100644 index 0000000..264b736 --- /dev/null +++ b/src/day14.rs @@ -0,0 +1,82 @@ +use std::collections::HashMap; + +fn expand(depth: usize, left: char, right: char, rules: &[(char, char, char)], elements: &mut HashMap) { + if depth == 0 { + return; + } + match rules.iter().find(|rule| rule.0 == left && rule.1 == right) { + Some(rule) => { + let counter = elements.entry(rule.2).or_insert(0); + *counter += 1; + expand(depth - 1, left, rule.2, rules, elements); + expand(depth - 1, rule.2, right, rules, elements); + } + None => {} + } +} + +fn polymerize(depth: usize, template: &str, rules: &[(char, char, char)]) -> (usize, usize) { + let mut elements: HashMap = HashMap::new(); + + let chars = template.chars().collect::>(); + for pair in chars.windows(2) { + let (left, right) = (pair[0], pair[1]); + let counter = elements.entry(left).or_insert(0); + *counter += 1; + expand(depth, left, right, rules, &mut elements); + } + + // Add the last (right-side) element. + let counter = elements.entry(*chars.last().unwrap()).or_insert(0); + *counter += 1; + + let least_common = elements.iter().min_by(|x, y| x.1.cmp(y.1)).unwrap().1; + let most_common = elements.iter().max_by(|x, y| x.1.cmp(y.1)).unwrap().1; + (*least_common, *most_common) +} + +fn main() { + const INPUT: &str = include_str!("../inputs/day14.txt"); + let (template, rules) = INPUT.split_once("\n\n").unwrap(); + let (least_common, most_common) = polymerize( + 10, + template, + &rules + .lines() + .map(|rule| rule.split_once(" -> ").unwrap()) + .map(|(a, b)| { + let mut pair = a.chars(); + ( + pair.next().unwrap(), + pair.next().unwrap(), + b.chars().next().unwrap(), + ) + }) + .collect::>(), + ); + println!("solution {}", most_common - least_common); +} + +#[test] +fn test_polymerize() { + let rules = [ + ('C', 'H', 'B'), + ('H', 'H', 'N'), + ('C', 'B', 'H'), + ('N', 'H', 'C'), + ('H', 'B', 'C'), + ('H', 'C', 'B'), + ('H', 'N', 'C'), + ('N', 'N', 'C'), + ('B', 'H', 'H'), + ('N', 'C', 'B'), + ('N', 'C', 'B'), + ('N', 'B', 'B'), + ('B', 'N', 'B'), + ('B', 'B', 'N'), + ('B', 'C', 'B'), + ('C', 'C', 'N'), + ('C', 'N', 'C'), + ]; + assert_eq!(polymerize(10, "NNCB", &rules), (161, 1749)); +}