part 2 should not have taken this long
This commit is contained in:
parent
b1a8ab8bcd
commit
340ef2d4d3
@ -1,41 +1,71 @@
|
||||
use color_eyre::eyre;
|
||||
|
||||
|
||||
fn most_common_bits(numbers: &Vec<u16>) -> u16 {
|
||||
let mut bit_diffs: [isize; 12] = [0; 12];
|
||||
for num in numbers {
|
||||
for i in 0..11 {
|
||||
if num & (1 << i) > 0 {
|
||||
bit_diffs[i] += 1
|
||||
}
|
||||
else {
|
||||
bit_diffs[i] -= 1
|
||||
}
|
||||
}
|
||||
}
|
||||
fn most_common_bit(numbers: &Vec<u16>, pos: u8) -> u16 {
|
||||
// number of times the bit in question is 1,
|
||||
// minus the number of times it's 0
|
||||
let mask: u16 = 1 << pos;
|
||||
let total: isize = numbers
|
||||
.iter()
|
||||
.map(|n| if n & mask > 0 {1} else {-1})
|
||||
.sum();
|
||||
|
||||
let mut result = 0u16;
|
||||
for (i, sum) in bit_diffs.iter().enumerate() {
|
||||
let bit = if *sum >= 0 {1} else {0};
|
||||
result |= bit << i;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
|
||||
fn invert_12bit(n: u16) -> u16 {
|
||||
!n & (65535 >> 4) // since these are really only 12-bit numbers we have to clear the 4 spurious 1's that come from inverting the original
|
||||
// if the total is positive, then 1 is more frequent than 0
|
||||
if total >= 0 {1} else {0}
|
||||
}
|
||||
|
||||
|
||||
fn part1(numbers: &Vec<u16>) -> u64 {
|
||||
let gamma = most_common_bits(numbers);
|
||||
let epsilon = invert_12bit(gamma);
|
||||
let mut gamma = 0u16;
|
||||
for i in 0..12 {
|
||||
let mask = most_common_bit(numbers, i) << i;
|
||||
gamma |= mask;
|
||||
}
|
||||
|
||||
// alternate solution: it feels super cool, but it's not any fewer lines than the above, and way less clear :(
|
||||
// let gamma = (0..12)
|
||||
// .fold(
|
||||
// 0u16,
|
||||
// |g, i| g | (most_common_bit(numbers, i) << i)
|
||||
// );
|
||||
|
||||
// epsilon is just the bit inverse of gamma, but since these are really 12-bit numbers
|
||||
// we have to clear the 4 spurious 1's that come from inverting the original
|
||||
let epsilon = !gamma & (65535 >> 4);
|
||||
epsilon as u64 * gamma as u64
|
||||
}
|
||||
|
||||
|
||||
fn filter_bit_criteria(numbers: Vec<u16>, bit_pos: u8, bit_value: u16) -> Vec<u16> {
|
||||
numbers
|
||||
.into_iter()
|
||||
.filter(|n| (n >> bit_pos) & 1 == bit_value)
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
||||
fn part2(numbers: &Vec<u16>) -> u64 {
|
||||
let mut oxy = numbers.clone();
|
||||
let mut co2 = numbers.clone();
|
||||
for pos in (0..12).rev() {
|
||||
if oxy.len() > 1 {
|
||||
let oxy_bit = most_common_bit(&oxy, pos);
|
||||
oxy = filter_bit_criteria(oxy, pos, oxy_bit);
|
||||
}
|
||||
|
||||
if co2.len() > 1 {
|
||||
let co2_bit = most_common_bit(&co2, pos) ^ 1; // flip the rightmost bit, giving us the least common instead
|
||||
co2 = filter_bit_criteria(co2, pos, co2_bit);
|
||||
}
|
||||
}
|
||||
|
||||
// assume both vecs have len == 1 now, since otherwise it means
|
||||
// AoC gave us an invalid problem input
|
||||
oxy[0] as u64 * co2[0] as u64
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub fn run(data: &str) -> eyre::Result<()> {
|
||||
let mut nums = Vec::new();
|
||||
for line in data.lines() {
|
||||
@ -43,5 +73,6 @@ pub fn run(data: &str) -> eyre::Result<()> {
|
||||
}
|
||||
|
||||
println!("One: {}", part1(&nums));
|
||||
println!("Two: {}", part2(&nums));
|
||||
Ok(())
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user