From: alex Date: Sun, 3 Dec 2023 14:34:38 +0000 (+0100) Subject: Day03 - part 2 X-Git-Url: https://aoc.elinar.fr/?a=commitdiff_plain;h=cae5cf2775851473830fccb420318245f3fccf61;p=aoc_2023 Day03 - part 2 --- diff --git a/src/day03.rs b/src/day03.rs index 12a9b0f..c97ea41 100644 --- a/src/day03.rs +++ b/src/day03.rs @@ -84,7 +84,102 @@ fn run_part1(input: &str) -> Result> { fn run_part2(input: &str) -> Result> { 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::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::().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>) -> i32 { + let n_lines = numbers.len() - 1; // 0-based value + + let mut lines_to_check: Vec = 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 = 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 = 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()); } }