205 lines
5.4 KiB
Rust
205 lines
5.4 KiB
Rust
use std::io::{self, BufRead};
|
|
use std::path::Path;
|
|
use std::fs::File;
|
|
|
|
fn main(){
|
|
// Submarine is breaking, do diagnostics by checking power consumption
|
|
// Calculate gamma rate * epsilon rate
|
|
// Diagnostics are encoded by series of binary numbers
|
|
|
|
// Gamma rate is most common bit for each bit in the series
|
|
// Epsilon rate is the opposite, i.e. least common bit
|
|
|
|
// So when gamma rate would be 10011, epsilon rate automatically is 01100
|
|
|
|
|
|
println!("Advent of Code #3!\n");
|
|
|
|
let path = Path::new("./3.txt");
|
|
let display = path.display();
|
|
|
|
let file = match File::open(&path) {
|
|
Err(why) => panic!("Couldn't open {}: {}", display, why),
|
|
Ok(file) => file,
|
|
};
|
|
|
|
let lines = io::BufReader::new(file).lines();
|
|
let mut diagnostics = Vec::<Vec::<bool>>::new();
|
|
|
|
for line in lines{
|
|
let mut d_line = Vec::<bool>::new();
|
|
if let Ok(l) = line {
|
|
for c in l.chars() {
|
|
match c {
|
|
'0' => d_line.push(false),
|
|
'1' => d_line.push(true),
|
|
_ => (),
|
|
}
|
|
}
|
|
}
|
|
diagnostics.push(d_line);
|
|
}
|
|
|
|
let mut line_numbers = 0;
|
|
let b_len = diagnostics[0].len();
|
|
let mut ones = vec![0; b_len];
|
|
|
|
for line in &diagnostics {
|
|
line_numbers += 1;
|
|
|
|
for i in 0 .. b_len {
|
|
match line[i] {
|
|
true => ones[i] += 1,
|
|
false => (),
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut gamma_rate = Vec::new();
|
|
for n in ones {
|
|
if n > line_numbers / 2 {
|
|
gamma_rate.push(true);
|
|
} else {
|
|
gamma_rate.push(false);
|
|
}
|
|
}
|
|
|
|
let mut gamma_rate_decimal = 0;
|
|
let mut pow = 1;
|
|
|
|
gamma_rate.reverse();
|
|
for b in &gamma_rate {
|
|
match b {
|
|
true => gamma_rate_decimal += pow,
|
|
false => (),
|
|
}
|
|
pow *= 2;
|
|
}
|
|
|
|
println!("Gamma rate in decimal is {}, epsilon rate in decimal is {}, yielding product of {}",
|
|
gamma_rate_decimal, pow - gamma_rate_decimal - 1,
|
|
gamma_rate_decimal * (pow - gamma_rate_decimal - 1));
|
|
|
|
|
|
|
|
// Now on to the second part of day 3
|
|
|
|
// Verify life support rating, by multiplying oxygen generator rating by co2 scrubber rating
|
|
// Oxygen generator rating is determined by finding the most common bit for the first bit
|
|
// Then, throw out all diagnostics line that do not have the same most common bit for the first position
|
|
// Repeat until only one line remains, this is the oxygen generator rating
|
|
// For the co2 scrubber rating, do the same but for the least common bit per position
|
|
|
|
gamma_rate.reverse();
|
|
let mut viable_oxygen = vec![true; line_numbers];
|
|
let mut viable_scrubber = vec![true; line_numbers];
|
|
|
|
let mut n_oxygen = line_numbers;
|
|
let mut n_scrubber = line_numbers;
|
|
|
|
for bit_n in 0 .. b_len {
|
|
let mcb = most_common_bit(bit_n, &viable_oxygen, &diagnostics);
|
|
let lcb = !most_common_bit(bit_n, &viable_scrubber, &diagnostics);
|
|
|
|
for line_n in 0 .. line_numbers {
|
|
if viable_oxygen[line_n] && n_oxygen > 1 {
|
|
if diagnostics[line_n][bit_n] != mcb {
|
|
n_oxygen -= 1;
|
|
viable_oxygen[line_n] = false;
|
|
}
|
|
}
|
|
|
|
if viable_scrubber[line_n] && n_scrubber > 1 {
|
|
if diagnostics[line_n][bit_n] != lcb {
|
|
n_scrubber -= 1;
|
|
viable_scrubber[line_n] = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// println!("\nIteration {}:", bit_n);
|
|
// for line_n in 0 .. line_numbers {
|
|
// if viable_oxygen[line_n] {
|
|
// print_bool_vec(&diagnostics[line_n]);
|
|
// }
|
|
// }
|
|
|
|
if n_oxygen == 1 && n_scrubber == 1 {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// println!("n_oxygen: {}, n_scrubber: {}", n_oxygen, n_scrubber);
|
|
|
|
let mut oxygen_ans = 0;
|
|
let mut scrubber_ans = 0;
|
|
|
|
for i in 0 .. line_numbers {
|
|
if viable_oxygen[i] {
|
|
oxygen_ans = i;
|
|
}
|
|
|
|
if viable_scrubber[i] {
|
|
scrubber_ans = i;
|
|
}
|
|
}
|
|
|
|
print_bool_vec(&diagnostics[oxygen_ans]);
|
|
// print_bool_vec(&diagnostics[scrubber_ans]);
|
|
|
|
diagnostics[oxygen_ans].reverse();
|
|
diagnostics[scrubber_ans].reverse();
|
|
|
|
let oxygen_dec = bit_to_decimal(&diagnostics[oxygen_ans]);
|
|
let scrubber_dec = bit_to_decimal(&diagnostics[scrubber_ans]);
|
|
|
|
println!("Oxygen generator rating is {}, co2 scrubber rating is {}, yields product of {}",
|
|
oxygen_dec, scrubber_dec, oxygen_dec * scrubber_dec);
|
|
}
|
|
|
|
fn bit_to_decimal(bits: &Vec::<bool>) -> u64 {
|
|
let mut pow = 1;
|
|
let mut result = 0;
|
|
|
|
for b in bits {
|
|
match b {
|
|
true => result += pow,
|
|
false => (),
|
|
}
|
|
pow *= 2;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
fn most_common_bit(index: usize, valid_series: &Vec::<bool>, bit_series: &Vec::<Vec::<bool>>) -> bool {
|
|
let mut ones = 0;
|
|
let mut valids = 0;
|
|
|
|
for i in 0 .. valid_series.len() {
|
|
if valid_series[i] {
|
|
valids += 1;
|
|
|
|
if bit_series[i][index] {
|
|
ones += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut v = valids as f32;
|
|
v /= 2.0;
|
|
v = v.ceil();
|
|
valids = v as u64;
|
|
|
|
if ones >= valids {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
fn print_bool_vec(input: &Vec::<bool>) -> () {
|
|
for b in input {
|
|
print!("{},", b);
|
|
} println!();
|
|
} |