Skip to main content

advent_of_code/year2020/
day06.rs

1use crate::input::Input;
2use std::ops::{BitAnd, BitOr};
3
4type AnswersBitSet = u32;
5
6/// Convert the yes answers of a person, as a string of a-z characters identifying
7/// the questions the person answered yes to, to a bit set where:
8/// - First bit is set if question 'a' has been answered with yes.
9/// - Second bit is set if question 'b' has been answered with yes.
10/// - ...
11fn person_answers_to_bit_set(answers: &str) -> AnswersBitSet {
12    answers
13        .bytes()
14        .map(|question_identifier| 1 << (question_identifier - b'a'))
15        .sum::<AnswersBitSet>()
16}
17
18pub fn solve(input: &Input) -> Result<AnswersBitSet, String> {
19    const GROUP_SEPARATOR: &str = "\n\n";
20
21    if !input.text.bytes().all(|b| matches!(b, b'a'..=b'z' | b'\n')) {
22        return Err("Invalid input - only a-z, \\n expected".to_string());
23    }
24
25    let initial_bit_set = input.part_values(0, AnswersBitSet::MAX);
26
27    let bit_set_merger = if input.is_part_one() {
28        BitOr::bitor
29    } else {
30        BitAnd::bitand
31    };
32
33    let computer = |text: &str| {
34        Ok(text
35            .split(GROUP_SEPARATOR)
36            .map(|group_answers| {
37                group_answers
38                    .lines()
39                    .map(person_answers_to_bit_set)
40                    .fold(initial_bit_set, bit_set_merger)
41                    .count_ones()
42            })
43            .sum())
44    };
45
46    computer(input.text)
47}
48
49#[test]
50pub fn tests() {
51    test_part_one_no_allocations!("abc\n\nabc" => 6);
52
53    let real_input = include_str!("day06_input.txt");
54    test_part_one_no_allocations!(real_input => 6686);
55    test_part_two_no_allocations!(real_input => 3476);
56}