|
1 |
| -use rustc_hash::FxHashMap; |
2 |
| - |
3 |
| -use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; |
| 1 | +use memoize::memoize; |
4 | 2 |
|
5 | 3 | advent_of_code::solution!(11);
|
6 | 4 |
|
7 | 5 | type Stone = u64;
|
8 | 6 | type Step = u8;
|
9 |
| -type MemoKey = (Step, Stone); |
10 |
| -type Memo = FxHashMap<MemoKey, u64>; |
11 | 7 |
|
12 |
| -fn blink_rec(memo: &mut Memo, stone: Stone, times: Step) -> u64 { |
| 8 | +#[memoize] |
| 9 | +fn blink_rec(stone: Stone, times: Step) -> u64 { |
13 | 10 | if times == 0 {
|
14 | 11 | return 1;
|
15 | 12 | }
|
16 |
| - if let Some(count) = memo.get(&(times, stone)) { |
17 |
| - return *count; |
18 |
| - } |
19 | 13 |
|
20 |
| - let res = { |
21 |
| - let mut digit_count = 0; |
22 |
| - let mut temp = stone; |
23 |
| - while temp > 0 { |
24 |
| - digit_count += 1; |
25 |
| - temp /= 10; |
26 |
| - } |
| 14 | + if stone == 0 { |
| 15 | + return blink_rec(1, times - 1); |
| 16 | + } |
| 17 | + let mut digit_count = 0; |
| 18 | + let mut temp = stone; |
| 19 | + while temp > 0 { |
| 20 | + digit_count += 1; |
| 21 | + temp /= 10; |
| 22 | + } |
27 | 23 |
|
28 |
| - if stone == 0 { |
29 |
| - blink_rec(memo, 1, times - 1) |
30 |
| - } else if digit_count % 2 == 0 { |
31 |
| - let divisor = 10_u64.pow(digit_count / 2); |
32 |
| - blink_rec(memo, stone / divisor, times - 1) |
33 |
| - + blink_rec(memo, stone % divisor, times - 1) |
34 |
| - } else { |
35 |
| - blink_rec(memo, stone * 2024, times - 1) |
36 |
| - } |
37 |
| - }; |
| 24 | + if digit_count % 2 == 0 { |
| 25 | + let divisor = 10_u64.pow(digit_count / 2); |
| 26 | + return blink_rec(stone / divisor, times - 1) + blink_rec(stone % divisor, times - 1); |
| 27 | + } |
38 | 28 |
|
39 |
| - memo.insert((times, stone), res); |
40 |
| - res |
| 29 | + return blink_rec(stone * 2024, times - 1); |
41 | 30 | }
|
42 | 31 |
|
43 |
| -fn parse_input(input: &str) -> Vec<Stone> { |
44 |
| - input |
| 32 | +fn solve(input: &str, times: Step) -> u64 { |
| 33 | + let stones = input |
45 | 34 | .split_whitespace()
|
46 | 35 | .filter(|p| !p.is_empty())
|
47 | 36 | .map(|s| s.parse::<u64>())
|
48 | 37 | .filter(|r| r.is_ok())
|
49 | 38 | .map(|r| r.unwrap())
|
50 |
| - .collect::<Vec<_>>() |
51 |
| -} |
| 39 | + .collect::<Vec<_>>(); |
52 | 40 |
|
53 |
| -pub fn part_one(input: &str) -> Option<u64> { |
54 |
| - let times = 25; |
55 |
| - let stones = parse_input(input); |
56 |
| - let mut memo = FxHashMap::with_capacity_and_hasher(100000, Default::default()); |
57 | 41 | let count = stones
|
58 |
| - .iter() |
59 |
| - .map(|start_stone| blink_rec(&mut memo, *start_stone, times)) |
| 42 | + .iter() // so fast that parallel is slower |
| 43 | + .map(|start_stone| blink_rec(*start_stone, times)) |
60 | 44 | .sum::<u64>();
|
61 | 45 |
|
62 |
| - Some(count as u64) |
| 46 | + return count; |
63 | 47 | }
|
64 | 48 |
|
65 |
| -pub fn part_two(input: &str) -> Option<u64> { |
66 |
| - let times = 75; |
67 |
| - let stones = parse_input(input); |
68 |
| - let count = stones |
69 |
| - .par_iter() |
70 |
| - .map(|start_stone| { |
71 |
| - let mut memo = FxHashMap::with_capacity_and_hasher(100000, Default::default()); |
72 |
| - blink_rec(&mut memo, *start_stone, times) |
73 |
| - }) |
74 |
| - .sum::<u64>(); |
| 49 | +pub fn part_one(input: &str) -> Option<u64> { |
| 50 | + Some(solve(input, 25)) |
| 51 | +} |
75 | 52 |
|
76 |
| - Some(count as u64) |
| 53 | +pub fn part_two(input: &str) -> Option<u64> { |
| 54 | + Some(solve(input, 75)) |
77 | 55 | }
|
78 | 56 |
|
79 | 57 | #[cfg(test)]
|
|
0 commit comments