Day 3 clean-up

This commit is contained in:
Zoé Cassiopée Gauthier 2021-12-03 17:21:47 -05:00
parent 40121a400a
commit 79da3ab4aa

View File

@ -1,94 +1,115 @@
use std::io::{self, BufRead}; use std::io::{self, BufRead};
fn most_common_bits(report: &Vec<String>) -> String { struct Diagnostics<const N: usize> {
(0..12) report: Vec<String>,
.map(|i| {
let counts = report
.iter()
.fold((0, 0), |acc, x| match x.chars().nth(i).unwrap() {
'0' => (acc.0 + 1, acc.1),
'1' => (acc.0, acc.1 + 1),
_ => acc,
});
if counts.0 > counts.1 {
'0'
} else {
'1'
}
})
.collect()
} }
fn most_common_value(report: Vec<String>, n: usize) -> Option<String> { impl<const N: usize> Diagnostics<N> {
(0..n) fn gamma_rate(&self) -> u32 {
.fold(report, |r, i| { u32::from_str_radix(&self.most_common_bits(), 2).unwrap()
if r.len() > 1 { }
let counts = r
.iter()
.fold((0, 0), |acc, x| match x.chars().nth(i).unwrap() {
'0' => (acc.0 + 1, acc.1),
'1' => (acc.0, acc.1 + 1),
_ => acc,
});
r.iter()
.filter(|x| match x.chars().nth(i).unwrap() {
'0' if counts.0 > counts.1 => true,
'1' if counts.0 <= counts.1 => true,
_ => false,
})
.cloned()
.collect()
} else {
r
}
})
.first()
.cloned()
}
fn least_common_value(report: Vec<String>) -> Option<String> { fn epsilon_rate(&self) -> u32 {
(0..12) 0xfff ^ self.gamma_rate()
.fold(report, |r, i| { }
if r.len() > 1 {
let counts = r fn oxygen_generator_rating(&self) -> u32 {
.iter() u32::from_str_radix(&self.most_common_value(), 2).unwrap()
.fold((0, 0), |acc, x| match x.chars().nth(i).unwrap() { }
'0' => (acc.0 + 1, acc.1),
'1' => (acc.0, acc.1 + 1), fn co2_scrubber_rating(&self) -> u32 {
_ => acc, u32::from_str_radix(&self.least_common_value(), 2).unwrap()
}); }
r.iter()
.filter(|x| match x.chars().nth(i).unwrap() { fn count_bit(&self, values: &Vec<String>, bit: usize) -> (usize, usize) {
'0' if counts.0 <= counts.1 => true, values
'1' if counts.0 > counts.1 => true, .iter()
_ => false, .fold((0, 0), |acc, x| match x.chars().nth(bit).unwrap() {
}) '0' => (acc.0 + 1, acc.1),
.cloned() '1' => (acc.0, acc.1 + 1),
.collect() _ => acc,
} else { })
r }
}
}) fn most_common_bits(&self) -> String {
.first() (0..N)
.cloned() .map(|i| {
let (zeros, ones) = self.count_bit(&self.report, i);
if zeros > ones {
'0'
} else {
'1'
}
})
.collect()
}
fn filter_values(
&self,
values: Vec<String>,
bit: usize,
predicate: impl Fn(usize, usize) -> bool,
) -> Vec<String> {
if values.len() <= 1 {
return values;
}
let (zeros, ones) = self.count_bit(&values, bit);
values
.iter()
.filter(|x| match x.chars().nth(bit).unwrap() {
'0' if !predicate(zeros, ones) => true,
'1' if predicate(zeros, ones) => true,
_ => false,
})
.cloned()
.collect()
}
fn most_common_value(&self) -> String {
(0..N)
.fold(self.report.clone(), |r, i| {
self.filter_values(r, i, |zeros, ones| ones >= zeros)
})
.first()
.unwrap()
.clone()
}
fn least_common_value(&self) -> String {
(0..N)
.fold(self.report.clone(), |r, i| {
self.filter_values(r, i, |zeros, ones| ones < zeros)
})
.first()
.unwrap()
.clone()
}
} }
fn main() { fn main() {
const INPUT: &'static str = include_str!("../inputs/day3.txt"); const INPUT: &'static str = include_str!("../inputs/day3.txt");
let report: Vec<String> = io::Cursor::new(INPUT).lines().map(|l| l.unwrap()).collect(); let report: Vec<String> = io::Cursor::new(INPUT).lines().map(|l| l.unwrap()).collect();
let gamma_rate = u32::from_str_radix(&most_common_bits(&report), 2).unwrap(); let diagnostics = Diagnostics::<12> { report: report };
let epsilon_rate = 0xfff ^ gamma_rate;
println!("gamma rate {} epsilon rate {}", gamma_rate, epsilon_rate);
println!("solution {}", gamma_rate * epsilon_rate);
let oxygen_generator_rating = println!(
u32::from_str_radix(&most_common_value(report.clone(), 12).unwrap(), 2).unwrap(); "gamma rate {} epsilon rate {}",
println!("oxygen generator rating {}", oxygen_generator_rating); diagnostics.gamma_rate(),
diagnostics.epsilon_rate()
);
println!(
"solution {}",
diagnostics.gamma_rate() * diagnostics.epsilon_rate()
);
let co2_scrubber_rating = u32::from_str_radix(&least_common_value(report).unwrap(), 2).unwrap(); println!(
println!("CO2 scrubber rating {}", co2_scrubber_rating); "oxygen generator rating {} CO2 scrubber rating {}",
diagnostics.oxygen_generator_rating(),
println!("solution {}", oxygen_generator_rating * co2_scrubber_rating); diagnostics.co2_scrubber_rating()
);
println!(
"solution {}",
diagnostics.oxygen_generator_rating() * diagnostics.co2_scrubber_rating()
);
} }
#[test] #[test]
@ -107,5 +128,6 @@ fn oxygen_generator_rating() {
"00010".to_string(), "00010".to_string(),
"01010".to_string(), "01010".to_string(),
]; ];
assert_eq!(most_common_value(report, 5).unwrap(), "10111"); let diagnostics = Diagnostics::<5> { report: report };
assert_eq!(diagnostics.most_common_value(), "10111");
} }