Dag: 3
SprÄk: Rust
use crate::solution::Solution;
type ReportEntry = u32;
struct Day3 {
report: Vec<ReportEntry>,
zeros: Vec<u32>,
bit_width: usize,
}
impl Solution for Day3 {
fn part1(&self) -> String {
power_consumption(&self.zeros, self.report.len(), self.bit_width)
.to_string()
}
fn part2(&self) -> String {
life_support_rating(&self.report, self.bit_width)
.to_string()
}
}
fn power_consumption(zeros: &[u32], num_reports: usize, bit_width: usize) -> ReportEntry {
let thresh = (num_reports / 2) as ReportEntry;
let gamma = zeros
.iter()
.map(|&num_zeros| (num_zeros <= thresh) as ReportEntry)
.fold(0, |gamma, bit_value| (gamma << 1) + bit_value);
let epsilon = !gamma & ((1 << bit_width) - 1);
gamma * epsilon
}
fn life_support_rating(report: &[ReportEntry], bit_width: usize) -> ReportEntry {
oxygen_generator_rating(report, bit_width) * co_scrubber_rating(report, bit_width)
}
fn oxygen_generator_rating(report: &[ReportEntry], bit_width: usize) -> ReportEntry {
rating(report, bit_width, |num_ones, report_len| 2 * num_ones >= report_len)
}
fn co_scrubber_rating(report: &[ReportEntry], bit_width: usize) -> ReportEntry {
rating(report, bit_width, |num_ones, report_len| 2 * num_ones < report_len)
}
fn rating(report: &[ReportEntry], bit_width: usize, cmp_fn: fn(usize, usize) -> bool) -> ReportEntry {
let should_be_set_fn = |numbers: &[u32], bit: usize| {
let num_ones = numbers
.iter()
.fold(0, |num_set, &number| num_set + is_bit_set(number, bit) as usize);
cmp_fn(num_ones, numbers.len())
};
let mut numbers = report.to_vec();
for bit in (0..bit_width).rev() {
let should_be_set = should_be_set_fn(&numbers, bit);
numbers = numbers
.into_iter()
.filter(|&number| !(is_bit_set(number, bit) ^ should_be_set))
.collect();
if numbers.len() == 1 {
break
}
}
numbers[0]
}
fn is_bit_set(number: u32, bit: usize) -> bool {
((number >> bit) & 1) != 0
}
pub fn new(input: &str) -> Box<dyn Solution> {
let (report, zeros, bit_width) = input_parser(input);
Box::new(Day3{
report,
zeros,
bit_width,
})
}
fn input_parser(input: &str) -> (Vec<ReportEntry>, Vec<u32>, usize) {
let bit_width = input.find('\n').expect("Invalid input");
let numbers = input
.lines()
.map(|num_str| ReportEntry::from_str_radix(num_str, 2).expect("Not a binary number"));
let mut report = Vec::new();
let mut zeros = vec![0; bit_width];
for number in numbers {
report.push(number);
for i in 0..bit_width {
// First bit in input is used as LSB in gamma/epsilon
zeros[bit_width - i - 1] += is_bit_set(number, i) as u32;
}
}
(report, zeros, bit_width)
}
Ingen strÀnghantering, hÀr Àr det bit-twiddel
Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer