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",
|
||||
"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