From 6d72191e2ce5d423ca03c894d2dad1d3061bd4f3 Mon Sep 17 00:00:00 2001 From: Justin Wernick Date: Tue, 19 Apr 2022 20:27:29 +0200 Subject: Refile for merging repos --- 2021/src/bin/day_3.rs | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 2021/src/bin/day_3.rs (limited to '2021/src/bin/day_3.rs') diff --git a/2021/src/bin/day_3.rs b/2021/src/bin/day_3.rs new file mode 100644 index 0000000..2238dfb --- /dev/null +++ b/2021/src/bin/day_3.rs @@ -0,0 +1,128 @@ +use nom::{ + character::complete::{digit1, line_ending}, + combinator::{map, map_res}, + multi::separated_list1, + IResult, +}; +use std::fs; + +fn main() -> Result<(), Box> { + let input = fs::read_to_string("inputs/day_3.txt")?; + let diagnostics = parse_diagnostics(&input).unwrap().1; + + dbg!(diagnostics.gamma()); + dbg!(diagnostics.epsilon()); + dbg!(diagnostics.oxygen()); + dbg!(diagnostics.co2()); + dbg!(diagnostics.gamma() * diagnostics.epsilon()); + dbg!(diagnostics.oxygen() * diagnostics.co2()); + + Ok(()) +} + +#[derive(Debug, Clone)] +struct Diagnostics { + bitsets: Vec, + bitset_len: usize, +} + +impl Diagnostics { + fn new(bitsets: Vec) -> Diagnostics { + Diagnostics { + bitset_len: bitsets.iter().map(|b| b.len).max().unwrap_or(0), + bitsets, + } + } + + fn gamma(&self) -> Bitset { + let mut gamma = Bitset { + bits: 0, + len: self.bitset_len, + }; + for bit in 0..gamma.len { + let ones_count = self + .bitsets + .iter() + .filter(|bitset| bitset.check_bit(bit)) + .count(); + if ones_count >= self.bitsets.len() / 2 { + gamma.set_bit(bit); + } + } + gamma + } + + fn epsilon(&self) -> Bitset { + !self.gamma() + } + + fn oxygen(&self) -> Bitset { + self.bit_criteria_match(|d| d.gamma()) + } + + fn co2(&self) -> Bitset { + self.bit_criteria_match(|d| d.epsilon()) + } + + fn bit_criteria_match(&self, criteria: impl Fn(&Diagnostics) -> Bitset) -> Bitset { + let mut candidates = self.clone(); + for bit in (0..self.bitset_len).rev() { + let bit_criteria = criteria(&candidates).check_bit(bit); + candidates + .bitsets + .retain(|candidate| candidate.check_bit(bit) == bit_criteria); + if candidates.bitsets.len() == 1 { + return candidates.bitsets[0]; + } + } + Bitset::default() + } +} + +#[derive(Default, Debug, Clone, Copy)] +struct Bitset { + bits: u32, + len: usize, +} + +impl Bitset { + fn check_bit(&self, bit: usize) -> bool { + self.bits & (1 << bit) != 0 + } + + fn set_bit(&mut self, bit: usize) { + self.bits |= 1 << bit; + } +} + +impl std::ops::Mul for Bitset { + type Output = Self; + fn mul(self, rhs: Bitset) -> Self::Output { + Bitset { + bits: self.bits * rhs.bits, + len: self.len.max(rhs.len), // dodgy. This might need to grow. + } + } +} +impl std::ops::Not for Bitset { + type Output = Bitset; + fn not(self) -> ::Output { + Bitset { + bits: !self.bits & ((1 << self.len) - 1), + len: self.len, + } + } +} + +fn parse_diagnostics(input: &str) -> IResult<&str, Diagnostics> { + map(separated_list1(line_ending, parse_bitset), Diagnostics::new)(input) +} + +fn parse_bitset(input: &str) -> IResult<&str, Bitset> { + map_res(digit1, |num| { + u32::from_str_radix(num, 2).map(|bits| Bitset { + bits, + len: num.len(), + }) + })(input) +} -- cgit v1.2.3