Skip to content

Commit 8d90441

Browse files
committed
More efficient looping and reduced caching of only common values
1 parent 4de5f33 commit 8d90441

File tree

2 files changed

+40
-33
lines changed

2 files changed

+40
-33
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Advent of Code [![checks-badge]][checks-link] [![docs-badge]][docs-link]
22

33
Blazing fast Rust solutions for every [Advent of Code] puzzle from 2015 to 2024, taking
4-
**497 milliseconds** to solve all 500 stars. Each solution is carefully optimized for performance
4+
**493 milliseconds** to solve all 500 stars. Each solution is carefully optimized for performance
55
while ensuring the code remains concise, readable, and idiomatic.
66

77
## Features
@@ -67,7 +67,7 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
6767

6868
| Year | [2015](#2015) | [2016](#2016) | [2017](#2017) | [2018](#2018) | [2019](#2019) | [2020](#2020) | [2021](#2021) | [2022](#2022) | [2023](#2023) | [2024](#2024) |
6969
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
70-
| Benchmark (ms) | 15 | 109 | 82 | 35 | 14 | 220 | 8 | 5 | 5 | 4 |
70+
| Benchmark (ms) | 15 | 109 | 78 | 35 | 14 | 220 | 8 | 5 | 5 | 4 |
7171

7272
## 2024
7373

@@ -303,7 +303,7 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
303303
| 2 | [Corruption Checksum](https://adventofcode.com/2017/day/2) | [Source](src/year2017/day02.rs) | 2 |
304304
| 3 | [Spiral Memory](https://adventofcode.com/2017/day/3) | [Source](src/year2017/day03.rs) | 2 |
305305
| 4 | [High-Entropy Passphrases](https://adventofcode.com/2017/day/4) | [Source](src/year2017/day04.rs) | 86 |
306-
| 5 | [A Maze of Twisty Trampolines, All Alike](https://adventofcode.com/2017/day/5) | [Source](src/year2017/day05.rs) | 22000 |
306+
| 5 | [A Maze of Twisty Trampolines, All Alike](https://adventofcode.com/2017/day/5) | [Source](src/year2017/day05.rs) | 18000 |
307307
| 6 | [Memory Reallocation](https://adventofcode.com/2017/day/6) | [Source](src/year2017/day06.rs) | 81 |
308308
| 7 | [Recursive Circus](https://adventofcode.com/2017/day/7) | [Source](src/year2017/day07.rs) | 93 |
309309
| 8 | [I Heard You Like Registers](https://adventofcode.com/2017/day/8) | [Source](src/year2017/day08.rs) | 47 |

src/year2017/day05.rs

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616
//! We then precompute all possible combination for blocks of size 16, using this to accelerate
1717
//! part two.
1818
use crate::util::parse::*;
19-
20-
const WIDTH: usize = 16;
21-
const LENGTH: usize = 1 << WIDTH;
19+
use std::array::from_fn;
2220

2321
pub fn parse(input: &str) -> Vec<i32> {
2422
input.iter_signed().collect()
@@ -49,37 +47,32 @@ pub fn part2(input: &[i32]) -> usize {
4947
let mut fine = 0;
5048
let mut coarse = 0;
5149
let mut compact = Vec::new();
52-
let mut cache = vec![[(0_u16, 0_u8, 0_u8); LENGTH]; WIDTH];
53-
54-
// Precompute all possible combinations. For each binary starting number we can start at any
55-
// offset from 0..16.
56-
for i in 0..WIDTH {
57-
for j in 0..LENGTH {
58-
let mut offset = i as u16;
59-
let mut value = j as u16;
60-
let mut steps = 0;
61-
62-
while offset < 16 {
63-
value ^= 1 << offset;
64-
steps += 1;
65-
offset += 3 - ((value >> offset) & 1);
66-
}
6750

68-
cache[i][j] = (value, steps, offset as u8 - i as u8);
69-
}
70-
}
51+
// Precompute all possible combinations for each binary starting number from 0 to 2^16,
52+
// starting at any offset from 0..2.
53+
let cache: Vec<[_; 0x10000]> =
54+
(0..3).map(|offset| from_fn(|value| compute_block(value, offset))).collect();
7155

7256
while index < jump.len() {
7357
if index < coarse {
58+
if index % 16 >= 3 {
59+
let j = index / 16;
60+
let (next, steps, delta) = compute_block(compact[j], index % 16);
61+
62+
compact[j] = next as usize;
63+
total += steps as usize;
64+
index += delta as usize;
65+
}
66+
7467
// Index lies within precomputed blocks.
75-
let base = index / 16;
76-
let offset = index % 16;
77-
let value = compact[base] as usize;
78-
let (next, steps, delta) = cache[offset][value];
79-
80-
compact[base] = next;
81-
total += steps as usize;
82-
index += delta as usize;
68+
for j in (index / 16)..(coarse / 16) {
69+
let value = compact[j];
70+
let (next, steps, delta) = cache[index % 16][value];
71+
72+
compact[j] = next as usize;
73+
total += steps as usize;
74+
index += delta as usize;
75+
}
8376
} else {
8477
// Fall back to part one approach.
8578
let next = index.wrapping_add(jump[index] as usize);
@@ -93,7 +86,7 @@ pub fn part2(input: &[i32]) -> usize {
9386
if fine.is_multiple_of(16) {
9487
let value = (coarse..fine).rev().fold(0, |acc, i| (acc << 1) | (jump[i] & 1));
9588
coarse = fine;
96-
compact.push(value as u16);
89+
compact.push(value as usize);
9790
}
9891
}
9992

@@ -103,3 +96,17 @@ pub fn part2(input: &[i32]) -> usize {
10396

10497
total
10598
}
99+
100+
#[inline]
101+
fn compute_block(mut value: usize, mut offset: usize) -> (u16, u8, u8) {
102+
let start = offset;
103+
let mut steps = 0;
104+
105+
while offset < 16 {
106+
value ^= 1 << offset;
107+
steps += 1;
108+
offset += 3 - ((value >> offset) & 1);
109+
}
110+
111+
(value as u16, steps, (offset - start) as u8)
112+
}

0 commit comments

Comments
 (0)