1
1
advent_of_code:: solution!( 21 ) ;
2
2
3
- use std :: collections :: HashSet ;
3
+ use advent_of_code :: util :: bignumbers :: U1024 ;
4
4
5
- #[ derive( Clone , Copy , PartialEq , Eq , Hash ) ]
6
- struct Location {
7
- x : usize ,
8
- y : usize ,
9
- }
5
+ use std:: collections:: HashSet ;
10
6
11
7
struct Data {
12
- rock_locations : HashSet < Location > ,
8
+ rock_locations : HashSet < ( usize , usize ) > ,
13
9
len_x : usize ,
14
10
len_y : usize ,
15
11
}
@@ -23,7 +19,7 @@ fn parse_data(input: &str) -> Data {
23
19
for ( y, line) in input. lines ( ) . enumerate ( ) {
24
20
for ( x, v) in line. chars ( ) . enumerate ( ) {
25
21
if v == '#' {
26
- rock_locations. insert ( Location { x, y } ) ;
22
+ rock_locations. insert ( ( x, y) ) ;
27
23
}
28
24
}
29
25
}
@@ -35,78 +31,55 @@ fn parse_data(input: &str) -> Data {
35
31
}
36
32
}
37
33
38
- // def do_magic(my_positions_bits):
39
- // new_position_bits = [x for x in my_positions_bits]
40
- // for y in range(1, len_y - 1):
41
- // left = my_positions_bits[y] << 1
42
- // right = my_positions_bits[y] >> 1
43
- // up = my_positions_bits[y-1]
44
- // down = my_positions_bits[y+1]
34
+ fn run_step ( my_positions_bits : & [ U1024 ] , rocks_bits : & [ U1024 ] ) -> Vec < U1024 > {
35
+ let mut new_positions_bits = my_positions_bits. iter ( ) . copied ( ) . collect :: < Vec < _ > > ( ) ;
45
36
46
- // new_position_bits[y] = (new_position_bits[y] | left | right | up | down) & ~my_positions_bits[y] & ~rocks_bits[y]
37
+ for y in 1 ..my_positions_bits. len ( ) - 1 {
38
+ let left = my_positions_bits[ y] << 1 ;
39
+ let right = my_positions_bits[ y] >> 1 ;
40
+ let up = my_positions_bits[ y - 1 ] ;
41
+ let down = my_positions_bits[ y + 1 ] ;
47
42
48
- // return new_position_bits
49
-
50
- fn run_step (
51
- my_locations : HashSet < Location > ,
52
- rock_locations : & HashSet < Location > ,
53
- len_x : usize ,
54
- len_y : usize ,
55
- ) -> HashSet < Location > {
56
- let mut new_locations = HashSet :: with_capacity ( my_locations. len ( ) * 4 ) ;
57
-
58
- for loc in my_locations. into_iter ( ) {
59
- let left = Location {
60
- x : loc. x . wrapping_sub ( 1 ) ,
61
- y : loc. y ,
62
- } ;
63
-
64
- let right = Location {
65
- x : loc. x + 1 ,
66
- y : loc. y ,
67
- } ;
68
-
69
- let up = Location {
70
- x : loc. x ,
71
- y : loc. y . wrapping_sub ( 1 ) ,
72
- } ;
73
-
74
- let down = Location {
75
- x : loc. x ,
76
- y : loc. y + 1 ,
77
- } ;
78
-
79
- new_locations. extend ( [ left, right, up, down] . iter ( ) . filter ( |l| {
80
- !rock_locations. contains ( & Location {
81
- x : l. x % len_x,
82
- y : l. y % len_y,
83
- } )
84
- } ) ) ;
43
+ new_positions_bits[ y] = ( new_positions_bits[ y] | left | right | up | down)
44
+ & !my_positions_bits[ y]
45
+ & !rocks_bits[ y]
85
46
}
86
47
87
- new_locations
48
+ new_positions_bits
88
49
}
89
50
90
- pub fn part_one ( input : & str ) -> Option < u32 > {
51
+ pub fn part_one ( input : & str ) -> Option < u64 > {
91
52
let Data {
92
53
rock_locations,
93
54
len_x,
94
55
len_y,
95
56
} = parse_data ( input) ;
96
57
97
- let start_location = Location {
98
- x : len_x / 2 ,
99
- y : len_y / 2 ,
100
- } ;
58
+ let mut rocks_bits = vec ! [ !U1024 :: ZERO ] ;
59
+ for y in 0 ..len_y {
60
+ let mut rocks_bits_line = U1024 :: ZERO ;
61
+ for x in 0 ..len_x {
62
+ if rock_locations. contains ( & ( x, y) ) {
63
+ rocks_bits_line |= U1024 :: ONE << ( x + 1 )
64
+ }
65
+ rocks_bits_line |= U1024 :: ONE ;
66
+ rocks_bits_line |= U1024 :: ONE << ( len_x + 1 )
67
+ }
68
+ rocks_bits. push ( rocks_bits_line) ;
69
+ }
70
+ rocks_bits. push ( !U1024 :: ZERO ) ;
101
71
102
- let my_locations = ( 0 ..64 ) . fold ( HashSet :: from ( [ start_location] ) , |acc, _| {
103
- run_step ( acc, & rock_locations, len_x, len_y)
104
- . into_iter ( )
105
- . filter ( |l| ( 0 ..len_x) . contains ( & l. x ) && ( 0 ..len_y) . contains ( & l. y ) )
106
- . collect ( )
107
- } ) ;
72
+ let mut my_positions_bits = ( 0 ..rocks_bits. len ( ) )
73
+ . map ( |_| U1024 :: ZERO )
74
+ . collect :: < Vec < _ > > ( ) ;
75
+ my_positions_bits[ ( len_y + 2 ) / 2 ] |= U1024 :: ONE << ( ( len_x + 2 ) / 2 ) ;
108
76
109
- let result = my_locations. len ( ) as u32 ;
77
+ let my_positions_bits = ( 0 ..64 ) . fold ( my_positions_bits, |acc, _| run_step ( & acc, & rocks_bits) ) ;
78
+
79
+ let result = my_positions_bits
80
+ . iter ( )
81
+ . map ( |x| x. count_ones ( ) as u64 )
82
+ . sum ( ) ;
110
83
111
84
Some ( result)
112
85
}
@@ -118,26 +91,55 @@ pub fn part_two(input: &str) -> Option<u64> {
118
91
len_y,
119
92
} = parse_data ( input) ;
120
93
121
- let start_location = Location {
122
- x : len_x * 2 + len_x / 2 ,
123
- y : len_y * 2 + len_y / 2 ,
124
- } ;
94
+ let mut rocks_bits = vec ! [ ] ;
95
+ for y in 0 ..len_y {
96
+ let mut rocks_bits_line = U1024 :: ZERO ;
97
+ for x in 0 ..len_x {
98
+ if rock_locations. contains ( & ( x, y) ) {
99
+ rocks_bits_line |= U1024 :: ONE << x
100
+ }
101
+ }
102
+ rocks_bits. push ( rocks_bits_line) ;
103
+ }
104
+
105
+ const GRID_MULTIPLIER : usize = 7 ;
106
+
107
+ let original_rocks_bits = rocks_bits;
108
+ let mut rocks_bits = Vec :: with_capacity ( original_rocks_bits. len ( ) * GRID_MULTIPLIER ) ;
109
+ for _ in 0 ..GRID_MULTIPLIER {
110
+ rocks_bits. extend ( original_rocks_bits. iter ( ) . copied ( ) ) ;
111
+ }
112
+
113
+ for l_x_m in 1 ..GRID_MULTIPLIER {
114
+ for r in rocks_bits. iter_mut ( ) {
115
+ * r |= * r << ( l_x_m * len_x) ;
116
+ }
117
+ }
118
+
119
+ let mut my_positions_bits = ( 0 ..rocks_bits. len ( ) )
120
+ . map ( |_| U1024 :: ZERO )
121
+ . collect :: < Vec < _ > > ( ) ;
122
+ my_positions_bits[ len_y * GRID_MULTIPLIER / 2 ] |= U1024 :: ONE << ( len_x * GRID_MULTIPLIER / 2 ) ;
125
123
126
124
let mut results = vec ! [ ] ;
127
- let mut my_locations = HashSet :: from ( [ start_location] ) ;
128
125
129
- let magic_number_1 = len_x / 2 ;
130
- let magic_number_2 = magic_number_1 + len_x;
131
- let magic_number_3 = magic_number_2 + len_x;
126
+ let magic_number_1 = len_x as i64 / 2 ;
127
+ let magic_number_2 = magic_number_1 + len_x as i64 ;
128
+ let magic_number_3 = magic_number_2 + len_x as i64 ;
132
129
133
130
let mut i = 0 ;
134
131
while results. len ( ) < 3 {
135
- my_locations = run_step ( my_locations , & rock_locations , len_x , len_y ) ;
132
+ my_positions_bits = run_step ( & my_positions_bits , & rocks_bits ) ;
136
133
137
134
i += 1 ;
138
135
139
136
if i == magic_number_1 || i == magic_number_2 || i == magic_number_3 {
140
- results. push ( ( i as i64 , my_locations. len ( ) as i64 ) ) ;
137
+ let i_result = my_positions_bits
138
+ . iter ( )
139
+ . map ( |x| x. count_ones ( ) as i64 )
140
+ . sum :: < i64 > ( ) ;
141
+
142
+ results. push ( ( i, i_result) ) ;
141
143
}
142
144
}
143
145
0 commit comments