Complete 2023 Day 3
This commit is contained in:
parent
979d241bb8
commit
822157e3bb
@ -45,7 +45,7 @@ IDs of the games that would have been possible, you get **8**.
|
||||
Determine which games would have been possible if the bag had been loaded with only 12 red cubes, 13 green cubes, and
|
||||
14 blue cubes. **What is the sum of the IDs of those games?**
|
||||
|
||||
## Part Two
|
||||
## Part 2
|
||||
|
||||
The Elf says they've stopped producing snow because they aren't getting any **water**! He isn't sure why the water stopped;
|
||||
however, he can show you how to get to the water source to check it out for yourself. It's just up ahead!
|
||||
|
@ -39,3 +39,44 @@ In this schematic, two numbers are **not** part numbers because they are not adj
|
||||
|
||||
Of course, the actual engine schematic is much larger.
|
||||
**What is the sum of all of the part numbers in the engine schematic?**
|
||||
|
||||
## Part 2
|
||||
|
||||
The engineer finds the missing part and installs it in the engine! As the engine springs to life, you jump in the
|
||||
closest gondola, finally ready to ascend to the water source.
|
||||
|
||||
You don't seem to be going very fast, though. Maybe something is still wrong? Fortunately, the gondola has a phone
|
||||
labeled "help", so you pick it up and the engineer answers.
|
||||
|
||||
Before you can explain the situation, she suggests that you look out the window. There stands the engineer, holding a
|
||||
phone in one hand and waving with the other. You're going so slowly that you haven't even left the station. You exit
|
||||
the gondola.
|
||||
|
||||
The missing part wasn't the only issue - one of the gears in the engine is wrong. A **gear** is any `*` symbol that is
|
||||
adjacent to **exactly two part numbers**. Its **gear ratio** is the result of multiplying those two numbers together.
|
||||
|
||||
This time, you need to find the gear ratio of every gear and add them all up so that the engineer can figure out
|
||||
which gear needs to be replaced.
|
||||
|
||||
Consider the same engine schematic again:
|
||||
|
||||
```
|
||||
467..114.. FAILED
|
||||
|
||||
...*......
|
||||
..35..633.
|
||||
......#...
|
||||
617*......
|
||||
.....+.58.
|
||||
..592.....
|
||||
......755.
|
||||
...$.*....
|
||||
.664.598..
|
||||
```
|
||||
|
||||
In this schematic, there are **two** gears. The first is in the top left; it has part numbers `467` and `35`, so its
|
||||
gear ratio is `16345`. The second gear is in the lower right; its gear ratio is `451490`. (The * adjacent to `617` is
|
||||
**not** a gear because it is only adjacent to one part number.) Adding up all of the gear ratios produces `**467835**`.
|
||||
|
||||
**What is the sum of all of the gear ratios in your engine schematic?**
|
||||
|
||||
|
@ -105,7 +105,7 @@ impl Grid {
|
||||
(idx % self.num_cols(), idx / self.num_cols())
|
||||
}
|
||||
|
||||
fn adjacent_ind(&self, r: Range<usize>) -> HashSet<usize> {
|
||||
fn adjacent_ind_range(&self, r: Range<usize>) -> HashSet<usize> {
|
||||
let min = r.start;
|
||||
let max = r.end - 1;
|
||||
let mut ind = HashSet::new();
|
||||
@ -154,16 +154,20 @@ impl Grid {
|
||||
ind
|
||||
}
|
||||
|
||||
fn find_adjacent(&self, r: Range<usize>) -> Vec<ValueType> {
|
||||
self.adjacent_ind(r)
|
||||
fn find_adjacent_range(&self, r: Range<usize>) -> Vec<ValueType> {
|
||||
self.adjacent_ind_range(r)
|
||||
.into_iter()
|
||||
.map(|ind| self.values[ind])
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn find_adjacent(&self, i: usize) -> HashSet<ValueType> {
|
||||
HashSet::from_iter(self.find_adjacent_range(i..i + 1).iter().cloned())
|
||||
}
|
||||
|
||||
fn is_part_number(&self, r: Range<usize>) -> bool {
|
||||
use ValueType::*;
|
||||
self.find_adjacent(r).into_iter().any(|t| match t {
|
||||
self.find_adjacent_range(r).into_iter().any(|t| match t {
|
||||
Symbol(_) => true,
|
||||
_ => false,
|
||||
})
|
||||
@ -180,13 +184,85 @@ impl Grid {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_unique_part_numbers(&self) -> HashSet<usize> {
|
||||
HashSet::from_iter(self.get_part_numbers().iter().cloned())
|
||||
fn get_part_number_ind(&self) -> Vec<usize> {
|
||||
self.numbers
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, nl)| {
|
||||
let range = nl.start..nl.end;
|
||||
self.is_part_number(range)
|
||||
})
|
||||
.map(|(id, _)| id)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_gears(&self) -> Vec<usize> {
|
||||
self.values
|
||||
.clone()
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.filter(|(_, vt)| match vt {
|
||||
ValueType::Symbol('*') => true,
|
||||
_ => false,
|
||||
})
|
||||
.map(|(id, _)| id)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_gear_ratios(&self) -> Vec<(usize, usize)> {
|
||||
let valid_part_number_ind = self.get_part_number_ind();
|
||||
let potential_gear_symbols = self.get_gears();
|
||||
|
||||
// Valid gear ratios are two valid part numbers adjacent to the gear symbol
|
||||
let raw_gear_ratios: Vec<_> = potential_gear_symbols
|
||||
.into_iter()
|
||||
.filter_map(|s| {
|
||||
let mut number_count = 0;
|
||||
let gr: Vec<_> = self
|
||||
.find_adjacent(s)
|
||||
.into_iter()
|
||||
.filter(|vt| match vt {
|
||||
ValueType::Number(id) => valid_part_number_ind.contains(id),
|
||||
_ => false,
|
||||
})
|
||||
.collect();
|
||||
|
||||
gr.iter().for_each(|vt| match vt {
|
||||
ValueType::Number(_) => number_count += 1,
|
||||
_ => {}
|
||||
});
|
||||
|
||||
match number_count {
|
||||
2 => Some(gr),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
raw_gear_ratios
|
||||
.into_iter()
|
||||
.map(|v| {
|
||||
v.into_iter()
|
||||
.map(|vt| match vt {
|
||||
ValueType::Number(id) => self.numbers[id].to_number(),
|
||||
_ => panic!("Invalid gear ratio!"),
|
||||
})
|
||||
.collect::<Vec<usize>>()
|
||||
})
|
||||
.map(|gr| (gr[0], gr[1]))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_part_number_sum(&self) -> usize {
|
||||
self.get_part_numbers().iter().sum()
|
||||
}
|
||||
|
||||
fn get_gear_ratio_sum(&self) -> usize {
|
||||
self.get_gear_ratios()
|
||||
.into_iter()
|
||||
.map(|(gr0, gr1)| gr0 * gr1)
|
||||
.sum()
|
||||
}
|
||||
}
|
||||
|
||||
fn part_one() {
|
||||
@ -197,8 +273,14 @@ fn part_one() {
|
||||
);
|
||||
}
|
||||
|
||||
fn part_two() {
|
||||
let grid = Grid::parse(FILE_STR);
|
||||
println!("Part 2: Sum of gear ratios: {}", grid.get_gear_ratio_sum())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
part_one();
|
||||
part_two();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -206,7 +288,6 @@ mod tests {
|
||||
const EXAMPLE_FILE_STR: &'static str = include_str!("example_input.txt");
|
||||
use super::*;
|
||||
use FromIterator;
|
||||
use ValueType::*;
|
||||
|
||||
#[test]
|
||||
fn test_get_part_number_sum_part_1() {
|
||||
@ -215,9 +296,15 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_adjacent_index() {
|
||||
fn test_get_gear_ratio_sum_part_2() {
|
||||
let grid = Grid::parse(FILE_STR);
|
||||
assert_eq!(grid.get_gear_ratio_sum(), 84289137);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_adjacent_ind_range() {
|
||||
let grid = Grid::parse(EXAMPLE_FILE_STR);
|
||||
let actual = grid.adjacent_ind(62..65);
|
||||
let actual = grid.adjacent_ind_range(62..65);
|
||||
assert_eq!(12, actual.len());
|
||||
assert_eq!(
|
||||
HashSet::from_iter(actual.iter().cloned()),
|
||||
@ -237,4 +324,11 @@ mod tests {
|
||||
let grid = Grid::parse(EXAMPLE_FILE_STR);
|
||||
assert_eq!(grid.get_part_number_sum(), 4361);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_gear_ratio_sum() {
|
||||
let grid = Grid::parse(EXAMPLE_FILE_STR);
|
||||
let sum = grid.get_gear_ratio_sum();
|
||||
assert_eq!(sum, 467835);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user