From 20be794e885d020a3ea9d8905fab46fc64a4ae85 Mon Sep 17 00:00:00 2001 From: Lars Martens Date: Sun, 22 Dec 2024 11:12:33 +0100 Subject: [PATCH] Solve 22 --- src/bin/22.rs | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/bin/22.rs diff --git a/src/bin/22.rs b/src/bin/22.rs new file mode 100644 index 0000000..6d68c9a --- /dev/null +++ b/src/bin/22.rs @@ -0,0 +1,84 @@ +use aoc::*; +use itertools::Itertools; +use std::collections::HashMap; +use std::iter; + +const INPUT: &str = include_str!("../../input/22"); + +fn main() { + assert_example!(part1, "22-test", 37327623); + println!("Part 1: {}", part1(INPUT)); + assert_example!(part2, "22-test", 24); + println!("Part 2: {}", part2(INPUT)); +} + +fn part1(input: &str) -> usize { + parse(input) + .map(|secret| secret_numbers(secret).last().unwrap()) + .sum() +} + +fn part2(input: &str) -> usize { + let buyers = parse(input); + let possible_sales = buyers.flat_map(possible_sales); + + let mut sequences = HashMap::new(); + for (seq, price) in possible_sales { + let price = price as usize; + let entry = sequences.entry(seq).or_insert(0); + *entry += price; + } + + sequences.into_values().max().unwrap() +} + +fn possible_sales(secret: usize) -> HashMap<[i8; 4], u8> { + let mut sales = HashMap::new(); + for (a, b, c, d) in price_changes(secret).tuple_windows() { + let seq = [a.change, b.change, c.change, d.change]; + sales.entry(seq).or_insert(d.price); + } + sales +} + +fn price_changes(secret: usize) -> impl Iterator { + let prices = secret_numbers(secret).map(|s| (s % 10) as u8); + prices.tuple_windows().map(|(a, b)| PriceChange { + price: b, + change: b as i8 - a as i8, + }) +} + +#[derive(Debug, Copy, Clone)] +struct PriceChange { + price: u8, + change: i8, +} + +fn secret_numbers(mut secret: usize) -> impl Iterator { + iter::from_fn(move || { + let s = secret; + secret = mix_prune(secret); + Some(s) + }) + .take(2001) +} + +fn mix_prune(mut secret: usize) -> usize { + const MOD: usize = 16777216; + + let n = secret * 64; + secret = (secret ^ n) % MOD; + + let n = secret / 32; + secret = (secret ^ n) % MOD; + + let n = secret * 2048; + secret = (secret ^ n) % MOD; + + secret +} + +fn parse(input: &str) -> impl Iterator + use<'_> { + input.lines().map(|line| line.parse().unwrap()) +}