Compare commits

...

2 commits

Author SHA1 Message Date
Antoine Martin 9d81739f2b 2021: day14: fix stack overflow in part 1 2021-12-14 13:39:48 +01:00
Antoine Martin 218d9d5298 2021: day14: part 1 2021-12-14 13:35:35 +01:00
5 changed files with 297 additions and 0 deletions

102
aoc2021/input/day14.txt Normal file
View file

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

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

174
aoc2021/src/day14.rs Normal file
View file

@ -0,0 +1,174 @@
use std::collections::{HashMap, HashSet, LinkedList};
use std::fmt::Write;
use anyhow::{Context, Result};
const INPUT: &str = include_str!("../input/day14.txt");
pub fn run() -> Result<String> {
let mut res = String::with_capacity(128);
writeln!(res, "part 1: {}", part1(INPUT)?)?;
Ok(res)
}
fn part1(input: &str) -> Result<usize> {
let (polymer, rules) = input.split_once("\n\n").context("couldn't split input")?;
let mut polymer: Polymer = polymer.parse()?;
let rules: Rules = rules.parse()?;
let mut molecule_set = polymer.molecule_set();
rules.0.values().for_each(|v| {
molecule_set.insert(*v);
});
for _ in 0..10 {
polymer.insert_pairs(&rules.0)?;
}
let occurrences = polymer.compute_occurrences(&molecule_set);
let (_, least_common_occurrences) = occurrences
.iter()
.min_by_key(|(_, occurrences)| occurrences)
.unwrap();
let (_, most_common_occurrences) = occurrences
.iter()
.max_by_key(|(_, occurrences)| occurrences)
.unwrap();
Ok(most_common_occurrences - least_common_occurrences)
}
struct Rules(HashMap<(char, char), char>);
impl std::str::FromStr for Rules {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self> {
Ok(Self(
s.lines()
.map(str::trim)
.map(|l| {
let (pair, res) = l.split_once(" -> ").context("couldn't parse rule")?;
Ok((
(
pair.chars().next().context("")?,
pair.chars().nth(1).context("")?,
),
res.chars().next().context("couldn't parse rule")?,
))
})
.collect::<Result<_>>()?,
))
}
}
#[derive(Debug)]
struct Polymer {
molecules: Option<LinkedList<char>>,
}
impl Polymer {
fn insert_pairs(&mut self, rules: &HashMap<(char, char), char>) -> Result<()> {
debug_assert!(self.molecules.is_some());
self.molecules = Some(insert_pairs(
std::mem::replace(&mut self.molecules, None).unwrap(),
rules,
)?);
Ok(())
}
fn compute_occurrences(&self, molecule_set: &HashSet<char>) -> Vec<(char, usize)> {
debug_assert!(self.molecules.is_some());
let mut res = Vec::new();
for molecule in molecule_set {
let count = self
.molecules
.as_ref()
.unwrap() // we always have a Some, Option only used for std::mem::replace
.iter()
.filter(|&m| m == molecule)
.count();
res.push((*molecule, count));
}
res
}
fn molecule_set(&self) -> HashSet<char> {
debug_assert!(self.molecules.is_some());
self.molecules.as_ref().unwrap().iter().copied().collect()
}
}
impl std::str::FromStr for Polymer {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self> {
let molecules = s.trim().chars().collect();
Ok(Polymer {
molecules: Some(molecules),
})
}
}
fn insert_pairs(
molecules: LinkedList<char>,
rules: &HashMap<(char, char), char>,
) -> Result<LinkedList<char>> {
if molecules.len() <= 1 {
return Ok(molecules);
}
let mut head = molecules;
let mut tail = head.split_off(0);
while tail.len() > 1 {
// List length is at least 2
let mut iter = tail.iter();
let (left, right) = (*iter.next().unwrap(), *iter.next().unwrap());
let to_insert = *rules
.get(&(left, right))
.with_context(|| format!("couldn't find rule for pair ({}, {})", left, right))?;
// tail = left
// new_tail = right -> rest
let new_tail = tail.split_off(1);
// head = head -> left
head.append(&mut tail);
// head = head -> left -> to_insert
head.push_back(to_insert);
// tail = right -> rest
tail = new_tail;
}
head.append(&mut tail);
Ok(head)
}
#[cfg(test)]
mod tests {
use super::*;
const PROVIDED: &str = include_str!("../input/day14_provided.txt");
#[test]
fn part1_provided() {
assert_eq!(part1(PROVIDED).unwrap(), 1588);
}
#[test]
fn part1_real() {
assert_eq!(part1(INPUT).unwrap(), 3247);
}
}

View file

@ -13,3 +13,4 @@ pub mod day10;
pub mod day11; pub mod day11;
pub mod day12; pub mod day12;
pub mod day13; pub mod day13;
pub mod day14;

View file

@ -15,6 +15,7 @@ use aoc2021::day10;
use aoc2021::day11; use aoc2021::day11;
use aoc2021::day12; use aoc2021::day12;
use aoc2021::day13; use aoc2021::day13;
use aoc2021::day14;
fn main() -> Result<()> { fn main() -> Result<()> {
let days: &[DayFunc] = &[ let days: &[DayFunc] = &[
@ -31,6 +32,7 @@ fn main() -> Result<()> {
day11::run, day11::run,
day12::run, day12::run,
day13::run, day13::run,
day14::run,
]; ];
aoc::run(days) aoc::run(days)