Complete day 14

This commit is contained in:
Tyler Hallada 2021-12-14 23:37:48 -05:00
parent e3352bb5ec
commit 9599641ddc
5 changed files with 284 additions and 0 deletions

8
Cargo.lock generated
View File

@ -115,3 +115,11 @@ dependencies = [
"anyhow",
"common",
]
[[package]]
name = "day14"
version = "0.1.0"
dependencies = [
"anyhow",
"common",
]

10
crates/day14/Cargo.toml Normal file
View File

@ -0,0 +1,10 @@
[package]
name = "day14"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0"
common = { path = "../common" }

View File

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

View File

@ -0,0 +1,18 @@
NNCB
CH -> B
HH -> N
CB -> H
NH -> C
HB -> C
HC -> B
HN -> C
NN -> C
BH -> H
NC -> B
NB -> B
BN -> B
BB -> N
BC -> B
CC -> N
CN -> C

146
crates/day14/src/main.rs Normal file
View File

@ -0,0 +1,146 @@
use anyhow::{anyhow, Result};
use common::instrument;
use std::collections::HashMap;
const INPUT: &str = include_str!("input/input.txt");
fn solve_part1(input: &str) -> Result<usize> {
let mut parts = input.split("\n\n");
let template = parts.next().ok_or(anyhow!("no template"))?;
let mut rules: HashMap<(char, char), char> = HashMap::new();
for rule in parts
.next()
.ok_or(anyhow!("no pair insertion rules"))?
.lines()
{
let mut rule_parts = rule.split(" -> ");
let pair: Vec<char> = rule_parts
.next()
.ok_or(anyhow!("no pair part of rule"))?
.chars()
.take(2)
.collect();
let insertion = rule_parts
.next()
.ok_or(anyhow!("no pair part of rule"))?
.chars()
.next()
.ok_or(anyhow!("empty insertion rule"))?;
rules.insert((pair[0], pair[1]), insertion);
}
let mut counts = HashMap::new();
for c in template.chars() {
*counts.entry(c).or_insert(0) += 1;
}
let mut polymer = template.chars().collect::<Vec<char>>();
for _ in 0..10 {
let mut insertions = vec![];
for (i, pair) in polymer.windows(2).enumerate() {
if let Some(insertion) = rules.get(&(pair[0], pair[1])) {
insertions.push((i + 1, *insertion));
*counts.entry(*insertion).or_insert(0) += 1;
}
}
for (i, (insertion_index, char)) in insertions.into_iter().enumerate() {
polymer.insert(insertion_index + i, char);
}
}
let max: (&char, &usize) = counts
.iter()
.max_by_key(|(_, count)| **count)
.ok_or(anyhow!("no max"))?;
let min: (&char, &usize) = counts
.iter()
.min_by_key(|(_, count)| **count)
.ok_or(anyhow!("no min"))?;
Ok(max.1 - min.1)
}
fn solve_part2(input: &str) -> Result<usize> {
let mut parts = input.split("\n\n");
let template = parts.next().ok_or(anyhow!("no template"))?;
let mut rules: HashMap<(char, char), char> = HashMap::new();
for rule in parts
.next()
.ok_or(anyhow!("no pair insertion rules"))?
.lines()
{
let mut rule_parts = rule.split(" -> ");
let pair: Vec<char> = rule_parts
.next()
.ok_or(anyhow!("no pair part of rule"))?
.chars()
.take(2)
.collect();
let insertion = rule_parts
.next()
.ok_or(anyhow!("no pair part of rule"))?
.chars()
.next()
.ok_or(anyhow!("empty insertion rule"))?;
rules.insert((pair[0], pair[1]), insertion);
}
let polymer = template.chars().collect::<Vec<char>>();
let mut pair_counts: HashMap<(char, char), usize> = HashMap::new();
for pair in polymer.windows(2) {
*pair_counts.entry((pair[0], pair[1])).or_insert(0) += 1;
}
for _ in 0..40 {
let mut new_pair_counts = HashMap::new();
for (pair, count) in pair_counts.into_iter() {
if let Some(insertion) = rules.get(&pair) {
*new_pair_counts.entry((pair.0, *insertion)).or_insert(0) += count;
*new_pair_counts.entry((*insertion, pair.1)).or_insert(0) += count;
}
}
pair_counts = new_pair_counts;
}
let mut counts = HashMap::new();
for ((first, _), count) in pair_counts.iter() {
*counts.entry(*first).or_insert(0) += count;
}
*counts
.entry(*polymer.last().ok_or(anyhow!("empty polymer"))?)
.or_insert(0) += 1;
let max: (&char, &usize) = counts
.iter()
.max_by_key(|(_, count)| **count)
.ok_or(anyhow!("no max"))?;
let min: (&char, &usize) = counts
.iter()
.min_by_key(|(_, count)| **count)
.ok_or(anyhow!("no min"))?;
Ok(max.1 - min.1)
}
fn main() {
instrument!(solve_part1(INPUT).unwrap(), solve_part2(INPUT).unwrap());
}
#[cfg(test)]
mod tests {
use super::*;
const TEST_INPUT: &str = include_str!("input/test.txt");
#[test]
fn solves_part1() {
assert_eq!(solve_part1(TEST_INPUT).unwrap(), 1588);
}
#[test]
fn solves_part2() {
assert_eq!(solve_part2(TEST_INPUT).unwrap(), 2188189693529);
}
}