Completed day 3
This commit is contained in:
parent
e64edbd201
commit
8359a6b308
135
src/day3.rs
Normal file
135
src/day3.rs
Normal file
@ -0,0 +1,135 @@
|
||||
/// I thought this would be useful for both parts but I was very wrong
|
||||
fn bit_count(input: &String) -> (Vec<i64>, usize) {
|
||||
let byte_len = input.lines().next().unwrap().len();
|
||||
let mut count = vec![0i64; byte_len];
|
||||
|
||||
for line in input.lines() {
|
||||
let mut i = 0;
|
||||
for c in line.chars() {
|
||||
if c == '1' {
|
||||
count[i] += 1;
|
||||
} else if c == '0' {
|
||||
count[i] -= 1;
|
||||
} else {
|
||||
panic! {"Malformed input!"};
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
(count, byte_len)
|
||||
}
|
||||
|
||||
/// Returns the product of gamma and epsilon.
|
||||
///
|
||||
/// Gamma is determined by the most common bit values at each position in all of the
|
||||
/// input.
|
||||
///
|
||||
/// Epsilon is the inverse, determined by the least common bit values.
|
||||
pub fn part1(input: String) {
|
||||
let (count, byte_len) = bit_count(&input);
|
||||
|
||||
let mut gamma = 0u64;
|
||||
let mut epsilon = 0u64;
|
||||
for i in 0..byte_len {
|
||||
// ERROR: wrong with even counts
|
||||
gamma |= ((count[i] > 0) as u64) << (byte_len - (i + 1));
|
||||
epsilon |= ((count[i] <= 0) as u64) << (byte_len - (i + 1));
|
||||
}
|
||||
|
||||
println!("{}", gamma * epsilon);
|
||||
}
|
||||
|
||||
/// Counts high/low bits in
|
||||
fn count_bits(data: &Vec<u64>, bit_index: usize, mask: u64, bit_diag: u64) -> (u64, i64) {
|
||||
let mut bit_prevalance = 0i64;
|
||||
let mut valid_count = 0u64;
|
||||
|
||||
for byte in data {
|
||||
//println!("byte: {}", bit_diag ^ (byte & mask));
|
||||
if bit_diag ^ (byte & mask) == 0 {
|
||||
valid_count += 1;
|
||||
if (byte & (1 << bit_index)) > 0 {
|
||||
bit_prevalance += 1;
|
||||
} else {
|
||||
bit_prevalance -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//println!("bit_index: {}, mask: {}, bit_diag: {}, valid_count: {}, bit_prevalance: {}", bit_index, mask, bit_diag, valid_count, bit_prevalance);
|
||||
(valid_count, bit_prevalance)
|
||||
}
|
||||
|
||||
/// I *could* document this, but why would I want to? :P
|
||||
/// AOC itself serves as documentation.
|
||||
pub fn part2(input: String) {
|
||||
let byte_len = input.lines().next().unwrap().len();
|
||||
let data: Vec<u64> = input
|
||||
.lines()
|
||||
.map(|l| u64::from_str_radix(l, 2).unwrap())
|
||||
.collect();
|
||||
|
||||
let mut generator_mask = 0u64;
|
||||
let mut generator_diag = 0u64;
|
||||
let mut generator_value = None;
|
||||
let mut scrubber_mask = 0u64;
|
||||
let mut scrubber_diag = 0u64;
|
||||
let mut scrubber_value = None;
|
||||
|
||||
// Diagnostic bit sequence will be different for generator and scrubber
|
||||
// Logic for counting bits will be the same, just need to keep diagnostic bits seperate
|
||||
for i in 0..byte_len {
|
||||
let bit_index = byte_len - i - 1;
|
||||
|
||||
// Set diagnostic bit for each piece of data individually
|
||||
if generator_value.is_none() {
|
||||
let (valid_count, bit_prevalance) =
|
||||
count_bits(&data, bit_index, generator_mask, generator_diag);
|
||||
|
||||
// We want to match against the most common bit, which is 1 when prevalance is positive.
|
||||
// We also want to match on one when they are equal.
|
||||
if bit_prevalance >= 0 {
|
||||
generator_diag |= 1 << bit_index;
|
||||
}
|
||||
generator_mask |= 1 << bit_index;
|
||||
|
||||
// Only one valid solution, grab it and get out
|
||||
if valid_count <= 2 || i == byte_len - 1 {
|
||||
generator_value = Some(
|
||||
data.iter()
|
||||
.filter(|d| generator_diag ^ (*d & generator_mask) == 0)
|
||||
.next()
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if scrubber_value.is_none() {
|
||||
let (valid_count, bit_prevalance) =
|
||||
count_bits(&data, bit_index, scrubber_mask, scrubber_diag);
|
||||
|
||||
// We want to match against the least common bit, which is 1 when prevalance is negative.
|
||||
// When equal we match against 0.
|
||||
if bit_prevalance < 0 {
|
||||
scrubber_diag |= 1 << bit_index;
|
||||
}
|
||||
scrubber_mask |= 1 << bit_index;
|
||||
|
||||
// Only one valid solution, grab it and get out
|
||||
if valid_count <= 2 || i == byte_len - 1 {
|
||||
scrubber_value = Some(
|
||||
data.iter()
|
||||
.filter(|d| scrubber_diag ^ (*d & scrubber_mask) == 0)
|
||||
.next()
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let gen = generator_value.unwrap();
|
||||
let scrub = scrubber_value.unwrap();
|
||||
|
||||
println!("{}", gen * scrub);
|
||||
}
|
@ -2,6 +2,7 @@ use clap::{App, Arg};
|
||||
|
||||
mod day1;
|
||||
mod day2;
|
||||
mod day3;
|
||||
|
||||
fn main() {
|
||||
let matches = App::new("AOC 2021 Code")
|
||||
@ -44,6 +45,11 @@ fn main() {
|
||||
2 => day2::part2(input),
|
||||
_ => (),
|
||||
},
|
||||
3 => match part {
|
||||
1 => day3::part1(input),
|
||||
2 => day3::part2(input),
|
||||
_ => (),
|
||||
},
|
||||
_ => println!("Day {} not completed yet!", day),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user