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