Compare commits

...

2 commits

Author SHA1 Message Date
37293ab29e 2021 day14/rust: add solution 2021-12-15 19:54:39 +01:00
7828e5a9d2 2021 day14: add data 2021-12-15 19:39:37 +01:00
4 changed files with 265 additions and 0 deletions

2
2021/data/day14.expected Normal file
View file

@ -0,0 +1,2 @@
2068
2158894777814

102
2021/data/day14.input Normal file
View file

@ -0,0 +1,102 @@
KFFNFNNBCNOBCNPFVKCP
PB -> F
KC -> F
OB -> H
HV -> N
FS -> S
CK -> K
CC -> V
HF -> K
VP -> C
CP -> S
HO -> N
OS -> N
HS -> O
HB -> F
OH -> V
PP -> B
BS -> N
VS -> F
CN -> B
KB -> O
KH -> B
SS -> K
NS -> B
BP -> V
FB -> S
PV -> O
NB -> S
FC -> F
VB -> P
PC -> O
VF -> K
BV -> K
OO -> B
PN -> N
NH -> H
SP -> B
KF -> O
BN -> F
OF -> C
VV -> H
BB -> P
KN -> H
PO -> C
BH -> O
HC -> B
VO -> O
FV -> B
PK -> V
KO -> H
BK -> V
SC -> S
KV -> B
OV -> S
HK -> F
NP -> V
VH -> P
OK -> S
SO -> C
PF -> C
SH -> N
FP -> V
CS -> C
HH -> O
KK -> P
BF -> S
NN -> O
OC -> C
CB -> O
BO -> V
ON -> F
BC -> P
NO -> N
KS -> H
FF -> V
FN -> V
HP -> N
VC -> F
OP -> K
VN -> S
NV -> F
SV -> F
FO -> V
PS -> H
VK -> O
PH -> P
NF -> N
KP -> S
CF -> S
FK -> P
FH -> F
CO -> H
SN -> B
NC -> H
SK -> P
CV -> P
CH -> H
HN -> N
SB -> H
NK -> B
SF -> H

View file

@ -0,0 +1,9 @@
[package]
name = "day14_rs"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nom = "7.1.0"

View file

@ -0,0 +1,152 @@
#![warn(clippy::pedantic)]
use nom::{
bytes::complete::{tag, take_till},
character::complete::{anychar, newline},
combinator::recognize,
multi::many1,
sequence::{pair, separated_pair, terminated},
};
use std::collections::BTreeMap;
use std::io::{stdin, Read};
use std::ops::Add;
type Input<'a> = &'a str;
type IResult<'a, T> = nom::IResult<Input<'a>, T>;
type Rule = ((char, char), char);
fn rule(i: Input) -> IResult<Rule> {
separated_pair(pair(anychar, anychar), tag(" -> "), anychar)(i)
}
fn parse_input(i: Input) -> IResult<(&str, Vec<Rule>)> {
separated_pair(
terminated(recognize(take_till(|c| c == '\n')), newline),
newline,
many1(terminated(rule, newline)),
)(i)
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct Counter<T> {
counts: BTreeMap<T, usize>,
}
impl<T: Ord> Counter<T> {
pub fn new() -> Self {
Self {
counts: BTreeMap::new(),
}
}
pub fn push(&mut self, el: T) {
*self.counts.entry(el).or_insert(0) += 1;
}
pub fn most_common(&self) -> Option<(&T, usize)> {
self.counts
.iter()
.map(|(el, count)| (el, *count))
.max_by_key(|&(_, count)| count)
}
pub fn least_common(&self) -> Option<(&T, usize)> {
self.counts
.iter()
.map(|(el, count)| (el, *count))
.min_by_key(|&(_, count)| count)
}
}
impl<T: Ord> FromIterator<T> for Counter<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut counts = Self::new();
for el in iter {
counts.push(el);
}
counts
}
}
impl<T: Ord + Copy> Add<&Counter<T>> for Counter<T> {
type Output = Self;
fn add(mut self, other: &Self) -> Self {
for (el, count) in &other.counts {
*self.counts.entry(*el).or_insert(0) += count;
}
self
}
}
impl<T: Ord> Add for Counter<T> {
type Output = Self;
fn add(mut self, other: Self) -> Self {
for (el, count) in other.counts {
*self.counts.entry(el).or_insert(0) += count;
}
self
}
}
#[derive(Clone, Debug)]
struct LetterCounter {
rules: BTreeMap<(char, char), char>,
counts: BTreeMap<(char, char, usize), Counter<char>>,
}
impl LetterCounter {
pub fn new(rules: BTreeMap<(char, char), char>) -> Self {
let mut counts = BTreeMap::new();
for &(left, right) in rules.keys() {
counts.insert((left, right, 0), Counter::from_iter([left]));
}
Self { rules, counts }
}
pub fn get_counts_right_exclusive(
&mut self,
left: char,
right: char,
depth: usize,
) -> &Counter<char> {
#[allow(clippy::map_entry)] // lifetimes don't work out
if !self.counts.contains_key(&(left, right, depth)) {
let middle = self.rules[&(left, right)];
let counts_left = self
.get_counts_right_exclusive(left, middle, depth - 1)
.clone();
let counts_right = self.get_counts_right_exclusive(middle, right, depth - 1);
let counts = counts_left + counts_right;
self.counts.insert((left, right, depth), counts);
}
&self.counts[&(left, right, depth)]
}
}
fn main() {
let mut input = String::new();
stdin().lock().read_to_string(&mut input).unwrap();
let (input, rules) = parse_input(&input).unwrap().1;
let rules: BTreeMap<_, _> = rules.into_iter().collect();
let chars: Vec<_> = input.chars().collect();
let mut counter = LetterCounter::new(rules);
let mut run = |steps| {
let mut totals = chars.windows(2).fold(Counter::new(), |counts, x| {
counts + counter.get_counts_right_exclusive(x[0], x[1], steps)
});
totals.push(*chars.last().unwrap());
println!(
"{:?}",
totals.most_common().unwrap().1 - totals.least_common().unwrap().1
);
};
run(10);
run(40);
}