1use Direction::*;
6use implementation::U256;
7
8const HEIGHT: usize = 210;
11
12enum Direction {
13 North,
14 South,
15 West,
16 East,
17}
18
19#[derive(Clone, Copy)]
20pub struct Input {
21 grid: [U256; HEIGHT],
22 north: [U256; HEIGHT],
23 south: [U256; HEIGHT],
24 west: [U256; HEIGHT],
25 east: [U256; HEIGHT],
26}
27
28pub fn parse(input: &str) -> Input {
30 let offset = 70;
32 let raw: Vec<_> = input.lines().map(str::as_bytes).collect();
33 let default = [U256::default(); HEIGHT];
34 let mut grid = default;
35
36 for (y, row) in raw.iter().enumerate() {
37 for (x, col) in row.iter().enumerate() {
38 if *col == b'#' {
39 grid[offset + y].set_bit(offset + x);
40 }
41 }
42 }
43
44 Input { grid, north: default, south: default, west: default, east: default }
45}
46
47pub fn part1(input: &Input) -> usize {
48 let mut input = *input;
49 let mut order = [North, South, West, East];
50
51 for _ in 0..10 {
52 step(&mut input, &mut order);
53 }
54
55 let grid = input.grid;
57 let elves = grid.iter().flat_map(U256::as_array).map(u8::count_ones).sum::<u32>() as usize;
58
59 let min_y = grid.iter().position(U256::non_zero).unwrap();
61 let max_y = grid.iter().rposition(U256::non_zero).unwrap();
62
63 let array = grid.iter().fold(U256::default(), |acc, &n| acc.or(n)).as_array();
65 let left = array.iter().position(|&e| e != 0).unwrap();
66 let right = array.iter().rposition(|&e| e != 0).unwrap();
67
68 let min_x = 8 * left + array[left].leading_zeros() as usize;
69 let max_x = 8 * right + (7 - array[right].trailing_zeros()) as usize;
70
71 (max_x - min_x + 1) * (max_y - min_y + 1) - elves
73}
74
75pub fn part2(input: &Input) -> u32 {
76 let mut input = *input;
77 let mut order = [North, South, West, East];
78 let mut moved = true;
79 let mut count = 0;
80
81 while moved {
82 moved = step(&mut input, &mut order);
83 count += 1;
84 }
85
86 count
87}
88
89fn step(input: &mut Input, order: &mut [Direction]) -> bool {
90 let Input { grid, north, south, west, east } = input;
91 let start = grid.iter().position(U256::non_zero).unwrap() - 1;
93 let end = grid.iter().rposition(U256::non_zero).unwrap() + 2;
94
95 let mut moved = false;
96
97 let mut prev;
98 let mut cur = grid[0].shr().or(grid[0]).or(grid[0].shl()).not();
101 let mut next = grid[1].shr().or(grid[1]).or(grid[1].shl()).not();
102
103 for i in start..end {
104 prev = cur;
106 cur = next;
107 next = grid[i + 1].shr().or(grid[i + 1]).or(grid[i + 1].shl()).not();
108
109 let mut up = prev;
110 let mut down = next;
111 let vertical = grid[i - 1].or(grid[i]).or(grid[i + 1]).not();
113 let mut left = vertical.shr();
114 let mut right = vertical.shl();
115 let mut remaining = grid[i].and(up.and(down).and(left).and(right).not());
117
118 for direction in &*order {
120 match direction {
121 North => {
122 up = up.and(remaining);
123 remaining = remaining.and(up.not());
124 }
125 South => {
126 down = down.and(remaining);
127 remaining = remaining.and(down.not());
128 }
129 West => {
130 left = left.and(remaining);
131 remaining = remaining.and(left.not());
132 }
133 East => {
134 right = right.and(remaining);
135 remaining = remaining.and(right.not());
136 }
137 }
138 }
139
140 north[i - 1] = up;
142 south[i + 1] = down;
143 west[i] = left.shl();
144 east[i] = right.shr();
145 }
146
147 for i in start..end {
151 let up = north[i];
152 let down = south[i];
153 let left = west[i];
154 let right = east[i];
155 north[i] = north[i].and(down.not());
156 south[i] = south[i].and(up.not());
157 west[i] = west[i].and(right.not());
158 east[i] = east[i].and(left.not());
159 }
160
161 for i in start..end {
162 let same =
164 grid[i].and(north[i - 1].or(south[i + 1]).or(west[i].shr()).or(east[i].shl()).not());
165 let change = north[i].or(south[i]).or(west[i]).or(east[i]);
167 grid[i] = same.or(change);
168 moved |= change.non_zero();
169 }
170
171 order.rotate_left(1);
173 moved
174}
175
176#[cfg(not(feature = "simd"))]
177mod implementation {
178 #[derive(Clone, Copy, Default)]
180 pub(super) struct U256 {
181 left: u128,
182 right: u128,
183 }
184
185 impl U256 {
186 pub(super) fn set_bit(&mut self, offset: usize) {
187 if offset < 128 {
188 self.left |= 1 << (127 - offset);
189 } else {
190 self.right |= 1 << (255 - offset);
191 }
192 }
193
194 pub(super) fn as_array(&self) -> [u8; 32] {
195 let mut result = [0; 32];
196 result[..16].copy_from_slice(&self.left.to_be_bytes());
197 result[16..].copy_from_slice(&self.right.to_be_bytes());
198 result
199 }
200
201 pub(super) fn non_zero(&self) -> bool {
202 self.left != 0 || self.right != 0
203 }
204
205 pub(super) fn shl(self) -> U256 {
206 U256 { left: (self.left << 1) | (self.right >> 127), right: (self.right << 1) }
207 }
208
209 pub(super) fn shr(self) -> U256 {
210 U256 { left: (self.left >> 1), right: (self.left << 127) | (self.right >> 1) }
211 }
212
213 pub(super) fn and(self, rhs: U256) -> U256 {
214 U256 { left: self.left & rhs.left, right: self.right & rhs.right }
215 }
216
217 pub(super) fn or(self, rhs: U256) -> U256 {
218 U256 { left: self.left | rhs.left, right: self.right | rhs.right }
219 }
220
221 pub(super) fn not(self) -> U256 {
222 U256 { left: !self.left, right: !self.right }
223 }
224 }
225}
226
227#[cfg(feature = "simd")]
228mod implementation {
229 use std::simd::*;
230
231 #[derive(Clone, Copy, Default)]
232 pub(super) struct U256 {
233 v: Simd<u8, 32>,
234 }
235
236 impl U256 {
237 pub(super) fn set_bit(&mut self, offset: usize) {
238 self.v[offset / 8] |= 1 << (7 - offset % 8);
239 }
240
241 pub(super) fn as_array(&self) -> [u8; 32] {
242 self.v.to_array()
243 }
244
245 pub(super) fn non_zero(&self) -> bool {
246 self.v != Simd::splat(0)
247 }
248
249 pub(super) fn shl(self) -> U256 {
250 U256 { v: (self.v << 1) | (self.v.shift_elements_left::<1>(0) >> 7) }
251 }
252
253 pub(super) fn shr(self) -> U256 {
254 U256 { v: (self.v >> 1) | (self.v.shift_elements_right::<1>(0) << 7) }
255 }
256
257 pub(super) fn and(self, rhs: U256) -> U256 {
258 U256 { v: self.v & rhs.v }
259 }
260
261 pub(super) fn or(self, rhs: U256) -> U256 {
262 U256 { v: self.v | rhs.v }
263 }
264
265 pub(super) fn not(self) -> U256 {
266 U256 { v: !self.v }
267 }
268 }
269}