1use crate::util::iter::*;
14use crate::util::parse::*;
15
16pub struct Rule<'a> {
17 start: usize,
18 end: usize,
19 letter: u8,
20 password: &'a [u8],
21}
22
23impl Rule<'_> {
24 fn from([a, b, c, d]: [&str; 4]) -> Rule<'_> {
25 Rule {
26 start: a.unsigned(),
27 end: b.unsigned(),
28 letter: c.as_bytes()[0],
29 password: d.as_bytes(),
30 }
31 }
32}
33
34pub fn parse(input: &str) -> Vec<Rule<'_>> {
35 input
36 .split(['-', ':', ' ', '\n'])
37 .filter(|s| !s.is_empty())
38 .chunk::<4>()
39 .map(Rule::from)
40 .collect()
41}
42
43pub fn part1(input: &[Rule<'_>]) -> usize {
44 input
45 .iter()
46 .filter(|rule| {
47 let count = rule.password.iter().filter(|&&l| l == rule.letter).count();
48 (rule.start..=rule.end).contains(&count)
49 })
50 .count()
51}
52
53pub fn part2(input: &[Rule<'_>]) -> usize {
54 input
55 .iter()
56 .filter(|rule| {
57 let first = rule.password[rule.start - 1] == rule.letter;
58 let second = rule.password[rule.end - 1] == rule.letter;
59 first ^ second
60 })
61 .count()
62}