aoc/year2021/
day03.rs

1//! # Binary Diagnostic
2//!
3//! Part 1 uses bit manipulation to build up the binary numbers directly one digit at a time.
4//!
5//! Part 2 clones the input `vec` then uses [`retain`] to efficiently discard numbers that
6//! don't meet the criteria.
7//!
8//! [`retain`]: Vec::retain
9pub fn parse(input: &str) -> Vec<&[u8]> {
10    input.lines().map(str::as_bytes).collect()
11}
12
13pub fn part1(input: &[&[u8]]) -> u32 {
14    let mut gamma = 0;
15    let mut epsilon = 0;
16
17    for column in 0..input[0].len() {
18        let ones = ones(input, column);
19        let zeros = input.len() - ones;
20
21        gamma = (gamma << 1) | (ones > zeros) as u32;
22        epsilon = (epsilon << 1) | (zeros > ones) as u32;
23    }
24
25    gamma * epsilon
26}
27
28pub fn part2(input: &[&[u8]]) -> u32 {
29    let gamma = rating(input, |a, b| a >= b);
30    let epsilon = rating(input, |a, b| a < b);
31    gamma * epsilon
32}
33
34fn ones(numbers: &[&[u8]], i: usize) -> usize {
35    numbers.iter().filter(|b| b[i] == b'1').count()
36}
37
38fn rating(input: &[&[u8]], cmp: fn(usize, usize) -> bool) -> u32 {
39    let mut numbers = input.to_vec();
40    let mut column = 0;
41
42    while numbers.len() > 1 {
43        let ones = ones(&numbers, column);
44        let zeros = numbers.len() - ones;
45        let keep = if cmp(ones, zeros) { b'1' } else { b'0' };
46
47        numbers.retain(|n| n[column] == keep);
48        column += 1;
49    }
50
51    numbers[0].iter().fold(0, |acc, &n| (acc << 1) | (n == b'1') as u32)
52}