-
Notifications
You must be signed in to change notification settings - Fork 0
/
22.rs
64 lines (53 loc) · 1.78 KB
/
22.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#![feature(test)]
use std::sync::atomic::{AtomicU64, Ordering};
use itertools::Itertools;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
type Input = Vec<u64>;
fn setup(input: &str) -> Input {
input.trim().lines().map(|l| l.parse().unwrap()).collect()
}
fn evolve(secret: u64) -> impl Iterator<Item = u64> {
std::iter::successors(Some(secret), |&num| {
let num = ((num << 6) ^ num) & 0xFFFFFF;
let num = ((num >> 5) ^ num) & 0xFFFFFF;
let num = ((num << 11) ^ num) & 0xFFFFFF;
Some(num)
})
}
fn diffs_to_idx(diffs: [i64; 4]) -> usize {
diffs.into_iter().fold(0, |idx, x| {
debug_assert!((-9..=9).contains(&x));
idx * 19 + (x + 9) as usize
})
}
fn part1(input: &Input) -> u64 {
input
.par_iter()
.map(|&secret| evolve(secret).nth(2000).unwrap())
.sum()
}
fn part2(input: &Input) -> u64 {
let sequences = (0..19usize.pow(4))
.map(|_| AtomicU64::new(0))
.collect::<Vec<_>>();
input.par_iter().for_each(|&secret| {
let mut seen = [0u64; 19usize.pow(4).div_ceil(64)];
evolve(secret)
.map(|num| num % 10)
.tuple_windows()
.map(|(a, b)| (b as i64 - a as i64, b))
.take(2000)
.tuple_windows()
.map(|((a, _), (b, _), (c, _), (d, price))| ((a, b, c, d), price))
.for_each(|(seq, price)| {
let idx = diffs_to_idx(seq.into());
if seen[idx / 64] & (1 << (idx % 64)) != 0 {
return;
}
seen[idx / 64] |= 1 << (idx % 64);
sequences[idx].fetch_add(price, Ordering::Relaxed);
});
});
sequences.into_iter().map(|x| x.into_inner()).max().unwrap()
}
aoc::main!(2024, 22, ex: 1, 2);