add day 14

This commit is contained in:
LordMZTE 2021-12-14 19:09:17 +01:00
parent 12c10cf056
commit 99ec7923f2
5 changed files with 217 additions and 6 deletions

102
input/day14.txt Normal file
View file

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

View file

@ -1,2 +1,3 @@
pub mod day1;
pub mod day14;
pub mod day5;

107
src/days/day14.rs Normal file
View file

@ -0,0 +1,107 @@
#![libaoc::day(14, "../../input/day14.txt")]
use std::collections::HashMap;
use libaoc::miette::{bail, miette, Result};
fn part1() -> Result<()> {
run(10)
}
fn part2() -> Result<()> {
run(40)
}
fn run(iters: u8) -> Result<()> {
let Input { start, rules } = parse_input()?;
let mut solution = [0; 26];
solution[start[0] as usize] = 1;
let mut cache = HashMap::new();
for win in start.windows(2) {
solution = compute_pair((win[0], win[1]), &rules, iters, &mut cache)
.zip(solution)
.map(|(a, b)| a + b);
}
let min = solution.iter().filter(|&&n| n != 0).min().unwrap_or(&0);
let max = solution.iter().filter(|&&n| n != 0).max().unwrap_or(&0);
println!("{}", max - min);
Ok(())
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
struct CacheKey {
left: u8,
right: u8,
iter: u8,
}
// This big brain algo isn't by me. I found it in someone else's solutions, but fully understood
// and rewrote it.
fn compute_pair<'cache>(
pair: (u8, u8),
rules: &HashMap<(u8, u8), u8>,
iter: u8,
cache: &'cache mut HashMap<CacheKey, [u64; 26]>,
) -> &'cache [u64; 26] {
let key = CacheKey {
left: pair.0,
right: pair.1,
iter,
};
if !cache.contains_key(&key) {
if let (Some(&ins), 1..) = (rules.get(&pair), iter) {
let arr_a = *compute_pair((pair.0, ins), rules, iter - 1, cache);
let arr_b = *compute_pair((ins, pair.1), rules, iter - 1, cache);
let sum = arr_a.zip(arr_b).map(|(a, b)| a + b);
cache.insert(key, sum);
} else {
let mut arr = [0; 26];
arr[pair.1 as usize] = 1;
cache.insert(key, arr);
}
}
&cache[&key]
}
fn char_to_idx(c: char) -> u8 {
c as u8 - b'A'
}
struct Input {
start: Vec<u8>,
rules: HashMap<(u8, u8), u8>,
}
fn parse_input() -> Result<Input> {
let mut lines = INPUT.lines();
let poly = lines
.next()
.ok_or_else(|| miette!("input empty"))?
.chars()
.map(char_to_idx)
.collect();
let mut rules = HashMap::new();
for line in lines.skip(1) {
let mut line = line.chars();
let a = line.next();
let b = line.next();
let c = line.nth(4);
match (a, b, c) {
(Some(a), Some(b), Some(c)) => {
rules.insert((char_to_idx(a), char_to_idx(b)), char_to_idx(c));
}
_ => bail!("invalid input"),
}
}
Ok(Input { start: poly, rules })
}

View file

@ -1,7 +1,6 @@
#![libaoc::day(5, "../../input/day5.txt")]
use std::cmp::{max, min, Ordering};
use std::io::BufRead;
use std::cmp::{max, Ordering};
use libaoc::miette::{miette, IntoDiagnostic, Result};
@ -39,6 +38,8 @@ fn solve(diagonal: bool) -> Result<()> {
if x1 == x2 {
let (y1, y2) = small_large(y1, y2);
// this lint would actually make this more ugly
#[allow(clippy::needless_range_loop)]
for y in y1..=y2 {
mtx[y][x1] += 1;
}

View file

@ -1,13 +1,13 @@
#![feature(array_zip)]
#![feature(custom_inner_attributes)]
#![feature(linked_list_cursors)]
#![feature(proc_macro_hygiene)]
mod days;
mod util;
use days::*;
fn main() -> libaoc::miette::Result<()> {
libaoc::run_days!(
day1,
day5,
)
libaoc::run_days!(day1, day5, day14,)
}