Added Solution for 2021 day 03

This commit is contained in:
Burnus 2023-04-19 20:12:33 +02:00
parent 028b30f131
commit 690296f00a
5 changed files with 1184 additions and 0 deletions

View file

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

View file

@ -0,0 +1,81 @@
The submarine has been making some odd creaking noises, so you ask it to produce a diagnostic report just in case.
The diagnostic report (your puzzle input) consists of a list of binary numbers which, when decoded properly, can tell you many useful things about the conditions of the submarine. The first parameter to check is the *power consumption*.
You need to use the binary numbers in the diagnostic report to generate two new binary numbers (called the *gamma rate* and the *epsilon rate*). The power consumption can then be found by multiplying the gamma rate by the epsilon rate.
Each bit in the gamma rate can be determined by finding the *most common bit in the corresponding position* of all numbers in the diagnostic report. For example, given the following diagnostic report:
```
00100
11110
10110
10111
10101
01111
00111
11100
10000
11001
00010
01010
```
Considering only the first bit of each number, there are five `0` bits and seven `1` bits. Since the most common bit is `1`, the first bit of the gamma rate is `1`.
The most common second bit of the numbers in the diagnostic report is `0`, so the second bit of the gamma rate is `0`.
The most common value of the third, fourth, and fifth bits are `1`, `1`, and `0`, respectively, and so the final three bits of the gamma rate are `110`.
So, the gamma rate is the binary number `10110`, or `*22*` in decimal.
The epsilon rate is calculated in a similar way; rather than use the most common bit, the least common bit from each position is used. So, the epsilon rate is `01001`, or `*9*` in decimal. Multiplying the gamma rate (`22`) by the epsilon rate (`9`) produces the power consumption, `*198*`.
Use the binary numbers in your diagnostic report to calculate the gamma rate and epsilon rate, then multiply them together. *What is the power consumption of the submarine?* (Be sure to represent your answer in decimal, not binary.)
Your puzzle answer was `2498354`.
\--- Part Two ---
----------
Next, you should verify the *life support rating*, which can be determined by multiplying the *oxygen generator rating* by the *CO2 scrubber rating*.
Both the oxygen generator rating and the CO2 scrubber rating are values that can be found in your diagnostic report - finding them is the tricky part. Both values are located using a similar process that involves filtering out values until only one remains. Before searching for either rating value, start with the full list of binary numbers from your diagnostic report and *consider just the first bit* of those numbers. Then:
* Keep only numbers selected by the *bit criteria* for the type of rating value for which you are searching. Discard numbers which do not match the bit criteria.
* If you only have one number left, stop; this is the rating value for which you are searching.
* Otherwise, repeat the process, considering the next bit to the right.
The *bit criteria* depends on which type of rating value you want to find:
* To find *oxygen generator rating*, determine the *most common* value (`0` or `1`) in the current bit position, and keep only numbers with that bit in that position. If `0` and `1` are equally common, keep values with a `*1*` in the position being considered.
* To find *CO2 scrubber rating*, determine the *least common* value (`0` or `1`) in the current bit position, and keep only numbers with that bit in that position. If `0` and `1` are equally common, keep values with a `*0*` in the position being considered.
For example, to determine the *oxygen generator rating* value using the same example diagnostic report from above:
* Start with all 12 numbers and consider only the first bit of each number. There are more `1` bits (7) than `0` bits (5), so keep only the 7 numbers with a `1` in the first position: `11110`, `10110`, `10111`, `10101`, `11100`, `10000`, and `11001`.
* Then, consider the second bit of the 7 remaining numbers: there are more `0` bits (4) than `1` bits (3), so keep only the 4 numbers with a `0` in the second position: `10110`, `10111`, `10101`, and `10000`.
* In the third position, three of the four numbers have a `1`, so keep those three: `10110`, `10111`, and `10101`.
* In the fourth position, two of the three numbers have a `1`, so keep those two: `10110` and `10111`.
* In the fifth position, there are an equal number of `0` bits and `1` bits (one each). So, to find the *oxygen generator rating*, keep the number with a `1` in that position: `10111`.
* As there is only one number left, stop; the *oxygen generator rating* is `10111`, or `*23*` in decimal.
Then, to determine the *CO2 scrubber rating* value from the same example above:
* Start again with all 12 numbers and consider only the first bit of each number. There are fewer `0` bits (5) than `1` bits (7), so keep only the 5 numbers with a `0` in the first position: `00100`, `01111`, `00111`, `00010`, and `01010`.
* Then, consider the second bit of the 5 remaining numbers: there are fewer `1` bits (2) than `0` bits (3), so keep only the 2 numbers with a `1` in the second position: `01111` and `01010`.
* In the third position, there are an equal number of `0` bits and `1` bits (one each). So, to find the *CO2 scrubber rating*, keep the number with a `0` in that position: `01010`.
* As there is only one number left, stop; the *CO2 scrubber rating* is `01010`, or `*10*` in decimal.
Finally, to find the life support rating, multiply the oxygen generator rating (`23`) by the CO2 scrubber rating (`10`) to get `*230*`.
Use the binary numbers in your diagnostic report to calculate the oxygen generator rating and CO2 scrubber rating, then multiply them together. *What is the life support rating of the submarine?* (Be sure to represent your answer in decimal, not binary.)
Your puzzle answer was `3277956`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, you should [return to your Advent calendar](/2021) and try another puzzle.
If you still want to see it, you can [get your puzzle input](3/input).

View file

@ -0,0 +1,83 @@
use core::fmt::Display;
#[derive(Debug, PartialEq, Eq)]
pub enum ParseError {
ParseIntError(char),
}
impl Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::ParseIntError(e) => write!(f, "Unable to parse into integer {e}"),
}
}
}
pub fn run(input: &str) -> Result<(usize, usize), ParseError> {
let bits: Vec<_> = input.lines().map(|line| line.chars().map(|i| i.to_digit(10).ok_or(ParseError::ParseIntError(i))).collect::<Result<Vec<_>, _>>()).collect::<Result<Vec<_>, _>>()?;
let mut ones = vec![0; bits[0].len()];
bits.iter().for_each(|number| number.iter().enumerate().for_each(|(idx, bit)| ones[idx] += bit));
let half = bits.len() as u32/2;
let mut gamma = 0;
let mut epsilon = 0;
ones.iter().for_each(|bit_count| {
gamma *= 2;
epsilon *= 2;
if bit_count > &half {
gamma += 1;
} else {
epsilon += 1;
}
});
let first = gamma as usize * epsilon as usize;
let bit_count = bits.len();
let mut oxygen_rating = bits.clone();
for idx in 0..bit_count {
if oxygen_rating.len() > 1 {
if oxygen_rating.iter().map(|bits| bits[idx]).sum::<u32>() >= (oxygen_rating.len() as u32 + 1) / 2 {
oxygen_rating.retain(|bits| bits[idx] == 1);
} else {
oxygen_rating.retain(|bits| bits[idx] == 0);
}
}
}
let oxygen_rating = oxygen_rating[0].iter().fold(0, |acc, bit| 2 * acc + *bit);
let mut co2_rating = bits.clone();
for idx in 0..bit_count {
if co2_rating.len() > 1 {
if co2_rating.iter().map(|bits| bits[idx]).sum::<u32>() >= (co2_rating.len() as u32 + 1) / 2 {
co2_rating.retain(|bits| bits[idx] == 0);
} else {
co2_rating.retain(|bits| bits[idx] == 1);
}
}
}
let co2_rating = co2_rating[0].iter().fold(0, |acc, bit| 2 * acc + *bit);
let second = oxygen_rating as usize * co2_rating as usize;
Ok((first, second))
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {name}")[..]).trim().to_string()
}
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
assert_eq!(run(&sample_input), Ok((198, 230)));
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input), Ok((2498354, 3277956)));
}
}

File diff suppressed because it is too large Load diff

View file

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