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 prev;
99 let mut cur = horizontal(grid[0]);
100 let mut next = horizontal(grid[1]);
101
102 for i in start..end {
103 prev = cur;
105 cur = next;
106 next = horizontal(grid[i + 1]);
107
108 let mut up = prev;
109 let mut down = next;
110 let vertical = grid[i - 1].or(grid[i]).or(grid[i + 1]).not();
112 let mut left = vertical.shr();
113 let mut right = vertical.shl();
114 let mut remaining = grid[i].and(up.and(down).and(left).and(right).not());
116
117 for direction in &*order {
119 match direction {
120 North => {
121 up = up.and(remaining);
122 remaining = remaining.and(up.not());
123 }
124 South => {
125 down = down.and(remaining);
126 remaining = remaining.and(down.not());
127 }
128 West => {
129 left = left.and(remaining);
130 remaining = remaining.and(left.not());
131 }
132 East => {
133 right = right.and(remaining);
134 remaining = remaining.and(right.not());
135 }
136 }
137 }
138
139 north[i - 1] = up;
141 south[i + 1] = down;
142 west[i] = left.shl();
143 east[i] = right.shr();
144 }
145
146 for i in start..end {
150 let (up, down, left, right) = (north[i], south[i], west[i], east[i]);
151 north[i] = up.and(down.not());
152 south[i] = down.and(up.not());
153 west[i] = left.and(right.not());
154 east[i] = right.and(left.not());
155 }
156
157 for i in start..end {
158 let same =
160 grid[i].and(north[i - 1].or(south[i + 1]).or(west[i].shr()).or(east[i].shl()).not());
161 let change = north[i].or(south[i]).or(west[i]).or(east[i]);
163 grid[i] = same.or(change);
164 moved |= change.non_zero();
165 }
166
167 order.rotate_left(1);
169 moved
170}
171
172#[cfg(not(feature = "simd"))]
173mod implementation {
174 #[derive(Clone, Copy, Default)]
176 pub(super) struct U256 {
177 left: u128,
178 right: u128,
179 }
180
181 impl U256 {
182 pub(super) fn set_bit(&mut self, offset: usize) {
183 if offset < 128 {
184 self.left |= 1 << (127 - offset);
185 } else {
186 self.right |= 1 << (255 - offset);
187 }
188 }
189
190 pub(super) fn as_array(&self) -> [u8; 32] {
191 let mut result = [0; 32];
192 result[..16].copy_from_slice(&self.left.to_be_bytes());
193 result[16..].copy_from_slice(&self.right.to_be_bytes());
194 result
195 }
196
197 pub(super) fn non_zero(&self) -> bool {
198 self.left != 0 || self.right != 0
199 }
200
201 pub(super) fn shl(self) -> U256 {
202 U256 { left: (self.left << 1) | (self.right >> 127), right: (self.right << 1) }
203 }
204
205 pub(super) fn shr(self) -> U256 {
206 U256 { left: (self.left >> 1), right: (self.left << 127) | (self.right >> 1) }
207 }
208
209 pub(super) fn and(self, rhs: U256) -> U256 {
210 U256 { left: self.left & rhs.left, right: self.right & rhs.right }
211 }
212
213 pub(super) fn or(self, rhs: U256) -> U256 {
214 U256 { left: self.left | rhs.left, right: self.right | rhs.right }
215 }
216
217 pub(super) fn not(self) -> U256 {
218 U256 { left: !self.left, right: !self.right }
219 }
220 }
221}
222
223#[cfg(feature = "simd")]
224mod implementation {
225 use std::simd::prelude::*;
226
227 #[derive(Clone, Copy, Default)]
228 pub(super) struct U256 {
229 v: Simd<u8, 32>,
230 }
231
232 impl U256 {
233 pub(super) fn set_bit(&mut self, offset: usize) {
234 self.v[offset / 8] |= 1 << (7 - offset % 8);
235 }
236
237 pub(super) fn as_array(&self) -> [u8; 32] {
238 self.v.to_array()
239 }
240
241 pub(super) fn non_zero(&self) -> bool {
242 self.v != Simd::splat(0)
243 }
244
245 pub(super) fn shl(self) -> Self {
246 Self { v: (self.v << 1) | (self.v.shift_elements_left::<1>(0) >> 7) }
247 }
248
249 pub(super) fn shr(self) -> Self {
250 Self { v: (self.v >> 1) | (self.v.shift_elements_right::<1>(0) << 7) }
251 }
252
253 pub(super) fn and(self, rhs: Self) -> Self {
254 Self { v: self.v & rhs.v }
255 }
256
257 pub(super) fn or(self, rhs: Self) -> Self {
258 Self { v: self.v | rhs.v }
259 }
260
261 pub(super) fn not(self) -> Self {
262 Self { v: !self.v }
263 }
264 }
265}