This commit is contained in:
Quentin Boyer 2025-01-04 20:38:53 +01:00
parent cd4268a9ce
commit 10245f3faa

141
src/bin/day19.rs Normal file
View file

@ -0,0 +1,141 @@
use core::str;
use std::{collections::HashMap, time::Instant};
use aoc_2024::{load, print_res};
use bstr::BString;
use color_eyre::eyre::{bail, OptionExt};
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum Color {
White,
Blue,
Black,
Red,
Green,
}
impl Color {
fn from_b(b: u8) -> color_eyre::Result<Self> {
Ok(match b {
b'w' => Color::White,
b'u' => Color::Blue,
b'b' => Color::Black,
b'r' => Color::Red,
b'g' => Color::Green,
_ => bail!("Invalid color: {}", b as char),
})
}
}
type Parsed = (Vec<Vec<Color>>, Vec<Vec<Color>>);
#[inline(never)]
pub fn parsing(input: &BString) -> color_eyre::Result<Parsed> {
let (towels, patterns) = str::from_utf8(input)?
.split_once("\n\n")
.ok_or_eyre("Missing blank line")?;
let towels = towels
.split(", ")
.map(|towel| {
towel
.bytes()
.map(Color::from_b)
.collect::<Result<Vec<_>, _>>()
})
.collect::<Result<_, _>>()?;
let patterns = patterns
.lines()
.map(|line| {
line.bytes()
.map(Color::from_b)
.collect::<Result<Vec<_>, _>>()
})
.collect::<Result<_, _>>()?;
Ok((towels, patterns))
}
#[inline(never)]
pub fn part1((towels, patterns): Parsed) {
let mut possible = 0;
'pattern: for pattern in patterns {
let mut current = vec![&*pattern];
while let Some(v) = current.pop() {
if v.is_empty() {
possible += 1;
continue 'pattern;
}
for towel in &towels {
if v.starts_with(towel) {
current.push(&v[towel.len()..]);
}
}
}
}
print_res!("Number of possible patterns: {possible}");
}
#[inline(never)]
pub fn part2((towels, patterns): Parsed) {
let mut memo = HashMap::new();
memo.insert(&[][..], 1);
let mut possible = 0;
fn arrangements<'a>(
pattern: &'a [Color],
towels: &[Vec<Color>],
memo: &mut HashMap<&'a [Color], usize>,
) -> usize {
match memo.get(pattern) {
Some(&v) => v,
None => {
let value = towels
.iter()
.map(|towel| {
if pattern.starts_with(towel) {
arrangements(&pattern[towel.len()..], towels, memo)
} else {
0
}
})
.sum();
memo.insert(pattern, value);
value
}
}
}
for pattern in &patterns {
possible += arrangements(pattern, &towels, &mut memo);
}
print_res!("Number of possible arrangements: {possible}");
}
pub fn main() -> color_eyre::Result<()> {
let context = load()?;
let start = Instant::now();
let parsed = parsing(&context.input)?;
let elapsed = humantime::format_duration(start.elapsed());
let start = Instant::now();
if context.part == 1 {
part1(parsed);
} else {
part2(parsed);
}
let elapsed_part = humantime::format_duration(start.elapsed());
println!(" Parsing: {elapsed}");
println!(" Solving: {elapsed_part}");
Ok(())
}