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
|
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?**
|
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;
|
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!
|
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.
|
Of course, the actual engine schematic is much larger.
|
||||||
**What is the sum of all of the part numbers in the engine schematic?**
|
**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())
|
(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 min = r.start;
|
||||||
let max = r.end - 1;
|
let max = r.end - 1;
|
||||||
let mut ind = HashSet::new();
|
let mut ind = HashSet::new();
|
||||||
@ -154,16 +154,20 @@ impl Grid {
|
|||||||
ind
|
ind
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_adjacent(&self, r: Range<usize>) -> Vec<ValueType> {
|
fn find_adjacent_range(&self, r: Range<usize>) -> Vec<ValueType> {
|
||||||
self.adjacent_ind(r)
|
self.adjacent_ind_range(r)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|ind| self.values[ind])
|
.map(|ind| self.values[ind])
|
||||||
.collect()
|
.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 {
|
fn is_part_number(&self, r: Range<usize>) -> bool {
|
||||||
use ValueType::*;
|
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,
|
Symbol(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
})
|
})
|
||||||
@ -180,13 +184,85 @@ impl Grid {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_unique_part_numbers(&self) -> HashSet<usize> {
|
fn get_part_number_ind(&self) -> Vec<usize> {
|
||||||
HashSet::from_iter(self.get_part_numbers().iter().cloned())
|
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 {
|
fn get_part_number_sum(&self) -> usize {
|
||||||
self.get_part_numbers().iter().sum()
|
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() {
|
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() {
|
fn main() {
|
||||||
part_one();
|
part_one();
|
||||||
|
part_two();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -206,7 +288,6 @@ mod tests {
|
|||||||
const EXAMPLE_FILE_STR: &'static str = include_str!("example_input.txt");
|
const EXAMPLE_FILE_STR: &'static str = include_str!("example_input.txt");
|
||||||
use super::*;
|
use super::*;
|
||||||
use FromIterator;
|
use FromIterator;
|
||||||
use ValueType::*;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_part_number_sum_part_1() {
|
fn test_get_part_number_sum_part_1() {
|
||||||
@ -215,9 +296,15 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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 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!(12, actual.len());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
HashSet::from_iter(actual.iter().cloned()),
|
HashSet::from_iter(actual.iter().cloned()),
|
||||||
@ -237,4 +324,11 @@ mod tests {
|
|||||||
let grid = Grid::parse(EXAMPLE_FILE_STR);
|
let grid = Grid::parse(EXAMPLE_FILE_STR);
|
||||||
assert_eq!(grid.get_part_number_sum(), 4361);
|
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