208 lines
6.1 KiB
Rust
208 lines
6.1 KiB
Rust
use std::fs::File;
|
|
use std::io::{self, BufRead};
|
|
use std::path::Path;
|
|
|
|
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
|
|
where
|
|
P: AsRef<Path>,
|
|
{
|
|
let file = File::open(filename)?;
|
|
Ok(io::BufReader::new(file).lines())
|
|
}
|
|
|
|
fn str_to_bit_vec(binary_string: &str) -> Vec<u32> {
|
|
binary_string
|
|
.chars()
|
|
.map(|c| {
|
|
c.to_digit(2)
|
|
.expect(format!("Unknown binary string: {}", binary_string).as_str())
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
struct MeanBits {
|
|
bits: Vec<u32>,
|
|
count: u32,
|
|
}
|
|
|
|
fn calc_gamma_epsilon(bit_mask: u32, values: Vec<Vec<u32>>) -> (u32, u32) {
|
|
let result = values
|
|
.iter()
|
|
.map(|bits| MeanBits {
|
|
bits: bits.clone(),
|
|
count: 1,
|
|
})
|
|
// Reduce by summing each bit and keeping count
|
|
.reduce(|acc, these_bits| MeanBits {
|
|
bits: acc
|
|
.bits
|
|
.iter()
|
|
.zip(these_bits.bits.iter())
|
|
.map(|val| val.0 + val.1)
|
|
.collect(),
|
|
count: acc.count + these_bits.count,
|
|
})
|
|
.expect(format!("No results!").as_str());
|
|
|
|
// Calc the gamma value from the MeanBits result
|
|
let gamma = result
|
|
.bits
|
|
.iter()
|
|
.map(|b| (b * 10) / result.count)
|
|
.map(|b| {
|
|
println!("digit {}, count {}", b, result.count);
|
|
b
|
|
})
|
|
.map(|b| match b {
|
|
b if b < 5 => "0".to_string(),
|
|
b if b >= 5 => "1".to_string(),
|
|
_ => panic!("not possible?"),
|
|
})
|
|
.reduce(|result, b| (&[result, b]).join(""))
|
|
.map(|gamma| {
|
|
println!("gamma {}", gamma);
|
|
gamma
|
|
})
|
|
.map(|gamma| u32::from_str_radix(gamma.as_str(), 2))
|
|
.expect("Could not parse gama value")
|
|
.unwrap();
|
|
|
|
// NOT the gamma and apply mask
|
|
let epsilon = !gamma & bit_mask;
|
|
|
|
(gamma, epsilon)
|
|
}
|
|
|
|
fn part1() -> (u32, u32) {
|
|
// Mask should be the length of a line
|
|
let bit_mask = u32::from_str_radix("111111111111", 2).unwrap();
|
|
let result = read_lines("input.txt")
|
|
.expect("Expected a file to read")
|
|
.map(|line| line.expect("Could not read line"))
|
|
.map(|line| str_to_bit_vec(&line))
|
|
// Prep for mean calc
|
|
.map(|bits| MeanBits {
|
|
bits: bits,
|
|
count: 1,
|
|
})
|
|
// Reduce by summing each bit and keeping count
|
|
.reduce(|acc, these_bits| MeanBits {
|
|
bits: acc
|
|
.bits
|
|
.iter()
|
|
.zip(these_bits.bits.iter())
|
|
.map(|val| val.0 + val.1)
|
|
.collect(),
|
|
count: acc.count + these_bits.count,
|
|
})
|
|
.expect(format!("No results!").as_str());
|
|
|
|
// Calc the gamma value from the MeanBits result
|
|
let gamma = result
|
|
.bits
|
|
.iter()
|
|
.map(|b| (b * 10) / result.count)
|
|
.map(|b| {
|
|
println!("digit {}, count {}", b, result.count);
|
|
b
|
|
})
|
|
.map(|b| match b {
|
|
b if b < 5 => "0".to_string(),
|
|
b if b >= 5 => "1".to_string(),
|
|
_ => panic!("not possible?"),
|
|
})
|
|
.reduce(|result, b| (&[result, b]).join(""))
|
|
.map(|gamma| {
|
|
println!("gamma {}", gamma);
|
|
gamma
|
|
})
|
|
.map(|gamma| u32::from_str_radix(gamma.as_str(), 2))
|
|
.expect("Could not parse gama value")
|
|
.unwrap();
|
|
|
|
// NOT the gamma and apply mask
|
|
let epsilon = !gamma & bit_mask;
|
|
|
|
println!(
|
|
"Result for part 1: gamma: {} epsilon: {} result: {}",
|
|
gamma,
|
|
epsilon,
|
|
gamma * epsilon
|
|
);
|
|
|
|
(gamma, epsilon)
|
|
}
|
|
|
|
fn part2() {
|
|
// Oh wow... Getting uggly as my rust is not so great.
|
|
// This can almost certainly be done with less iterations, but I'm getting lazy now
|
|
let mask_length: u32 = 12;
|
|
let bit_mask =
|
|
u32::from_str_radix("1".repeat(mask_length.try_into().unwrap()).as_str(), 2).unwrap();
|
|
let bit_vects: Vec<Vec<u32>> = read_lines("input.txt")
|
|
.expect("Expected a file to read")
|
|
.map(|line| line.expect("Could not read line"))
|
|
.map(|line| str_to_bit_vec(&line))
|
|
.collect();
|
|
|
|
let mut index: u32 = 0;
|
|
let mut oxy_vects = bit_vects.clone();
|
|
while oxy_vects.len() > 1 {
|
|
println!("Length of vectors is {}", oxy_vects.len());
|
|
let (gamma, _epsilon) = calc_gamma_epsilon(bit_mask, oxy_vects.clone());
|
|
let mask_bit: u32 = mask_length - index - 1;
|
|
let gamma_bit = gamma >> mask_bit & 1;
|
|
println!(
|
|
"Gamma is {:#b} and bit at index {} is {}",
|
|
gamma, mask_bit, gamma_bit
|
|
);
|
|
// let epsilon_bit = epsilon >> index & mask_bit;
|
|
let iu: usize = index.try_into().unwrap();
|
|
oxy_vects.retain(|bits| bits[iu] == gamma_bit);
|
|
index += 1;
|
|
}
|
|
let oxygen_rating = oxy_vects[0]
|
|
.iter()
|
|
.map(|b| b.to_string())
|
|
.reduce(|result, b| (&[result, b]).join(""))
|
|
.map(|oxy| u32::from_str_radix(oxy.as_str(), 2))
|
|
.expect("No oxygen rating")
|
|
.unwrap();
|
|
|
|
index = 0;
|
|
let mut co2_vects = bit_vects.clone();
|
|
while co2_vects.len() > 1 {
|
|
println!("Length of vectors is {}", co2_vects.len());
|
|
let (_gamma, epsilon) = calc_gamma_epsilon(bit_mask, co2_vects.clone());
|
|
let mask_bit: u32 = mask_length - index - 1;
|
|
let epsilon_bit = epsilon >> mask_bit & 1;
|
|
println!(
|
|
"Gamma is {:#b} and bit at index {} is {}",
|
|
epsilon, mask_bit, epsilon_bit
|
|
);
|
|
// let epsilon_bit = epsilon >> index & mask_bit;
|
|
let iu: usize = index.try_into().unwrap();
|
|
co2_vects.retain(|bits| bits[iu] == epsilon_bit);
|
|
index += 1;
|
|
}
|
|
let co2_rating = co2_vects[0]
|
|
.iter()
|
|
.map(|b| b.to_string())
|
|
.reduce(|result, b| (&[result, b]).join(""))
|
|
.map(|oxy| u32::from_str_radix(oxy.as_str(), 2))
|
|
.expect("No oxygen rating")
|
|
.unwrap();
|
|
|
|
println!(
|
|
"Part 2! O2 = {}, CO2 = {}, Result is {}",
|
|
oxygen_rating,
|
|
co2_rating,
|
|
oxygen_rating * co2_rating
|
|
)
|
|
}
|
|
|
|
fn main() {
|
|
part1();
|
|
part2()
|
|
}
|