@@ -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+
912impl 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