2021: day 4 solution

[?]
Dec 7, 2021, 8:55 PM
ZW7LNZTW4AZWJBHXZ5IU25PXTVFBAE5NPP7OD3JJNS54WCWYQ34QC

Dependencies

Change contents

  • file addition: day3.rs (----------)
    [2.16]
    #[derive(Clone, Copy, Debug)]
    struct BitCount {
    ones: u64,
    zeros: u64,
    }
    impl BitCount {
    fn new() -> Self {
    Self { ones: 0, zeros: 0 }
    }
    fn count_char(&mut self, c: char) {
    match c {
    '1' => self.count_one(),
    '0' => self.count_zero(),
    _ => (),
    }
    }
    fn count_bit(&mut self, b: bool) {
    if b {
    self.count_one()
    } else {
    self.count_zero()
    }
    }
    fn count_one(&mut self) {
    self.ones += 1;
    }
    fn count_zero(&mut self) {
    self.zeros += 1;
    }
    fn gamma(&self) -> bool {
    self.ones >= self.zeros
    }
    fn epsilon(&self) -> bool {
    self.zeros > self.ones
    }
    }
    impl Default for BitCount {
    fn default() -> Self {
    Self::new()
    }
    }
    struct StretchZip<'a, Item, Rhs> {
    lhs: &'a mut Vec<Item>,
    ix: usize,
    rhs: Rhs,
    }
    impl<'a, Item: Default, Rhs: Iterator> StretchZip<'a,Item,Rhs> {
    fn new(lhs: &'a mut Vec<Item>, rhs: Rhs) -> Self {
    Self { lhs, ix: 0, rhs }
    }
    }
    impl<'a, Item: Default, Rhs: Iterator> Iterator for StretchZip<'a,Item,Rhs> {
    type Item = (&'a mut Item, <Rhs as Iterator>::Item);
    fn next(&mut self) -> Option<(&'a mut Item, <Rhs as Iterator>::Item)> {
    let r = self.rhs.next()?;
    if self.ix >= self.lhs.len() {
    self.lhs.push(<Item as Default>::default());
    }
    let l = unsafe {
    std::mem::transmute::<&mut Item, &'a mut Item>(self.lhs.get_mut(self.ix)?)
    };
    self.ix += 1;
    Some((l,r))
    }
    }
    trait CounterList<C> {
    fn count<I: Iterator<Item=C>>(&mut self, item: I);
    }
    impl CounterList<char> for Vec<BitCount> {
    fn count<I: Iterator<Item=char>>(&mut self, item: I) {
    for (counter, bit) in StretchZip::new(self, item) {
    counter.count_char(bit);
    }
    }
    }
    fn life_support(field: bool, readings: &Vec<Vec<bool>>) -> u64 {
    let mut remaining_1 = Vec::new();
    let mut remaining_2 = Vec::new();
    for ix in 0 .. readings[0].len() {
    let (source, sink) = if ix == 0 {
    (readings, &mut remaining_1)
    } else if ix % 2 == 0 {
    (&remaining_2, &mut remaining_1)
    } else {
    (&remaining_1, &mut remaining_2)
    };
    let mut counter = BitCount::new();
    for reading in source.iter() {
    counter.count_bit(reading[ix]);
    }
    let target = if field {
    counter.gamma()
    } else {
    counter.epsilon()
    };
    sink.clear();
    sink.extend(source.iter().filter(|reading| reading[ix] == target).cloned());
    match sink.len() {
    0 => { sink.extend(source.iter().cloned()); }
    1 => { return from_bits(sink[0].iter().copied()); }
    _ => {}
    }
    }
    from_bits(if remaining_1.len() <= remaining_2.len() {
    &remaining_1[0]
    } else {
    &remaining_2[0]
    }.iter().copied())
    }
    fn from_bits<I: Iterator<Item=bool>>(source: I) -> u64 {
    let mut result = 0;
    for b in source {
    result = result * 2 + (if b { 1 } else { 0 });
    }
    result
    }
    fn main() {
    use std::io::BufRead;
    let filename = std::env::args().nth(1).expect("Expected filename");
    let file = std::io::BufReader::new(
    std::fs::File::open(<String as AsRef<std::path::Path>>::as_ref(&filename)).unwrap()
    );
    let mut counters = Vec::new();
    let mut record = Vec::new();
    for line in file.lines().filter_map(Result::ok) {
    counters.count(line.chars());
    record.push(line.chars().filter_map(|c| match c {
    '0' => Some(false),
    '1' => Some(true),
    _ => None
    }).collect::<Vec<_>>())
    };
    let gamma = from_bits(counters.iter().map(BitCount::gamma));
    println!("Gamma: {}", gamma);
    let epsilon = from_bits(counters.iter().map(BitCount::epsilon));
    println!("Epsilon: {}", epsilon);
    println!("Product: {}", gamma * epsilon);
    let oxygen = life_support(true, &record);
    println!("Oxygen: {}", oxygen);
    let scrubber = life_support(false, &record);
    println!("CO2 Scrubber: {}", scrubber);
    println!("Product: {}", oxygen * scrubber);
    }