aoc-rs-2021/src/day_14/model.rs
Jan Christian Grünhage 403be5d4da implement day 14
2021-12-16 00:08:46 +01:00

103 lines
2.8 KiB
Rust

use std::{collections::HashMap, str::FromStr};
use itertools::Itertools;
#[derive(Clone)]
pub struct Polymer {
pub first: char,
pub last: char,
pub map: HashMap<(char, char), usize>,
}
impl FromStr for Polymer {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut map = HashMap::new();
for neighbours in s.chars().tuple_windows::<(char, char)>() {
map.entry(neighbours)
.and_modify(|count| *count += 1)
.or_insert(1);
}
let first = s.chars().next().unwrap();
let last = s.chars().last().unwrap();
Ok(Self { first, last, map })
}
}
#[derive(Copy, Clone)]
pub struct Rule {
pub neighbours: (char, char),
pub separator: char,
}
pub struct Rules {
pub map: HashMap<(char, char), char>,
}
impl TryFrom<Vec<Rule>> for Rules {
type Error = &'static str;
fn try_from(rule_vec: Vec<Rule>) -> Result<Self, Self::Error> {
if rule_vec.is_empty() {
return Err("rule set can't be empty");
}
let mut rules = Rules {
map: Default::default(),
};
for rule in rule_vec {
if rules.map.contains_key(&rule.neighbours) {
return Err("ambigous rule set");
}
rules.map.insert(rule.neighbours, rule.separator);
}
Ok(rules)
}
}
impl Polymer {
pub fn apply(&mut self, rules: &Rules) {
let mut new_map = HashMap::new();
for (neighbours, count) in self.map.iter() {
if let Some(separator) = rules.map.get(neighbours) {
new_map
.entry((neighbours.0, *separator))
.and_modify(|old_count| *old_count += count)
.or_insert(*count);
new_map
.entry((*separator, neighbours.1))
.and_modify(|old_count| *old_count += count)
.or_insert(*count);
} else {
new_map
.entry(*neighbours)
.and_modify(|old_count| *old_count += count)
.or_insert(*count);
}
}
self.map = new_map
}
pub fn element_counts(&self) -> HashMap<char, usize> {
let mut map = HashMap::new();
map.insert(self.first, 1);
map.insert(self.last, 1);
for ((left, right), count) in self.map.iter() {
map.entry(*left)
.and_modify(|old_count| *old_count += count)
.or_insert(*count);
map.entry(*right)
.and_modify(|old_count| *old_count += count)
.or_insert(*count);
}
map.iter()
.map(|(element, count)| (*element, count / 2))
.collect()
}
}
pub struct Input {
pub polymer: Polymer,
pub rules: Rules,
}