From 415cd38c773572e2fd66fcec35dd80d9f90b750f Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 8 Dec 2023 09:08:53 +0100 Subject: [PATCH] Day08 - part 2 --- src/day08.rs | 120 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 109 insertions(+), 11 deletions(-) diff --git a/src/day08.rs b/src/day08.rs index ca3f181..0e9e0c8 100644 --- a/src/day08.rs +++ b/src/day08.rs @@ -3,6 +3,7 @@ use std::error::Error; use std::fs::File; use std::collections::HashMap; +use std::collections::HashSet; pub fn run(input_file: &str) -> Result<(), Box> { let mut f = File::open(input_file)?; @@ -52,10 +53,10 @@ fn run_part1(input: &str) -> Result> { let mut step = 0; let mut i = 0; - let mut found_ZZZ = false; + let mut found = false; let mut node: String = String::from("AAA"); - while !found_ZZZ { + while node != "ZZZ" { if i >= puzzle.instructions.len() { i = 0; } @@ -67,9 +68,6 @@ fn run_part1(input: &str) -> Result> { }; node = new_node.to_string(); - if node == "ZZZ".to_string() { - found_ZZZ = true; - } i += 1; step += 1; } @@ -78,9 +76,87 @@ fn run_part1(input: &str) -> Result> { Ok(res) } -fn run_part2(input: &str) -> Result> { +fn factorize(a: u32) -> Vec { + let mut res: Vec = Vec::new(); + let mut n = a; + + let mut found = false; + while !found { + let s: f64 = (n as f64).sqrt().ceil(); + let s: u32 = s as u32; + found = s == 1; + for i in 2..=s { + if n % i == 0 { + res.push(i); + n /= i; + break; + } + if i == s { + res.push(n); + found = true; + } + } + } + res +} + +fn run_part2(input: &str) -> Result> { println!("Running day08 - part 2"); - let res = 0; + let puzzle = Puzzle::new(input); + + // on commence aux nœuds qui finissent par 'A' et on cherche à rejoindre + // les nœuds qui finissent par 'Z' + // + // 1. récupérer le nombre d'étape de chaque chemin + // 2. calculer le PPCM de ces nombres d'étapes + // + // PPCM(a,b,c) = PPCM(PPCM(a,b),c) + // + // Calcul du PPCM(a,b) + // 1. décomposer a et b en facteur premier + // 2. le PPCM est égal au produit des facteurs communs et des facteurs non communs + + let start_node: Vec<_> = puzzle.nodes.keys() + .filter(|k| k.ends_with('A')) + .collect(); + + // récupération de la longueur de chaque chemin + let steps: Vec<_> = start_node.into_iter() + .map(|n| { + let mut node = n; + let mut i = 0; + let mut step = 0; + while !node.ends_with('Z') { + if i >= puzzle.instructions.len() { + i = 0; + } + + let new_node = match puzzle.instructions[i] { + 'L' => &puzzle.nodes.get(node).unwrap().0, + 'R' => &puzzle.nodes.get(node).unwrap().1, + _ => unreachable!(), + }; + + node = new_node; + i += 1; + step += 1; + } + step + }) + .collect(); + + // décomposition en facteur premier + // et on ne conserve chaque facteur qu'une unique fois + let mut factor: HashSet = HashSet::new(); + steps.into_iter() + .for_each(|s| { + let f = factorize(s); + f.into_iter().for_each(|v| { factor.insert(v); }); + }); + + let res = factor.into_iter() + .map(|v| v as u64) + .product(); Ok(res) } @@ -88,8 +164,6 @@ fn run_part2(input: &str) -> Result> { mod tests { use super::*; - static TEXT_INPUT: &str = ""; - #[test] fn day08_part1_example1() { let input = "\ @@ -120,7 +194,31 @@ ZZZ = (ZZZ, ZZZ)"; #[test] fn day08_part2() { - let res = run_part2(TEXT_INPUT); - assert_eq!(0, res.unwrap()); + let input = "\ +LR + +11A = (11B, XXX) +11B = (XXX, 11Z) +11Z = (11B, XXX) +22A = (22B, XXX) +22B = (22C, 22C) +22C = (22Z, 22Z) +22Z = (22B, 22B) +XXX = (XXX, XXX)"; + + let res = run_part2(&input); + assert_eq!(6, res.unwrap()); + } + + #[test] + fn test_factorize() { + assert_eq!(factorize(2), [2]); + assert_eq!(factorize(3), [3]); + assert_eq!(factorize(5), [5]); + assert_eq!(factorize(7), [7]); + assert_eq!(factorize(4), [2,2]); + assert_eq!(factorize(9), [3,3]); + assert_eq!(factorize(10), [2,5]); + assert_eq!(factorize(32), [2,2,2,2,2]); } } -- 2.39.5