summaryrefslogtreecommitdiff
path: root/2021/day3/src/main.rs
blob: d943de05ad9c80c5ee05c3262241d295bd9bc78c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
use std::fs;
use std::path::Path;

const ENTRY_LENGTH: usize = 12;

/* AOC21 Day 3: https://adventofcode.com/2021/day/3 */
fn main() {
    let input = Path::new("resources").join("input.txt");
    let content = fs::read_to_string(input).expect("Unable to read input file");
    let report: Vec<u32> = content.lines().map(|l| u32::from_str_radix(l,2).expect("Malformed input")).collect();
    ex1(&report);
    ex2(report);
}

fn ex1(report: &[u32]) {
    let gamma = compute_gamma(&report);
    let epsilon = compute_epsilon(gamma);
    println!("Ex1: the result is {} ({} * {})", gamma*epsilon, gamma, epsilon);
}

fn compute_gamma(report: &[u32]) -> u32 {
    let length = report.len() as u32;
    let mut counter: Vec<u32> = vec![0; ENTRY_LENGTH];
    report.iter().for_each(|entry| counter.iter_mut().enumerate().for_each(|(i,v)| *v += (entry >> i) & 1));
    counter.iter().enumerate().map(|(i,v)| if v*2 > length { 1 << i } else { 0 }).sum()
}

fn compute_epsilon(gamma: u32) -> u32 {
    gamma ^ ((1 << ENTRY_LENGTH)-1)
}

fn ex2(report: Vec<u32>) {
    let o2 = compute_rating(report.clone(), ENTRY_LENGTH, 1);
    let co2 = compute_rating(report, ENTRY_LENGTH, 0);
    println!("Ex2: the result is {} ({} * {})", o2*co2, o2, co2);
}

fn compute_rating(mut ratings: Vec<u32>, bit: usize, criterion: u32) -> u32 {
    if ratings.len() == 1 || bit == 0 {
        ratings[0]
    } else {
        let ones = ratings.iter().filter(|&r| ((r >> bit-1) & 1) == 1).count();
        let sel = if 2*ones < ratings.len() { 1^criterion } else { criterion };
        ratings.retain(|&r| ((r >> bit-1) & 1) == sel);
        compute_rating(ratings, bit-1, criterion)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    const TEST_INPUT: [u32;12] = [0b00100, 0b11110, 0b10110, 0b10111, 0b10101, 0b01111, 0b00111, 0b11100, 0b10000, 0b11001, 0b00010, 0b01010];
    const ENTRY_LENGTH: usize = 5;

    #[test]
    fn oxygen_generator_rating() {
        assert_eq!(23,compute_rating(Vec::from(TEST_INPUT), ENTRY_LENGTH, 1))
    }

    #[test]
    fn co2_scrubber_rating() {
        assert_eq!(10,compute_rating(Vec::from(TEST_INPUT), ENTRY_LENGTH, 0))
    }
}