2021 Day 3 done in Rust

I'm not especially proud of the code : it's messy, took a long time
and could probably be vastly improved.
I could have used the intersperse iterator method but it's currently in
nightly only. Maybe another way of parsing the string would have prevented
the need ?
This commit is contained in:
Teo-CD 2021-12-04 20:47:11 +00:00
parent 57bf7b2194
commit 8d63db3d64
4 changed files with 1100 additions and 0 deletions

1000
2021/Day 3/input.txt Normal file

File diff suppressed because it is too large Load diff

5
2021/Day 3/rust_solution/Cargo.lock generated Normal file
View file

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

View file

@ -0,0 +1,9 @@
[package]
name = "rust_solution"
version = "0.1.0"
authors = ["Teo-CD <teo.couprie_diaz@telecom-sudparis.eu>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,86 @@
use std::fs;
/// Count number of ones in each bit position. If the count is less than half of the total number
/// of entries, then 0 is more common.
fn find_most_common_bits(input: &String) -> Vec<i16> {
let width = input.lines().nth(0).unwrap().len();
let mut bit_counts: Vec<i16> = std::vec::from_elem(0, width);
for value in input.lines() {
let mut chars = value.chars();
for index in 0..width {
bit_counts[index] += if chars.next().unwrap() == '1' { 1 } else { 0 };
}
}
bit_counts
}
/// Loop while finding the most/least common bit for the current position until we find
/// a single number in the list.
fn reduce_by_count(input: &String, most_common: bool) -> String {
let mut count = input.lines().count();
let mut bit_index = 0;
let mut filtered_input = input.clone();
while count > 1 {
let most_common_bit = if find_most_common_bits(&filtered_input)[bit_index]
>= filtered_input.lines().count() as i16 / 2
{
if most_common {
'1'
} else {
'0'
}
} else {
if most_common {
'0'
} else {
'1'
}
};
// Filter out the numbers which don't match the current most/least common bit.
filtered_input = filtered_input
.lines()
.filter(|line: &&str| line.chars().nth(bit_index).unwrap() == most_common_bit)
.map(|line| line.to_owned() + '\n'.to_string().as_str()) // Add the line separator back
.collect();
count = filtered_input.lines().count();
bit_index += 1;
}
String::from(filtered_input.lines().next().unwrap())
}
fn main() {
let contents = fs::read_to_string("../input.txt").expect("Could not open file.");
let bit_counts = find_most_common_bits(&contents);
// Compute power consumption
let mut gamma: u32 = 0;
let mut epsilon: u32 = 0;
for count in bit_counts {
gamma <<= 1;
epsilon <<= 1;
gamma |= if count > contents.lines().count() as i16 / 2 {
1
} else {
0
};
epsilon |= if count > contents.lines().count() as i16 / 2 {
0
} else {
1
}
}
println!(
"Submarine power consumption : {}",
gamma as u64 * epsilon as u64
);
// Compute oxygen generator rating and CO2 scrubber rating.
// from_str_radix converts from a string of the binary representation to an integer.
let ox_gen = isize::from_str_radix(reduce_by_count(&contents, true).as_str(), 2).unwrap();
let co2_scrub = isize::from_str_radix(reduce_by_count(&contents, false).as_str(), 2).unwrap();
println!("Oxygen generator rating : {}", ox_gen);
println!("CO2 scrubber rating : {}", co2_scrub);
println!("Life support rating : {}", ox_gen * co2_scrub);
}