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 let start = a.unsigned();
25 let end = b.unsigned();
26 let letter = c.as_bytes()[0];
27 let password = d.as_bytes();
28 Rule { start, end, letter, password }
29 }
30}
31
32pub fn parse(input: &str) -> Vec<Rule<'_>> {
33 input
34 .split(['-', ':', ' ', '\n'])
35 .filter(|s| !s.is_empty())
36 .chunk::<4>()
37 .map(Rule::from)
38 .collect()
39}
40
41pub fn part1(input: &[Rule<'_>]) -> usize {
42 input
43 .iter()
44 .filter(|rule| {
45 let count = rule.password.iter().filter(|&&l| l == rule.letter).count();
46 rule.start <= count && count <= rule.end
47 })
48 .count()
49}
50
51pub fn part2(input: &[Rule<'_>]) -> usize {
52 input
53 .iter()
54 .filter(|rule| {
55 let first = rule.password[rule.start - 1] == rule.letter;
56 let second = rule.password[rule.end - 1] == rule.letter;
57 first ^ second
58 })
59 .count()
60}