use super::PuzzleSolver;
#[derive(Debug)]
pub struct Solver {
pub input: Vec<String>,
}
impl Solver {
pub fn new(input: &str) -> Solver {
let input = input
.trim()
.split('\n')
.into_iter()
.map(|x| x.to_string())
.collect();
Solver { input }
}
}
impl PuzzleSolver for Solver {
fn part_one(&self) -> String {
println!("Multiplying gamma rate by epsilon rate");
let bit_counts = count_bits(&self.input);
let gamma_rate = generate_gamma_rate(&bit_counts, self.input.len());
let epsilon_rate = generate_epsilon_rate(&bit_counts, self.input.len());
(gamma_rate * epsilon_rate).to_string()
}
fn part_two(&self) -> String {
println!("Multiplying O2 rate by CO2 rate");
let o2_rating = find_oxygen_rating(&self.input);
let co2_rating = find_co2_rating(&self.input);
(o2_rating * co2_rating).to_string()
}
}
pub fn count_bits(binary_data: &[String]) -> Vec<usize> {
let mut counters = vec![0; binary_data[0].len()];
for entry in binary_data.iter() {
for (idx, bit) in entry.chars().enumerate() {
if bit == '1' {
counters[idx] += 1;
}
}
}
counters
}
pub fn count_bit_position(binary_data: &[String], pos: usize) -> (usize, usize) {
let mut ones = 0;
let mut zeros = 0;
for entry in binary_data.iter() {
if entry.chars().nth(pos).expect("Unable to index string") == '1' {
ones += 1;
} else {
zeros += 1
}
}
(ones, zeros)
}
pub fn find_oxygen_rating(binary_data: &[String]) -> usize {
let mut remaining_numbers = binary_data.to_owned();
for i in 0..binary_data[0].len() {
if remaining_numbers.len() == 1 {
break;
}
let (ones, zeros) = count_bit_position(&remaining_numbers, i);
if ones >= zeros {
remaining_numbers = remaining_numbers
.into_iter()
.filter(|x| x.chars().nth(i).unwrap() == '1')
.collect();
} else {
remaining_numbers = remaining_numbers
.into_iter()
.filter(|x| x.chars().nth(i).unwrap() == '0')
.collect();
}
}
usize::from_str_radix(&remaining_numbers[0], 2).unwrap()
}
pub fn find_co2_rating(binary_data: &[String]) -> usize {
let mut remaining_numbers = binary_data.to_owned();
for i in 0..binary_data[0].len() {
if remaining_numbers.len() == 1 {
break;
}
let (ones, zeros) = count_bit_position(&remaining_numbers, i);
if ones < zeros {
remaining_numbers = remaining_numbers
.into_iter()
.filter(|x| x.chars().nth(i).unwrap() == '1')
.collect();
} else {
remaining_numbers = remaining_numbers
.into_iter()
.filter(|x| x.chars().nth(i).unwrap() == '0')
.collect();
}
}
usize::from_str_radix(&remaining_numbers[0], 2).unwrap()
}
pub fn generate_gamma_rate(bit_counts: &[usize], data_length: usize) -> u32 {
let cutoff = data_length / 2;
let mut result = String::from("");
for count in bit_counts.iter() {
if count > &cutoff {
result.push('1');
} else {
result.push('0');
}
}
u32::from_str_radix(&result, 2).unwrap()
}
pub fn generate_epsilon_rate(bit_counts: &[usize], data_length: usize) -> u32 {
let cutoff = data_length / 2;
let mut result = String::from("");
for count in bit_counts.iter() {
if count > &cutoff {
result.push('0');
} else {
result.push('1');
}
}
u32::from_str_radix(&result, 2).unwrap()
}