1use crate::util::parse::*;
19
20const WIDTH: usize = 16;
21const LENGTH: usize = 1 << WIDTH;
22
23pub fn parse(input: &str) -> Vec<i32> {
24 input.iter_signed().collect()
25}
26
27pub fn part1(input: &[i32]) -> usize {
29 let mut jump = input.to_vec();
30 let mut total = 0;
31 let mut index = 0;
32
33 while index < jump.len() {
34 let next = index.wrapping_add(jump[index] as usize);
35 jump[index] += 1;
36 total += 1;
37 index = next;
38 }
39
40 total
41}
42
43#[expect(clippy::needless_range_loop)]
44pub fn part2(input: &[i32]) -> usize {
45 let mut jump = input.to_vec();
46 let mut total = 0;
47 let mut index = 0;
48
49 let mut fine = 0;
50 let mut coarse = 0;
51 let mut compact = Vec::new();
52 let mut cache = vec![[(0_u16, 0_u8, 0_u8); LENGTH]; WIDTH];
53
54 for i in 0..WIDTH {
57 for j in 0..LENGTH {
58 let mut offset = i as u16;
59 let mut value = j as u16;
60 let mut steps = 0;
61
62 while offset < 16 {
63 value ^= 1 << offset;
64 steps += 1;
65 offset += 3 - ((value >> offset) & 1);
66 }
67
68 cache[i][j] = (value, steps, offset as u8 - i as u8);
69 }
70 }
71
72 while index < jump.len() {
73 if index < coarse {
74 let base = index / 16;
76 let offset = index % 16;
77 let value = compact[base] as usize;
78 let (next, steps, delta) = cache[offset][value];
79
80 compact[base] = next;
81 total += steps as usize;
82 index += delta as usize;
83 } else {
84 let next = index.wrapping_add(jump[index] as usize);
86 jump[index] += if jump[index] == 3 { -1 } else { 1 };
87 total += 1;
88
89 if jump[index] == 2 && index == fine {
92 fine += 1;
93 if fine.is_multiple_of(16) {
94 let value = (coarse..fine).rev().fold(0, |acc, i| (acc << 1) | (jump[i] & 1));
95 coarse = fine;
96 compact.push(value as u16);
97 }
98 }
99
100 index = next;
101 }
102 }
103
104 total
105}