AoC_2021/src/day03.rs

82 lines
2.4 KiB
Rust

use aoc_runner_derive::{aoc, aoc_generator};
type Data = Vec<u16>;
fn make_histogram(input: &[u16]) -> Vec<(usize, i64)> {
let counts: &mut [Option<i64>] = &mut [None; 64];
input.iter().for_each(|val| {
for (n, count) in counts.iter_mut().enumerate().take(12) {
let v = count.get_or_insert(0);
if ((val >> n) & 1) == 1 {
*v += 1;
} else {
*v -= 1;
}
}
});
counts.reverse();
counts
.iter()
.enumerate()
.filter_map(|(a, b)| b.map(|b| (a, b)))
.collect::<Vec<_>>()
}
#[aoc_generator(day03)]
pub fn input_generator(input: &str) -> Vec<u16> {
input
.lines()
.map(|l| u16::from_str_radix(l, 2).unwrap())
.collect()
}
#[derive(Debug)]
enum Mode {
MostCommon,
LeastCommon,
}
fn tree_filter(data: &[u16], mut pos: usize, mode: Mode) -> u16 {
let (zero, one) = data
.iter()
.partition::<Vec<u16>, _>(|&v| ((v >> pos) & 1) == 0);
if data.is_empty() {
panic!("Uh Oh!");
}
if data.len() == 1 {
return data[0];
}
pos=pos.wrapping_sub(1);
if zero.len() == one.len() {
match mode {
Mode::MostCommon => tree_filter(&one, pos, mode),
Mode::LeastCommon => tree_filter(&zero, pos, mode),
}
} else {
let mut srt = vec![zero, one];
srt.sort_by_key(|v| v.len());
match mode {
Mode::MostCommon => tree_filter(&srt[1], pos, mode),
Mode::LeastCommon => tree_filter(&srt[0], pos, mode),
}
}
}
const ASCII_ZERO: u8 = 0x30;
#[aoc(day03, part1)] // 1997414
pub fn solve_part1(input: &Data) -> usize {
let counts = make_histogram(input);
let (gamma, epsilon): (String, String) = counts
.iter()
.map(|(_, v)| {
(
(ASCII_ZERO + (*v >= 0) as u8) as char,
(ASCII_ZERO + (*v < 0) as u8) as char,
)
})
.unzip();
let gamma = usize::from_str_radix(&gamma, 2).unwrap();
let epsilon = usize::from_str_radix(&epsilon, 2).unwrap();
gamma * epsilon
}
#[aoc(day03, part2)] // 1032597
pub fn solve_part2(input: &[u16]) -> usize {
// let input: Vec<bool> = input.iter().for_each(|v| v[0]).collect();
let a = tree_filter(input, 11, Mode::MostCommon) as usize;
let b = tree_filter(input, 11, Mode::LeastCommon) as usize;
a * b
}