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