Day 19
This commit is contained in:
parent
cd4268a9ce
commit
10245f3faa
1 changed files with 141 additions and 0 deletions
141
src/bin/day19.rs
Normal file
141
src/bin/day19.rs
Normal 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(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue