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)
}
#[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());
}
}