]> aoc.elinar.fr Git - aoc_2023/commitdiff
Day08 - part 2
authoralex <null>
Fri, 8 Dec 2023 08:08:53 +0000 (09:08 +0100)
committeralex <null>
Fri, 8 Dec 2023 08:26:23 +0000 (09:26 +0100)
src/day08.rs

index ca3f18170b98e0cf6edb46a31cb5440c35b94d1b..0e9e0c8e06a7e6c8696b20dde8520a90dd73bdbc 100644 (file)
@@ -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<dyn Error>> {
     let mut f = File::open(input_file)?;
@@ -52,10 +53,10 @@ fn run_part1(input: &str) -> Result<u32, Box<dyn Error>> {
 
     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<u32, Box<dyn Error>> {
         };
 
         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<u32, Box<dyn Error>> {
     Ok(res)
 }
 
-fn run_part2(input: &str) -> Result<u32, Box<dyn Error>> {
+fn factorize(a: u32) -> Vec<u32> {
+    let mut res: Vec<u32> = 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<u64, Box<dyn Error>> {
     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<u32> = 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<u32, Box<dyn Error>> {
 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]);
     }
 }