]> aoc.elinar.fr Git - aoc_2023/commitdiff
Day03 - part 2
authoralex <null>
Sun, 3 Dec 2023 14:34:38 +0000 (15:34 +0100)
committeralex <null>
Sun, 3 Dec 2023 14:34:38 +0000 (15:34 +0100)
src/day03.rs

index 12a9b0f23b4d7e08421a38238ea1fcd4f5575f72..c97ea418345423edd6a4ea6812fa757a3ca82278 100644 (file)
@@ -84,7 +84,102 @@ fn run_part1(input: &str) -> Result<i32, Box<dyn Error>> {
 
 fn run_part2(input: &str) -> Result<i32, Box<dyn Error>> {
     println!("Running day03 - part 2");
-    let res = 0;
+
+    // il faut trouver les symboles qui sont adjacents à *exactement* 2 nombres
+    // ensuite multiplier ces 2 nombres
+    // enfin additionner tous les résultats obtenus
+    //
+    // aussi on ne s'intéresse qu'aux symboles de type étoile "*"
+    //
+    // dans la partie 1, on partait de chaque nombre trouvé et regardait s'il
+    // était adjacent à un symbole
+    // dans cette partie 2 il semblerait plus judicieux de partie de chaque
+    // symbole et de chercher les nombres adjacents
+    // s'il y en a exactement 2 on additionne leur produit au résultat
+
+    // avec la crate regex, un nombre est une Capture qui contient l'index
+    // de début et l'index de fin, donc on peut définir une slice
+    // [(start-1)..(end+1)] et regarder si l'index du symbol est dedans.
+
+    // première passe, on extrait tous les nombres
+    // deuxième passe, pour chaque symbole "*", on analyse son entourage
+    //
+    // forme des données extraites de la première passe :
+    //   vecteur de vecteur
+    //   pour chaque ligne on stocke (start, end, value)
+
+    let re = Regex::new(r"\d+").unwrap();
+
+    let mut numbers: Vec<Vec<(usize, usize, i32)>> = Vec::new();
+    input.lines()
+        .for_each(|l| {
+            let mut line: Vec<(usize, usize, i32)> = Vec::new();
+            re.captures_iter(l)
+                .for_each(|c| {
+                    let m = c.get(0).unwrap();
+                    line.push((
+                            m.start(),
+                            m.end() - 1,
+                            m.as_str().parse::<i32>().unwrap()
+                    ));
+                });
+            numbers.push(line);
+        });
+    //println!("numbers: {:?}", numbers);
+
+    // deuxième passe, on cherche les symboles "*"
+    // puis recherche des nombres adjacents
+    // si exactement 2 nombres, on retourne leur produit
+    fn get_gear_ratio(line_number: usize, n_chars: usize, idx: usize, numbers: &Vec<Vec<(usize, usize, i32)>>) -> i32 {
+        let n_lines = numbers.len() - 1; // 0-based value
+
+        let mut lines_to_check: Vec<usize> = Vec::new();
+        if line_number > 0 { lines_to_check.push(line_number - 1); }
+        lines_to_check.push(line_number);
+        if line_number < n_lines { lines_to_check.push(line_number + 1); }
+
+        let mut idx_to_check: Vec<usize> = Vec::new();
+        if idx > 0 { idx_to_check.push(idx - 1); }
+        idx_to_check.push(idx);
+        if idx < n_chars { idx_to_check.push(idx + 1); }
+
+        let mut adjacent: Vec<i32> = Vec::new();
+        lines_to_check.iter()
+            .for_each(|i| {
+                numbers[*i].clone().into_iter()
+                    .filter(|(start, end, _)| {
+                        // pour chaque index autour du symbole, est-il dans
+                        // le slice [start..end] du nombre (end est inclus)
+                        idx_to_check.iter()
+                            .filter(|j| {
+                                (start..=end).contains(j)
+                            })
+                            .count() > 0
+                    })
+                    .for_each(|f| {
+                        //println!("found (line {line_number}): {:?}", f);
+                        adjacent.push(f.2);
+                    });
+            });
+        if adjacent.len() == 2 {
+            //println!("adjacent (line {line_number}): {:?}", adjacent);
+            return adjacent.iter().product();
+        }
+        0
+    }
+
+    let mut res = 0;
+    input.lines().enumerate()
+        .for_each(|(idx, l)| {
+            let n_chars = l.chars().count() - 1; // 0-based value;
+            l.chars().enumerate()
+                .filter(|(_, c)| *c == '*')
+                .for_each(|(i, _)| {
+                    //println!("symbol found: {idx}, {i}");
+                    res += get_gear_ratio(idx, n_chars, i, &numbers);
+                });
+        });
+
     Ok(res)
 }
 
@@ -111,8 +206,26 @@ mod tests {
 
     #[test]
     fn day03_part2() {
-        let input = "";
+        let input = "\
+467..114..
+...*......
+..35..633.
+......#...
+617*......
+.....+.58.
+..592.....
+......755.
+...$.*....
+.664.598..";
+        let res = run_part2(&input);
+        assert_eq!(467835, res.unwrap());
+    }
+
+    #[test]
+    fn day03_part2_end_of_line() {
+        let input = "\
+...153*274";
         let res = run_part2(&input);
-        assert_eq!(0, res.unwrap());
+        assert_eq!(41922, res.unwrap());
     }
 }