use utils::prelude::*;
#[derive(Clone, Debug)]
pub struct Day05<'a> {
lines: Vec<&'a [u8]>,
}
impl<'a> Day05<'a> {
pub fn new(input: &'a str, _: InputType) -> Result<Self, InputError> {
Ok(Self {
lines: parser::take_while1(u8::is_ascii_lowercase)
.error_msg("expected a-z")
.parse_lines(input)?,
})
}
#[must_use]
#[expect(clippy::eq_op)]
pub fn part1(&self) -> usize {
const VOWELS: u32 = 1 << (b'a' - b'a')
| 1 << (b'e' - b'a')
| 1 << (b'i' - b'a')
| 1 << (b'o' - b'a')
| 1 << (b'u' - b'a');
self.lines
.iter()
.filter(|&&l| l.windows(2).any(|w| w[0] == w[1]))
.filter(|&&l| {
l.iter()
.filter(|&&b| VOWELS & (1 << (b - b'a')) != 0)
.count()
>= 3
})
.filter(|&&l| l.windows(2).all(|w| w != b"ab"))
.filter(|&&l| l.windows(2).all(|w| w != b"cd"))
.filter(|&&l| l.windows(2).all(|w| w != b"pq"))
.filter(|&&l| l.windows(2).all(|w| w != b"xy"))
.count()
}
#[must_use]
pub fn part2(&self) -> usize {
let mut pair_positions = [0u32; 729];
let mut pos = 0;
self.lines
.iter()
.filter(|&&l| l.windows(3).any(|w| w[0] == w[2]))
.filter(|&&l| {
let string_start = pos;
l.windows(2).any(|w| {
let pair = 26 * (w[0] - b'a') as usize + (w[1] - b'a') as usize;
if pair_positions[pair] > string_start {
if pair_positions[pair] < pos {
return true;
}
} else {
pair_positions[pair] = pos + 1;
}
pos += 1;
false
})
})
.count()
}
}
examples!(Day05<'_> -> (usize, usize) [
{input: "ugknbfddgicrmopn", part1: 1},
{input: "aaa", part1: 1, part2: 0},
{input: "aaaa", part1: 1, part2: 1},
{input: "jchzalrnumimnmhp", part1: 0},
{input: "haegwjzuvuyypxyu", part1: 0},
{input: "dvszwmarrgswjxmb", part1: 0},
{input: "qjhvhtzxzqqjkmpb", part2: 1},
{input: "xxyxx", part2: 1},
{input: "uurcxstgmygtbstg", part2: 0},
{input: "ieodomkazucvgmuy", part2: 0},
]);