From cee59608de180349af58c66d52455acfa7fb44cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20LUDWIG?= Date: Fri, 8 Dec 2023 18:29:27 +0100 Subject: [PATCH] feat: add day 3 - part 2 --- day_3/README.md | 2 +- day_3/src/lib.rs | 126 ++++++++++++++++++++++++++++++++++++++++++---- day_3/src/main.rs | 4 +- 3 files changed, 120 insertions(+), 12 deletions(-) diff --git a/day_3/README.md b/day_3/README.md index 1555ad4..990527e 100644 --- a/day_3/README.md +++ b/day_3/README.md @@ -72,6 +72,6 @@ In this schematic, there are **two** gears. The first is in the top left; it has **What is the sum of all of the gear ratios in your engine schematic?** -Your puzzle answer was `answer`. +Your puzzle answer was `84363105`. **Both parts of this puzzle are complete! They provide two gold stars: `**`.** diff --git a/day_3/src/lib.rs b/day_3/src/lib.rs index 17a280c..ca3730b 100644 --- a/day_3/src/lib.rs +++ b/day_3/src/lib.rs @@ -1,8 +1,17 @@ -#[derive(Debug, PartialEq)] +use std::collections::HashMap; + +#[derive(Debug, PartialEq, Default, Clone, Copy)] +pub struct GearPosition { + pub index_line: usize, + pub index_character: usize, +} + +#[derive(Debug, PartialEq, Default, Clone, Copy)] pub struct NumberPosition { pub index_start: usize, pub index_end: usize, pub value: usize, + pub gear_position: GearPosition, } pub fn get_numbers_positions_from_line(line: &str) -> Vec { @@ -23,6 +32,7 @@ pub fn get_numbers_positions_from_line(line: &str) -> Vec { index_start, index_end, value, + gear_position: GearPosition::default(), }); number_string = String::from(""); index_start = 0; @@ -35,6 +45,7 @@ pub fn get_numbers_positions_from_line(line: &str) -> Vec { index_start, index_end, value, + gear_position: GearPosition::default(), }); } result @@ -44,6 +55,10 @@ pub fn is_symbol(character: char) -> bool { !character.is_ascii_digit() && character != '.' } +pub fn is_gear_symbol(character: char) -> bool { + character == '*' +} + pub fn part_1(input: &str) -> usize { let lines = input.lines().collect::>(); lines @@ -82,15 +97,108 @@ pub fn part_1(input: &str) -> usize { || has_symbol_on_the_top || has_symbol_on_the_bottom }) - .map(|matching_number| matching_number.value) + .map(|number_position| number_position.value) .sum::() }) .sum() } -// pub fn part_2(_input: &str) -> usize { -// 42 -// } +pub fn part_2(input: &str) -> usize { + let lines = input.lines().collect::>(); + let mut number_positions = vec![]; + + lines.iter().enumerate().for_each(|(index_line, &line)| { + get_numbers_positions_from_line(line) + .iter() + .for_each(|&number_position| { + let index_start = number_position.index_start.saturating_sub(1); + let index_end = if number_position.index_end + 1 >= line.len() { + line.len().saturating_sub(1) + } else { + number_position.index_end + 1 + }; + + let has_symbol_on_the_left = + line.chars().nth(index_start).is_some_and(is_gear_symbol); + if has_symbol_on_the_left { + let mut number_position = number_position.to_owned(); + number_position.gear_position.index_line = index_line; + number_position.gear_position.index_character = index_start; + number_positions.push(number_position); + } + + let has_symbol_on_the_right = + line.chars().nth(index_end).is_some_and(is_gear_symbol); + if has_symbol_on_the_right { + let mut number_position = number_position.to_owned(); + number_position.gear_position.index_line = index_line; + number_position.gear_position.index_character = index_end; + number_positions.push(number_position); + } + + let index_character_top = + lines.get(index_line.saturating_sub(1)).and_then(|&line| { + line.get(index_start..=index_end) + .and_then(|value| value.chars().position(is_gear_symbol)) + }); + if let Some(index_character_top) = index_character_top { + let mut number_position = number_position.to_owned(); + number_position.gear_position.index_line = index_line.saturating_sub(1); + number_position.gear_position.index_character = + index_character_top + index_start; + number_positions.push(number_position); + } + + let index_character_bottom = lines.get(index_line + 1).and_then(|&line| { + line.get(index_start..=index_end) + .and_then(|value| value.chars().position(is_gear_symbol)) + }); + if let Some(index_character_bottom) = index_character_bottom { + let mut number_position = number_position.to_owned(); + number_position.gear_position.index_line = index_line + 1; + number_position.gear_position.index_character = + index_character_bottom + index_start; + number_positions.push(number_position); + } + }); + }); + + // Key: "index_line-index_character" + // Value: usize + let mut gear_positions: HashMap> = HashMap::new(); + + number_positions.iter().for_each(|&number_position| { + let key = format!( + "{}-{}", + number_position.gear_position.index_line, number_position.gear_position.index_character, + ); + match gear_positions.get_mut(&key) { + Some(gear_positions) => { + gear_positions.push(number_position.value); + } + None => { + gear_positions.insert(key, vec![number_position.value]); + } + } + }); + + let mut result = 0; + + for (_, value) in gear_positions.iter() { + if value.len() != 2 { + continue; + } + + let first_number = value.first(); + let second_number = value.last(); + + if let (Some(first_number), Some(second_number)) = (first_number, second_number) { + result += first_number * second_number; + } + } + + result +} #[cfg(test)] mod day_3_tests { @@ -101,8 +209,8 @@ mod day_3_tests { assert_eq!(part_1(include_str!("../input_example_1.txt")), 4361); } - // #[test] - // fn test_part_2_example() { - // assert_eq!(part_2(include_str!("../input_example_1.txt")), 467835); - // } + #[test] + fn test_part_2_example() { + assert_eq!(part_2(include_str!("../input_example_1.txt")), 467835); + } } diff --git a/day_3/src/main.rs b/day_3/src/main.rs index 31b334d..896b5f5 100644 --- a/day_3/src/main.rs +++ b/day_3/src/main.rs @@ -1,8 +1,8 @@ -use day_3::part_1; +use day_3::{part_1, part_2}; fn main() { let input = include_str!("../input.txt"); println!("- Day 3: Gear Ratios -"); println!("Answer Part 1: {}", part_1(input)); - // println!("Answer Part 2: {}", part_2(input)); + println!("Answer Part 2: {}", part_2(input)); }