Complete day 14
This commit is contained in:
parent
e3352bb5ec
commit
9599641ddc
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -115,3 +115,11 @@ dependencies = [
|
|||||||
"anyhow",
|
"anyhow",
|
||||||
"common",
|
"common",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day14"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"common",
|
||||||
|
]
|
||||||
|
10
crates/day14/Cargo.toml
Normal file
10
crates/day14/Cargo.toml
Normal 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" }
|
102
crates/day14/src/input/input.txt
Normal file
102
crates/day14/src/input/input.txt
Normal 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
|
18
crates/day14/src/input/test.txt
Normal file
18
crates/day14/src/input/test.txt
Normal 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
146
crates/day14/src/main.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user