diff options
Diffstat (limited to '2021/day03/src/main.rs')
-rw-r--r-- | 2021/day03/src/main.rs | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/2021/day03/src/main.rs b/2021/day03/src/main.rs new file mode 100644 index 0000000..d943de0 --- /dev/null +++ b/2021/day03/src/main.rs | |||
@@ -0,0 +1,65 @@ | |||
1 | use std::fs; | ||
2 | use std::path::Path; | ||
3 | |||
4 | const ENTRY_LENGTH: usize = 12; | ||
5 | |||
6 | /* AOC21 Day 3: https://adventofcode.com/2021/day/3 */ | ||
7 | fn main() { | ||
8 | let input = Path::new("resources").join("input.txt"); | ||
9 | let content = fs::read_to_string(input).expect("Unable to read input file"); | ||
10 | let report: Vec<u32> = content.lines().map(|l| u32::from_str_radix(l,2).expect("Malformed input")).collect(); | ||
11 | ex1(&report); | ||
12 | ex2(report); | ||
13 | } | ||
14 | |||
15 | fn ex1(report: &[u32]) { | ||
16 | let gamma = compute_gamma(&report); | ||
17 | let epsilon = compute_epsilon(gamma); | ||
18 | println!("Ex1: the result is {} ({} * {})", gamma*epsilon, gamma, epsilon); | ||
19 | } | ||
20 | |||
21 | fn compute_gamma(report: &[u32]) -> u32 { | ||
22 | let length = report.len() as u32; | ||
23 | let mut counter: Vec<u32> = vec![0; ENTRY_LENGTH]; | ||
24 | report.iter().for_each(|entry| counter.iter_mut().enumerate().for_each(|(i,v)| *v += (entry >> i) & 1)); | ||
25 | counter.iter().enumerate().map(|(i,v)| if v*2 > length { 1 << i } else { 0 }).sum() | ||
26 | } | ||
27 | |||
28 | fn compute_epsilon(gamma: u32) -> u32 { | ||
29 | gamma ^ ((1 << ENTRY_LENGTH)-1) | ||
30 | } | ||
31 | |||
32 | fn ex2(report: Vec<u32>) { | ||
33 | let o2 = compute_rating(report.clone(), ENTRY_LENGTH, 1); | ||
34 | let co2 = compute_rating(report, ENTRY_LENGTH, 0); | ||
35 | println!("Ex2: the result is {} ({} * {})", o2*co2, o2, co2); | ||
36 | } | ||
37 | |||
38 | fn compute_rating(mut ratings: Vec<u32>, bit: usize, criterion: u32) -> u32 { | ||
39 | if ratings.len() == 1 || bit == 0 { | ||
40 | ratings[0] | ||
41 | } else { | ||
42 | let ones = ratings.iter().filter(|&r| ((r >> bit-1) & 1) == 1).count(); | ||
43 | let sel = if 2*ones < ratings.len() { 1^criterion } else { criterion }; | ||
44 | ratings.retain(|&r| ((r >> bit-1) & 1) == sel); | ||
45 | compute_rating(ratings, bit-1, criterion) | ||
46 | } | ||
47 | } | ||
48 | |||
49 | #[cfg(test)] | ||
50 | mod tests { | ||
51 | use super::*; | ||
52 | |||
53 | const TEST_INPUT: [u32;12] = [0b00100, 0b11110, 0b10110, 0b10111, 0b10101, 0b01111, 0b00111, 0b11100, 0b10000, 0b11001, 0b00010, 0b01010]; | ||
54 | const ENTRY_LENGTH: usize = 5; | ||
55 | |||
56 | #[test] | ||
57 | fn oxygen_generator_rating() { | ||
58 | assert_eq!(23,compute_rating(Vec::from(TEST_INPUT), ENTRY_LENGTH, 1)) | ||
59 | } | ||
60 | |||
61 | #[test] | ||
62 | fn co2_scrubber_rating() { | ||
63 | assert_eq!(10,compute_rating(Vec::from(TEST_INPUT), ENTRY_LENGTH, 0)) | ||
64 | } | ||
65 | } | ||