From dccffe6ab194f67629bcf169f112b64c9fdf7047 Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Mon, 27 Dec 2021 19:12:20 +0200 Subject: [PATCH] feat: solve day 14 part 2 --- src/day14.rs | 148 ++++++++++++++++++++++++++++++++++++++------------- src/main.rs | 1 + 2 files changed, 111 insertions(+), 38 deletions(-) diff --git a/src/day14.rs b/src/day14.rs index 99ecde0..5650dc6 100644 --- a/src/day14.rs +++ b/src/day14.rs @@ -1,39 +1,34 @@ use std::collections::HashMap; -pub struct InsertionRule([char; 2], char); - pub struct InputData { polymer_template: String, - rules: Vec -} - -fn parse_rule(line: &str) -> InsertionRule { - let (pattern, expansion) = line.split_once(" -> ").unwrap(); - return InsertionRule( - [pattern.chars().nth(0).unwrap(), pattern.chars().nth(1).unwrap()], - expansion.chars().nth(0).unwrap() - ); + rules: HashMap<[char; 2], char> } pub fn parse_input(input: &str) -> InputData { let (polymer_template, rules_section) = input.split_once("\n\n").unwrap(); - let rules = rules_section.lines() - .map(parse_rule) - .collect(); + let mut rules = HashMap::new(); + for line in rules_section.lines() { + let (pattern, expansion) = line.split_once(" -> ").unwrap(); + rules.insert( + [pattern.chars().nth(0).unwrap(), pattern.chars().nth(1).unwrap()], + expansion.chars().nth(0).unwrap() + ); + } return InputData { polymer_template: polymer_template.into(), rules }; } -fn expand_polymer(polymer: Vec, rules: &Vec) -> Vec { +fn naive_expand_polymer(polymer: Vec, rules: &HashMap<[char; 2], char>) -> Vec { let mut new_polymer = Vec::new(); for i in 0..polymer.len()-1 { new_polymer.push(polymer[i]); - for rule in rules { - if rule.0[0] == polymer[i] && rule.0[1] == polymer[i+1] { - new_polymer.push(rule.1); - } + let pair = [polymer[i], polymer[i+1]]; + let rule = rules.get(&pair); + if rule != None { + new_polymer.push(*rule.unwrap()); } } new_polymer.push(*polymer.last().unwrap()); @@ -43,7 +38,7 @@ fn expand_polymer(polymer: Vec, rules: &Vec) -> Vec { pub fn part1(input: &InputData) -> u32 { let mut polymer = input.polymer_template.chars().collect(); for _ in 0..10 { - polymer = expand_polymer(polymer, &input.rules); + polymer = naive_expand_polymer(polymer, &input.rules); } let mut element_amounts = HashMap::new(); @@ -57,6 +52,58 @@ pub fn part1(input: &InputData) -> u32 { return most_common_element - least_common_element; } +fn expand_polymer(polymer_pairs: &HashMap<[char; 2], u64>, rules: &HashMap<[char; 2], char>) -> HashMap<[char; 2], u64> { + let mut new_pairs = HashMap::new(); + for entry in polymer_pairs { + let pair = entry.0; + if rules.contains_key(pair) { + let rule = *rules.get(pair).unwrap(); + + let left_pair = [pair[0], rule]; + let left_entry = new_pairs.entry(left_pair).or_insert(0); + *left_entry += entry.1; + + let right_pair = [rule, pair[1]]; + let right_entry = new_pairs.entry(right_pair).or_insert(0); + *right_entry += entry.1; + } else { + let new_entry = new_pairs.entry(*entry.0).or_insert(0); + *new_entry = *entry.1; + } + } + return new_pairs; + +} + +pub fn part2(input: &InputData) -> u64 { + let polymer_template = &input.polymer_template; + let mut polymer_pairs = HashMap::new(); + for i in 0..polymer_template.len()-1 { + let pair = [ + polymer_template.chars().nth(i).unwrap(), + polymer_template.chars().nth(i+1).unwrap() + ]; + let entry = polymer_pairs.entry(pair).or_insert(0); + *entry += 1; + } + + for _ in 0..40 { + polymer_pairs = expand_polymer(&polymer_pairs, &input.rules); + } + + let mut element_amounts = HashMap::new(); + for entry in polymer_pairs { + for c in entry.0 { + let amount = element_amounts.entry(c).or_insert(0); + *amount += entry.1; + } + } + + let least_common_element = element_amounts.iter().min_by(|a, b| a.1.cmp(b.1)).unwrap().1; + let most_common_element = element_amounts.iter().max_by(|a, b| a.1.cmp(b.1)).unwrap().1; + return (most_common_element - least_common_element)/2 + 1; +} + #[cfg(test)] mod tests { use super::*; @@ -64,25 +111,50 @@ mod tests { #[test] fn part1_example() { let polymer_template = String::from("NNCB"); - let rules = vec![ - InsertionRule(['C', 'H'], 'B'), - InsertionRule(['H', 'H'], 'N'), - InsertionRule(['C', 'B'], 'H'), - InsertionRule(['N', 'H'], 'C'), - InsertionRule(['H', 'B'], 'C'), - InsertionRule(['H', 'C'], 'B'), - InsertionRule(['H', 'N'], 'C'), - InsertionRule(['N', 'N'], 'C'), - InsertionRule(['B', 'H'], 'H'), - InsertionRule(['N', 'C'], 'B'), - InsertionRule(['N', 'B'], 'B'), - InsertionRule(['B', 'N'], 'B'), - InsertionRule(['B', 'B'], 'N'), - InsertionRule(['B', 'C'], 'B'), - InsertionRule(['C', 'C'], 'N'), - InsertionRule(['C', 'N'], 'C') - ]; + let rules = HashMap::from([ + (['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', 'B'], 'B'), + (['B', 'N'], 'B'), + (['B', 'B'], 'N'), + (['B', 'C'], 'B'), + (['C', 'C'], 'N'), + (['C', 'N'], 'C') + ]); let result = part1(&InputData { polymer_template, rules }); assert_eq!(result, 1588); } + + #[test] + fn part2_example() { + let polymer_template = String::from("NNCB"); + let rules = HashMap::from([ + (['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', 'B'], 'B'), + (['B', 'N'], 'B'), + (['B', 'B'], 'N'), + (['B', 'C'], 'B'), + (['C', 'C'], 'N'), + (['C', 'N'], 'C') + ]); + let result = part2(&InputData { polymer_template, rules }); + assert_eq!(result, 2188189693529); + } } diff --git a/src/main.rs b/src/main.rs index 4a95005..b9a0cd7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -55,6 +55,7 @@ fn run(day: i32, part: i32, input_filename: &str) { "13.1" => println!("{}", day13::part1(&day13::parse_input(&contents))), "13.2" => day13::part2(&day13::parse_input(&contents)), "14.1" => println!("{}", day14::part1(&day14::parse_input(&contents))), + "14.2" => println!("{}", day14::part2(&day14::parse_input(&contents))), _ => println!("Day {} part {} not found", day, part) } }