Skip to main content

aoc/year2020/
day06.rs

1//! # Custom Customs
2//!
3//! This is a disguised binary question like the previous [`day 5`].
4//!
5//! We can store each passenger's answers as an implicit set in a `u32` since the cardinality
6//! is only 26. For each yes answer we set a bit, shifting left based on the letter. For example
7//! `acf` would be represented as `100101`.
8//!
9//! For part one to find groups where any person answered yes, we reduce the group using
10//! [bitwise OR](https://en.wikipedia.org/wiki/Bitwise_operation) then count the number of ones
11//! for each group using the blazing fast [`count_ones`] intrinsic.
12//!
13//! Part two is very similar, except that we use a bitwise AND instead. It is faster to run
14//! both parts at once during the parse.
15//!
16//! [`day 5`]: crate::year2020::day05
17//! [`count_ones`]: u32::count_ones
18use std::iter::once;
19
20type Input = (u32, u32);
21
22pub fn parse(input: &str) -> Input {
23    let mut any = 0_u32;
24    let mut all = u32::MAX;
25    let mut passenger = 0;
26    let mut part_one = 0;
27    let mut part_two = 0;
28    let mut check_group = false;
29
30    // End the input with a double newline, to include last group in the total.
31    for ch in input.bytes().chain(once(b'\n')) {
32        match ch {
33            b'\n' if check_group => {
34                // A second newline ends one group and prepares for the next.
35                check_group = false;
36                part_one += any.count_ones();
37                part_two += all.count_ones();
38                any = 0;
39                all = u32::MAX;
40            }
41            b'\n' => {
42                // A single newline separates passengers within a group.
43                any |= passenger;
44                all &= passenger;
45                passenger = 0;
46                check_group = true;
47            }
48            _ => {
49                // A letter sets the next bit for the given passenger.
50                // Masking to bits 1-26 is more efficient than subtracting to bits 0-25.
51                check_group = false;
52                passenger |= 1 << (ch & 31);
53            }
54        }
55    }
56
57    (part_one, part_two)
58}
59
60pub fn part1(input: &Input) -> u32 {
61    input.0
62}
63
64pub fn part2(input: &Input) -> u32 {
65    input.1
66}