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;
|
use color_eyre::eyre;
|
||||||
|
|
||||||
|
|
||||||
fn most_common_bits(numbers: &Vec<u16>) -> u16 {
|
fn most_common_bit(numbers: &Vec<u16>, pos: u8) -> u16 {
|
||||||
let mut bit_diffs: [isize; 12] = [0; 12];
|
// number of times the bit in question is 1,
|
||||||
for num in numbers {
|
// minus the number of times it's 0
|
||||||
for i in 0..11 {
|
let mask: u16 = 1 << pos;
|
||||||
if num & (1 << i) > 0 {
|
let total: isize = numbers
|
||||||
bit_diffs[i] += 1
|
.iter()
|
||||||
}
|
.map(|n| if n & mask > 0 {1} else {-1})
|
||||||
else {
|
.sum();
|
||||||
bit_diffs[i] -= 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut result = 0u16;
|
// if the total is positive, then 1 is more frequent than 0
|
||||||
for (i, sum) in bit_diffs.iter().enumerate() {
|
if total >= 0 {1} else {0}
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn part1(numbers: &Vec<u16>) -> u64 {
|
fn part1(numbers: &Vec<u16>) -> u64 {
|
||||||
let gamma = most_common_bits(numbers);
|
let mut gamma = 0u16;
|
||||||
let epsilon = invert_12bit(gamma);
|
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
|
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<()> {
|
pub fn run(data: &str) -> eyre::Result<()> {
|
||||||
let mut nums = Vec::new();
|
let mut nums = Vec::new();
|
||||||
for line in data.lines() {
|
for line in data.lines() {
|
||||||
@ -43,5 +73,6 @@ pub fn run(data: &str) -> eyre::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
println!("One: {}", part1(&nums));
|
println!("One: {}", part1(&nums));
|
||||||
|
println!("Two: {}", part2(&nums));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user