Skip to content

Commit b1558e0

Browse files
committed
Optimize 2017 day 5
Reduces runtime from ~37ms to ~25ms
1 parent 9d7b538 commit b1558e0

File tree

1 file changed

+43
-0
lines changed

1 file changed

+43
-0
lines changed

crates/year2017/src/day05.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ pub struct Day05 {
66
jumps: Vec<i32>,
77
}
88

9+
type Compressed = usize;
10+
const BITS: usize = Compressed::BITS as usize;
11+
912
impl Day05 {
1013
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
1114
Ok(Self {
@@ -35,11 +38,51 @@ impl Day05 {
3538
let mut steps = 0;
3639
let mut pc = 0;
3740

41+
// After each jump instruction is run enough times the offset oscillates back and forth
42+
// between 2 and 3. Once this happens, represent the jump as a single bit in a compressed
43+
// bit mask, which allows processing multiple jumps at once without each one requiring a
44+
// random memory read.
45+
let mut threes: Vec<Compressed> = vec![0; jumps.len().next_multiple_of(BITS) / BITS];
46+
// boundary represents the point where all prior jumps have stabilized on oscillating
47+
// between 2 and 3
48+
let mut boundary = 0;
49+
3850
while pc < jumps.len() {
3951
let offset = jumps[pc];
4052
jumps[pc] += if offset >= 3 { -1 } else { 1 };
53+
54+
if pc == boundary && (jumps[pc] == 2 || jumps[pc] == 3) {
55+
// Next jump after the boundary stabilized on 2/3
56+
boundary += 1;
57+
58+
let element_index = pc / BITS;
59+
let bit_index = pc % BITS;
60+
threes[element_index] |= ((jumps[pc] & 1) as Compressed) << bit_index;
61+
}
62+
4163
pc = pc.wrapping_add_signed(offset as isize);
4264
steps += 1;
65+
66+
while pc < boundary {
67+
// While inside the boundary loop over each compressed element and handle the jumps
68+
// in bulk
69+
let element_index = pc / BITS;
70+
let mut element = threes[element_index];
71+
72+
let bit_index = pc % BITS;
73+
let mut bit = 1 << bit_index;
74+
75+
let max = boundary.min((element_index + 1) * BITS);
76+
while pc < max {
77+
let offset = 2 + usize::from(element & bit != 0);
78+
element ^= bit;
79+
bit <<= offset;
80+
pc += offset;
81+
steps += 1;
82+
}
83+
84+
threes[element_index] = element;
85+
}
4386
}
4487

4588
steps

0 commit comments

Comments
 (0)