feat: solve day 14 part 2
This commit is contained in:
parent
42ea48d4e9
commit
dccffe6ab1
148
src/day14.rs
148
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<InsertionRule>
|
||||
}
|
||||
|
||||
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<char>, rules: &Vec<InsertionRule>) -> Vec<char> {
|
||||
fn naive_expand_polymer(polymer: Vec<char>, rules: &HashMap<[char; 2], char>) -> Vec<char> {
|
||||
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<char>, rules: &Vec<InsertionRule>) -> Vec<char> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user