Skip to content

Commit e40ae97

Browse files
committed
Simplify offset calculations
1 parent 931df84 commit e40ae97

File tree

7 files changed

+54
-55
lines changed

7 files changed

+54
-55
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
252252
| 15 | [Oxygen System](https://adventofcode.com/2019/day/15) | [Source](src/year2019/day15.rs) | 291 |
253253
| 16 | [Flawed Frequency Transmission](https://adventofcode.com/2019/day/16) | [Source](src/year2019/day16.rs) | 1956 |
254254
| 17 | [Set and Forget](https://adventofcode.com/2019/day/17) | [Source](src/year2019/day17.rs) | 338 |
255-
| 18 | [Many-Worlds Interpretation](https://adventofcode.com/2019/day/18) | [Source](src/year2019/day18.rs) | 1157 |
255+
| 18 | [Many-Worlds Interpretation](https://adventofcode.com/2019/day/18) | [Source](src/year2019/day18.rs) | 1039 |
256256
| 19 | [Tractor Beam](https://adventofcode.com/2019/day/19) | [Source](src/year2019/day19.rs) | 688 |
257257
| 20 | [Donut Maze](https://adventofcode.com/2019/day/20) | [Source](src/year2019/day20.rs) | 189 |
258258
| 21 | [Springdroid Adventure](https://adventofcode.com/2019/day/21) | [Source](src/year2019/day21.rs) | 1785 |
@@ -354,7 +354,7 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
354354
| 21 | [Scrambled Letters and Hash](https://adventofcode.com/2016/day/21) | [Source](src/year2016/day21.rs) | 10 |
355355
| 22 | [Grid Computing](https://adventofcode.com/2016/day/22) | [Source](src/year2016/day22.rs) | 28 |
356356
| 23 | [Safe Cracking](https://adventofcode.com/2016/day/23) | [Source](src/year2016/day23.rs) | 1 |
357-
| 24 | [Air Duct Spelunking](https://adventofcode.com/2016/day/24) | [Source](src/year2016/day24.rs) | 337 |
357+
| 24 | [Air Duct Spelunking](https://adventofcode.com/2016/day/24) | [Source](src/year2016/day24.rs) | 316 |
358358
| 25 | [Clock Signal](https://adventofcode.com/2016/day/25) | [Source](src/year2016/day25.rs) | 1 |
359359

360360
## 2015

src/year2016/day24.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ pub fn parse(input: &str) -> Input {
3030
let found: Vec<_> =
3131
grid.bytes.iter().enumerate().filter(|(_, b)| b.is_ascii_digit()).map(|(i, _)| i).collect();
3232

33+
let width = grid.width as usize;
3334
let stride = found.len();
3435
let mut distance = vec![0; stride * stride];
3536

3637
// BFS from each location. As a minor optimization we reuse `todo` and `visited`.
3738
let mut todo = VecDeque::new();
3839
let mut visited = vec![0; grid.bytes.len()];
39-
let orthogonal = [1, -1, grid.width, -grid.width].map(|i| i as usize);
4040

4141
for start in found {
4242
let from = grid.bytes[start].to_decimal() as usize;
@@ -50,12 +50,10 @@ pub fn parse(input: &str) -> Input {
5050
distance[stride * from + to] = steps;
5151
}
5252

53-
for offset in orthogonal {
54-
let next_index = index.wrapping_add(offset);
55-
56-
if grid.bytes[next_index] != b'#' && visited[next_index] != start {
57-
visited[next_index] = start;
58-
todo.push_back((next_index, steps + 1));
53+
for next in [index + 1, index - 1, index + width, index - width] {
54+
if grid.bytes[next] != b'#' && visited[next] != start {
55+
visited[next] = start;
56+
todo.push_back((next, steps + 1));
5957
}
6058
}
6159
}

src/year2019/day18.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ pub fn parse(input: &str) -> Grid<u8> {
8686
}
8787

8888
pub fn part1(input: &Grid<u8>) -> u32 {
89-
explore(input.width, &input.bytes)
89+
explore(input.width as usize, &input.bytes)
9090
}
9191

9292
pub fn part2(input: &Grid<u8>) -> u32 {
@@ -101,10 +101,10 @@ pub fn part2(input: &Grid<u8>) -> u32 {
101101
patch("###", 0);
102102
patch("@#@", 1);
103103

104-
explore(input.width, &modified)
104+
explore(input.width as usize, &modified)
105105
}
106106

107-
fn parse_maze(width: i32, bytes: &[u8]) -> Maze {
107+
fn parse_maze(width: usize, bytes: &[u8]) -> Maze {
108108
let mut initial = State::default();
109109
let mut found = Vec::new();
110110
let mut robots = 26;
@@ -125,7 +125,6 @@ fn parse_maze(width: i32, bytes: &[u8]) -> Maze {
125125
// Start a BFS from each key and robot's location stopping at the nearest neighbor.
126126
// As a minor optimization we re-use the same `todo` and `visited` between each search.
127127
let default = Door { distance: u32::MAX, needed: 0 };
128-
let orthogonal = [1, -1, width, -width].map(|i| i as usize);
129128

130129
let mut maze = [[default; 30]; 30];
131130
let mut visited = vec![usize::MAX; bytes.len()];
@@ -150,11 +149,10 @@ fn parse_maze(width: i32, bytes: &[u8]) -> Maze {
150149
continue;
151150
}
152151

153-
for delta in orthogonal {
154-
let next_index = index.wrapping_add(delta);
155-
if bytes[next_index] != b'#' && visited[next_index] != from {
156-
todo.push_back((next_index, distance + 1, needed));
157-
visited[next_index] = from;
152+
for next in [index + 1, index - 1, index + width, index - width] {
153+
if bytes[next] != b'#' && visited[next] != from {
154+
todo.push_back((next, distance + 1, needed));
155+
visited[next] = from;
158156
}
159157
}
160158
}
@@ -183,7 +181,7 @@ fn parse_maze(width: i32, bytes: &[u8]) -> Maze {
183181
Maze { initial, maze }
184182
}
185183

186-
fn explore(width: i32, bytes: &[u8]) -> u32 {
184+
fn explore(width: usize, bytes: &[u8]) -> u32 {
187185
let mut todo = MinHeap::with_capacity(5_000);
188186
let mut cache = FastMap::with_capacity(5_000);
189187

src/year2019/day20.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pub struct Maze {
4848
/// portal to build a list of distance pairs.
4949
pub fn parse(input: &str) -> Maze {
5050
let grid = Grid::parse(input);
51+
let width = grid.width as usize;
5152

5253
let mut tiles: Vec<_> =
5354
grid.bytes.iter().map(|&b| if b == b'.' { Tile::Open } else { Tile::Wall }).collect();
@@ -104,7 +105,6 @@ pub fn parse(input: &str) -> Maze {
104105
let mut portals = Vec::new();
105106
let mut todo = VecDeque::new();
106107
let mut visited = vec![0; tiles.len()];
107-
let orthogonal = [1, -1, grid.width, -grid.width].map(|i| i as usize);
108108

109109
for start in found {
110110
let mut edges = Vec::new();
@@ -113,8 +113,7 @@ pub fn parse(input: &str) -> Maze {
113113
while let Some((index, steps)) = todo.pop_front() {
114114
visited[index] = start;
115115

116-
for offset in orthogonal {
117-
let next_index = index.wrapping_add(offset);
116+
for next_index in [index + 1, index - 1, index + width, index - width] {
118117
let next_steps = steps + 1;
119118

120119
if visited[next_index] != start {

src/year2020/day11.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,9 @@ mod simd {
167167
}
168168

169169
// Common constants.
170-
let zero: Vector = Simd::splat(0);
171-
let one: Vector = Simd::splat(1);
172-
let limit: Vector = Simd::splat(limit);
170+
let zero = Simd::splat(0);
171+
let one = Simd::splat(1);
172+
let limit = Simd::splat(limit);
173173

174174
let mut current = grid.same_size_with(0);
175175
let mut next = grid.same_size_with(0);

src/year2020/day24.rs

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -37,25 +37,23 @@ pub fn parse(input: &str) -> FastSet<Hex> {
3737
b'e' => q += 1,
3838
b'w' => q -= 1,
3939
b'n' => {
40-
if b'e' == iter.next().unwrap() {
40+
r -= 1;
41+
if iter.next().unwrap() == b'e' {
4142
q += 1;
4243
}
43-
r -= 1;
4444
}
4545
b's' => {
46-
if b'e' != iter.next().unwrap() {
46+
r += 1;
47+
if iter.next().unwrap() == b'w' {
4748
q -= 1;
4849
}
49-
r += 1;
5050
}
5151
_ => unreachable!(),
5252
}
5353
}
5454

5555
let tile = Hex { q, r };
56-
if tiles.contains(&tile) {
57-
tiles.remove(&tile);
58-
} else {
56+
if !tiles.remove(&tile) {
5957
tiles.insert(tile);
6058
}
6159
}
@@ -80,7 +78,6 @@ pub fn part2(input: &FastSet<Hex>) -> usize {
8078
#[cfg(not(feature = "simd"))]
8179
mod scalar {
8280
use super::*;
83-
use std::array::from_fn;
8481

8582
pub(super) fn simulate(input: &FastSet<Hex>) -> usize {
8683
// Determine bounds
@@ -91,30 +88,32 @@ mod scalar {
9188

9289
// Create array with enough space to allow expansion for 100 generations.
9390
// 2 * (100 generations + 1 buffer) + Origin = 203 extra in each dimension
94-
let width = q2 - q1 + 203;
95-
let height = r2 - r1 + 203;
96-
let neighbors: [i32; 6] = [-1, 1, -width, width, 1 - width, width - 1];
97-
let neighbors: [usize; 6] = from_fn(|i| neighbors[i] as usize);
91+
let width = (q2 - q1 + 203) as usize;
92+
let height = (r2 - r1 + 203) as usize;
9893

94+
let mut state = vec![0_u8; width * height];
9995
let mut active = Vec::with_capacity(5_000);
10096
let mut candidates = Vec::with_capacity(5_000);
10197
let mut next_active = Vec::with_capacity(5_000);
10298

10399
// Create initial active state, offsetting tiles so that all indices are positive.
104100
for hex in input {
105-
let index = width * (hex.r - r1 + 101) + (hex.q - q1 + 101);
106-
active.push(index as usize);
101+
let index = width * (hex.r - r1 + 101) as usize + (hex.q - q1 + 101) as usize;
102+
active.push(index);
107103
}
108104

109105
for _ in 0..100 {
110-
let mut state: Vec<u8> = vec![0; (width * height) as usize];
106+
state.fill(0);
111107

112108
for &tile in &active {
113-
for &offset in &neighbors {
114-
// Earlier we converted the offsets from signed `i32` to unsigned `usize`. To
115-
// achieve subtraction for negative indices, we use a `wrapping_add` that performs
116-
// [two's complement](https://en.wikipedia.org/wiki/Two%27s_complement) arithmetic.
117-
let index = tile.wrapping_add(offset);
109+
for index in [
110+
tile + 1,
111+
tile - 1,
112+
tile + width,
113+
tile - width,
114+
tile + 1 - width,
115+
tile - 1 + width,
116+
] {
118117
state[index] += 1;
119118

120119
if state[index] == 2 {
@@ -177,9 +176,9 @@ mod simd {
177176
current[index] = 1;
178177
}
179178

180-
let zero: Vector = Simd::splat(0);
181-
let one: Vector = Simd::splat(1);
182-
let two: Vector = Simd::splat(2);
179+
let zero = Simd::splat(0);
180+
let one = Simd::splat(1);
181+
let two = Simd::splat(2);
183182

184183
for round in 0..100 {
185184
// The active state boundary expands by 1 horizontally and vertically each round.

src/year2021/day11.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99
1010
/// Pad the 10x10 grid by 1 on either side so that we can avoid boundary checks.
1111
type Input = [u8; 144];
12-
/// Offsets for each of the eight neighbors. The last four offsets will wrap around when
13-
/// added to `u8` to give a smaller index.
14-
const NEIGHBORS: [u8; 8] = [1, 11, 12, 13, 243, 244, 245, 255];
1512

1613
pub fn parse(input: &str) -> Input {
1714
let bytes: Vec<_> = input.lines().map(str::as_bytes).collect();
@@ -59,7 +56,7 @@ fn simulate(input: &Input, predicate: fn(usize, usize) -> bool) -> (usize, usize
5956
} else {
6057
grid[index] = 0;
6158
flashed[index] = true;
62-
todo.push(index as u8);
59+
todo.push(index);
6360
}
6461
}
6562
}
@@ -68,8 +65,16 @@ fn simulate(input: &Input, predicate: fn(usize, usize) -> bool) -> (usize, usize
6865
while let Some(index) = todo.pop() {
6966
flashes += 1;
7067

71-
for offset in NEIGHBORS {
72-
let next = index.wrapping_add(offset) as usize;
68+
for next in [
69+
index + 1,
70+
index + 11,
71+
index + 12,
72+
index + 13,
73+
index - 1,
74+
index - 11,
75+
index - 12,
76+
index - 13,
77+
] {
7378
if flashed[next] {
7479
continue;
7580
}
@@ -79,7 +84,7 @@ fn simulate(input: &Input, predicate: fn(usize, usize) -> bool) -> (usize, usize
7984
} else {
8085
grid[next] = 0;
8186
flashed[next] = true;
82-
todo.push(next as u8);
87+
todo.push(next);
8388
}
8489
}
8590
}

0 commit comments

Comments
 (0)