use std::fs::File; use std::io::{self, BufRead}; use std::path::Path; fn read_lines

(filename: P) -> io::Result>> where P: AsRef, { let file = File::open(filename)?; Ok(io::BufReader::new(file).lines()) } fn str_to_bit_vec(binary_string: &str) -> Vec { binary_string .chars() .map(|c| { c.to_digit(2) .expect(format!("Unknown binary string: {}", binary_string).as_str()) }) .collect() } struct MeanBits { bits: Vec, count: u32, } fn calc_gamma_epsilon(bit_mask: u32, values: Vec>) -> (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> = 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() }