#[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);
}