]> aoc.elinar.fr Git - aoc_2024/commitdiff
Day22 - part 2
authoralex <>
Sun, 22 Dec 2024 13:27:36 +0000 (14:27 +0100)
committeralex <>
Sun, 22 Dec 2024 13:27:36 +0000 (14:27 +0100)
src/day22.rs

index c30a8d0da5158e2ce4e95c006db8728dab10cf2a..ee13fc7daf729af4fbe6d1fde67c158b09f3899d 100644 (file)
@@ -1,5 +1,6 @@
 use std::error::Error;
 use std::path::Path;
+use std::collections::{HashMap, HashSet};
 
 fn mix(value: u64, secret: u64) -> u64 {
     value ^ secret
@@ -9,22 +10,60 @@ fn prune(value: u64) -> u64 {
     value % 16777216
 }
 
-fn new_secret(secret: u64, steps: usize) -> u64 {
+fn new_secret_steps(secret: u64, steps: usize) -> u64 {
     let mut s = secret;
-    for i in 0..steps {
+    (0..steps).for_each(|_| {
         s = prune(mix(s * 64, s));
         s = prune(mix(s / 32, s));
         s = prune(mix(s * 2048, s));
-    }
+    });
     s
 }
 
+fn new_secret(secret: u64) -> u64 {
+    let s = secret;
+    let s = prune(mix(s * 64, s));
+    let s = prune(mix(s / 32, s));
+    prune(mix(s * 2048, s))
+}
+
+fn buyer_prices(secret: u64, steps: usize) -> Vec<isize> {
+    let mut seq: Vec<u64> = Vec::new();
+    seq.push(secret);
+    (1..steps).for_each(|_| {
+        let last_secret = *seq.last().unwrap();
+        seq.push(new_secret(last_secret));
+    });
+    seq.into_iter().map(|s| (s % 10) as isize).collect()
+}
+
+fn buyer_seq(buyer_prices: &[isize]) -> Vec<isize> {
+    (1..buyer_prices.len()).zip(0..(buyer_prices.len()-1))
+        .map(|(i, j)| buyer_prices[i] - buyer_prices[j])
+        .collect()
+}
+
+fn buyer_windows(buyer_seq: &[isize]) -> HashMap<&[isize], isize> {
+    let windows = buyer_seq.windows(4).enumerate()
+         //.filter(|(i, w)| *w == vec![-2, 1, -1, 3])
+         .collect::<HashMap<_, _>>();
+
+    let mut bw: HashMap<&[isize], isize> = HashMap::new();
+    for (idx, w) in windows {
+        match bw.get_mut(w) {
+            Some(i) => { *i = (*i).min(idx as isize); } ,
+            None => { bw.insert(w, idx as isize); } ,
+        }
+    }
+    bw
+}
+
 fn run_part1(input: &str) -> Result<u64, Box<dyn Error>> {
     println!("Running {} - part 1", get_day());
 
     let res: u64 = input.lines()
         .map(|l| l.parse::<u64>().unwrap())
-        .map(|secret| new_secret(secret, 2000))
+        .map(|secret| new_secret_steps(secret, 2000))
         .sum();
 
     Ok(res)
@@ -33,7 +72,56 @@ fn run_part1(input: &str) -> Result<u64, Box<dyn Error>> {
 fn run_part2(input: &str) -> Result<u64, Box<dyn Error>> {
     println!("Running {} - part 2", get_day());
 
-    Ok(0)
+    // for each buyer, compute compute all its secrets
+    let buyer_secrets: Vec<u64> = input.lines()
+        .map(|l| l.parse::<u64>().unwrap())
+        .collect();
+
+    // for each buyer, extract its prices
+    let prices: Vec<Vec<isize>> = buyer_secrets.iter()
+        .map(|secret| buyer_prices(*secret, 2000))
+        .collect();
+
+    // for each buyer, compute the sequence of price changes
+    let seqs: Vec<Vec<isize>> = prices.iter()
+        .map(|p| buyer_seq(p))
+        .collect();
+
+    // for each buyer, extract all windows of 4 price changes with its associated index
+    let mut seqs_w: Vec<HashMap<&[isize], isize>> = seqs.iter()
+        .map(|s| buyer_windows(s))
+        .collect();
+
+    // for each buyer, associate the current price to each window
+    for (i, seq) in seqs_w.iter_mut().enumerate() {
+        seq.iter_mut()
+            .for_each(|(_, j)| { *j = prices[i][(*j+4) as usize]; });
+    }
+
+    // store all windows
+    let mut windows: HashSet<&[isize]> = HashSet::new();
+    seqs_w.iter()
+        .for_each(|s| {
+            s.iter().for_each(|(w, _)| { windows.insert(w); });
+        });
+
+    // search for the best window
+    let mut max: u64 = 0;
+    windows.iter()
+        .for_each(|w| {
+            let mut m: u64 = 0;
+            seqs_w.iter()
+                .for_each(|s| {
+                    if let Some(v) = s.get(w) {
+                        m += *v as u64;
+                    }
+                });
+            if m > max {
+                max = m;
+            }
+        });
+
+    Ok(max)
 }
 
 pub fn run(input: &str) -> Result<(), Box<dyn Error>> {
@@ -56,7 +144,10 @@ mod tests {
     use super::*;
 
     static TEXT_INPUT: &str = "\
-";
+1
+2
+3
+2024";
 
     #[test]
     fn test_part1() {
@@ -65,16 +156,21 @@ mod tests {
             12683156, 11100544, 12249484, 7753432, 5908254,
         ];
         for step in 0..secret_123_steps.len() {
-            assert_eq!(new_secret(123, step + 1), secret_123_steps[step]);
+            assert_eq!(new_secret_steps(123, step + 1), secret_123_steps[step]);
         }
-        assert_eq!(new_secret(1, 2000), 8685429);
-        assert_eq!(new_secret(10, 2000), 4700978);
-        assert_eq!(new_secret(100, 2000), 15273692);
-        assert_eq!(new_secret(2024, 2000), 8667524);
+        assert_eq!(new_secret_steps(1, 2000), 8685429);
+        assert_eq!(new_secret_steps(10, 2000), 4700978);
+        assert_eq!(new_secret_steps(100, 2000), 15273692);
+        assert_eq!(new_secret_steps(2024, 2000), 8667524);
     }
 
     #[test]
     fn test_part2() {
-        assert_eq!(0, run_part2(TEXT_INPUT).unwrap());
+        let buyer_123_prices = buyer_prices(123, 10);
+        assert_eq!(buyer_123_prices, vec![3, 0, 6, 5, 4, 4, 6, 4, 4, 2]);
+        let buyer_123_seq = buyer_seq(&buyer_123_prices);
+        assert_eq!(buyer_123_seq, vec![-3, 6, -1, -1, 0, 2, -2, 0, -2]);
+
+        assert_eq!(23, run_part2(TEXT_INPUT).unwrap());
     }
 }