Add (ugly) working day 3 in rust

This commit is contained in:
IamTheFij 2021-12-04 14:03:38 -08:00
parent b487214421
commit d664a9efa8
5 changed files with 1234 additions and 0 deletions

7
d03/Cargo.lock generated Normal file
View File

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "d03"
version = "0.1.0"

8
d03/Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "d03"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

1000
d03/input.txt Normal file

File diff suppressed because it is too large Load Diff

12
d03/input_short.txt Normal file
View File

@ -0,0 +1,12 @@
00100
11110
10110
10111
10101
01111
00111
11100
10000
11001
00010
01010

207
d03/src/main.rs Normal file
View File

@ -0,0 +1,207 @@
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()
}