From 33e9af89beb42db8631f176016e70d5cd3a5c552 Mon Sep 17 00:00:00 2001 From: Joseph Montanaro Date: Wed, 29 Dec 2021 13:51:59 -0800 Subject: [PATCH] day 14 --- 2021/src/day14.rs | 83 +++++++++++++++++++++++++++++++++++++++++++++++ 2021/src/lib.rs | 57 ++++++++++++++++++++++++++++++-- 2021/src/main.rs | 6 ++-- 3 files changed, 141 insertions(+), 5 deletions(-) create mode 100644 2021/src/day14.rs diff --git a/2021/src/day14.rs b/2021/src/day14.rs new file mode 100644 index 0000000..ab0b04e --- /dev/null +++ b/2021/src/day14.rs @@ -0,0 +1,83 @@ +use std::collections::HashMap; + +use color_eyre::eyre; + +use crate::lib::{IterExt, Counter}; + + +type Pairs = Counter<(char, char)>; +type Rules = HashMap<(char, char), char>; + + +fn load(data: &str) -> eyre::Result<(Pairs, Rules)> { + let mut lines = data.lines(); + let template = lines.next().unwrap().to_string(); + let mut pairs = Counter::new(); + for i in 1..template.len() { + let a = template.as_bytes()[i - 1] as char; + let b = template.as_bytes()[i] as char; + pairs.inc((a, b)); + } + lines.next(); + + let mut rules = HashMap::new(); + for line in &mut lines { + let (pair_s, tgt_s) = line.split(" -> ").take_pair()?; + let pair = pair_s.chars().take_pair()?; + let tgt = tgt_s.chars().next().unwrap(); + rules.insert(pair, tgt); + } + + Ok((pairs, rules)) +} + + +fn expand(src: &Pairs, rules: &Rules) -> Pairs { + let mut dst = Counter::new(); + for (&(a, b), count) in src.iter() { + if let Some(&tween) = rules.get(&(a, b)) { + dst.inc_by((a, tween), count); + dst.inc_by((tween, b), count); + } + } + dst +} + + +fn score(pairs: &Pairs) -> usize { + // "score" is defined as the number of occurences of the most common + // character minus the number of occurrences of the least common + let mut firsts = Counter::new(); + let mut lasts = Counter::new(); + for (pair, count) in pairs.iter() { + let (a, b) = *pair; + firsts.inc_by(a, count); + lasts.inc_by(b, count); + } + + // the count of a given character is the number of times it appears + // in either first or last place of a pair, whichever is greater + let mut counts = Counter::new(); + for (c, count) in firsts.iter().chain(lasts.iter()) { + if count > counts.get(c) { + counts.set(*c, count); + } + } + + let max = counts.iter().map(|(_c, n)| n).max().unwrap(); + let min = counts.iter().map(|(_c, n)| n).min().unwrap(); + max - min +} + + +pub fn run(data: &str) -> eyre::Result<(usize, usize)> { + let (mut pairs, rules) = load(data)?; + + for _i in 0..10 {pairs = expand(&pairs, &rules);} + let one = score(&pairs); + + for _i in 0..30 {pairs = expand(&pairs, &rules);} + let two = score(&pairs); + + Ok((one, two)) +} \ No newline at end of file diff --git a/2021/src/lib.rs b/2021/src/lib.rs index eadc466..e725aac 100644 --- a/2021/src/lib.rs +++ b/2021/src/lib.rs @@ -1,9 +1,11 @@ use std::io::Read; use std::collections::VecDeque; -use std::str::FromStr; -use std::fs::File; +use std::collections::HashMap; use std::fmt::{Display, Formatter}; +use std::fs::File; +use std::hash::Hash; use std::ops::{Index, IndexMut}; +use std::str::FromStr; use color_eyre::{eyre}; use eyre::eyre; @@ -264,3 +266,54 @@ impl Display for Vec2 { Ok(()) } } + + +#[derive(Debug, Clone)] +pub struct Counter { + data: HashMap +} + +#[allow(dead_code)] +impl Counter + where K: Eq + Hash, +{ + pub fn new() -> Self { + Counter {data: HashMap::::new()} + } + + pub fn inc(&mut self, key: K) { + let v = self.data.entry(key).or_insert(0); + *v += 1; + } + + pub fn inc_by(&mut self, key: K, increment: usize) { + let v = self.data.entry(key).or_insert(0); + *v += increment; + } + + pub fn dec(&mut self, key: K) { + let v = self.data.entry(key).or_insert(0); + if *v > 0 { + *v -= 1; + } + } + + pub fn dec_by(&mut self, key: K, decrement: usize) { + let v = self.data.entry(key).or_insert(0); + if *v >= decrement { + *v -= decrement; + } + } + + pub fn get(&mut self, key: &K) -> usize { + *self.data.get(key).unwrap_or(&0) + } + + pub fn set(&mut self, key: K, value: usize) { + self.data.insert(key, value); + } + + pub fn iter(&self) -> impl Iterator { + self.data.iter().map(|(k, v)| (k, *v)) + } +} diff --git a/2021/src/main.rs b/2021/src/main.rs index 3100cb2..13e99ea 100644 --- a/2021/src/main.rs +++ b/2021/src/main.rs @@ -4,14 +4,14 @@ use color_eyre::eyre; mod lib; use lib::load; -mod day13; +mod day14; fn main() -> eyre::Result<()> { - let data = load("data/13.txt")?; + let data = load("data/14.txt")?; let start = Instant::now(); - let (one, two) = day13::run(&data)?; + let (one, two) = day14::run(&data)?; let (dur, unit) = format_ns(start.elapsed().as_nanos()); let precision = 2.0 - dur.log10().floor();