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 = 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 = 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) { 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, 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)) } }