Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 94e4277

Browse files
Year 2015 speed and code quality improvements
1 parent c8df551 commit 94e4277

File tree

18 files changed

+244
-253
lines changed

18 files changed

+244
-253
lines changed

‎README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -370,14 +370,14 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
370370
| 5 | [Doesn't He Have Intern-Elves For This?](https://adventofcode.com/2015/day/5) | [Source](src/year2015/day05.rs) | 38 |
371371
| 6 | [Probably a Fire Hazard](https://adventofcode.com/2015/day/6) | [Source](src/year2015/day06.rs) | 6572 |
372372
| 7 | [Some Assembly Required](https://adventofcode.com/2015/day/7) | [Source](src/year2015/day07.rs) | 27 |
373-
| 8 | [Matchsticks](https://adventofcode.com/2015/day/8) | [Source](src/year2015/day08.rs) | 12 |
373+
| 8 | [Matchsticks](https://adventofcode.com/2015/day/8) | [Source](src/year2015/day08.rs) | 5 |
374374
| 9 | [All in a Single Night](https://adventofcode.com/2015/day/9) | [Source](src/year2015/day09.rs) | 34 |
375-
| 10 | [Elves Look, Elves Say](https://adventofcode.com/2015/day/10) | [Source](src/year2015/day10.rs) | 15 |
375+
| 10 | [Elves Look, Elves Say](https://adventofcode.com/2015/day/10) | [Source](src/year2015/day10.rs) | 17 |
376376
| 11 | [Corporate Policy](https://adventofcode.com/2015/day/11) | [Source](src/year2015/day11.rs) | 1 |
377-
| 12 | [JSAbacusFramework.io](https://adventofcode.com/2015/day/12) | [Source](src/year2015/day12.rs) | 83 |
377+
| 12 | [JSAbacusFramework.io](https://adventofcode.com/2015/day/12) | [Source](src/year2015/day12.rs) | 71 |
378378
| 13 | [Knights of the Dinner Table](https://adventofcode.com/2015/day/13) | [Source](src/year2015/day13.rs) | 37 |
379-
| 14 | [Reindeer Olympics](https://adventofcode.com/2015/day/14) | [Source](src/year2015/day14.rs) | 28 |
380-
| 15 | [Science for Hungry People](https://adventofcode.com/2015/day/15) | [Source](src/year2015/day15.rs) | 53 |
379+
| 14 | [Reindeer Olympics](https://adventofcode.com/2015/day/14) | [Source](src/year2015/day14.rs) | 24 |
380+
| 15 | [Science for Hungry People](https://adventofcode.com/2015/day/15) | [Source](src/year2015/day15.rs) | 43 |
381381
| 16 | [Aunt Sue](https://adventofcode.com/2015/day/16) | [Source](src/year2015/day16.rs) | 20 |
382382
| 17 | [No Such Thing as Too Much](https://adventofcode.com/2015/day/17) | [Source](src/year2015/day17.rs) | 45 |
383383
| 18 | [Like a GIF For Your Yard](https://adventofcode.com/2015/day/18) | [Source](src/year2015/day18.rs) | 154 |
@@ -386,7 +386,7 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
386386
| 21 | [RPG Simulator 20XX](https://adventofcode.com/2015/day/21) | [Source](src/year2015/day21.rs) | 2 |
387387
| 22 | [Wizard Simulator 20XX](https://adventofcode.com/2015/day/22) | [Source](src/year2015/day22.rs) | 235 |
388388
| 23 | [Opening the Turing Lock](https://adventofcode.com/2015/day/23) | [Source](src/year2015/day23.rs) | 6 |
389-
| 24 | [It Hangs in the Balance](https://adventofcode.com/2015/day/24) | [Source](src/year2015/day24.rs) | 380 |
389+
| 24 | [It Hangs in the Balance](https://adventofcode.com/2015/day/24) | [Source](src/year2015/day24.rs) | 237 |
390390
| 25 | [Let It Snow](https://adventofcode.com/2015/day/25) | [Source](src/year2015/day25.rs) | 1 |
391391

392392
[checks-badge]: https://img.shields.io/github/actions/workflow/status/maneatingape/advent-of-code-rust/checks.yml?label=checks

‎src/year2015/day01.rs

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,9 @@
11
//! # Not Quite Lisp
22
//!
33
//! The input is first converted into bytes. This is safe as it contains only ASCII characters.
4-
//! Then each parenthesis is parsed into either +1 or -1, treating the trailing newline
5-
//! as a special case of 0.
4+
//! Then each parenthesis is parsed into either +1 or -1.
65
pub fn parse(input: &str) -> Vec<i32> {
7-
fn helper(b: u8) -> i32 {
8-
match b {
9-
b'(' => 1,
10-
b')' => -1,
11-
_ => 0,
12-
}
13-
}
14-
input.bytes().map(helper).collect()
6+
input.trim().bytes().map(|b| if b == b'(' { 1 } else { -1 }).collect()
157
}
168

179
pub fn part1(input: &[i32]) -> i32 {
@@ -20,13 +12,12 @@ pub fn part1(input: &[i32]) -> i32 {
2012

2113
pub fn part2(input: &[i32]) -> usize {
2214
let mut floor = 0;
23-
24-
for (i, x) in input.iter().enumerate() {
25-
floor += x;
26-
if floor < 0 {
27-
return i + 1;
28-
}
29-
}
30-
31-
unreachable!()
15+
input
16+
.iter()
17+
.position(|&b| {
18+
floor += b;
19+
floor < 0
20+
})
21+
.map(|i| i + 1)
22+
.unwrap()
3223
}

‎src/year2015/day02.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
use crate::util::iter::*;
1212
use crate::util::parse::*;
1313

14-
type Gift = [u32; 3];
14+
type Input = Vec<[u32; 3]>;
1515

16-
pub fn parse(input: &str) -> Vec<Gift> {
16+
pub fn parse(input: &str) -> Input {
1717
input
1818
.iter_unsigned()
1919
.chunk::<3>()
@@ -25,10 +25,10 @@ pub fn parse(input: &str) -> Vec<Gift> {
2525
.collect()
2626
}
2727

28-
pub fn part1(input: &[Gift]) -> u32 {
28+
pub fn part1(input: &Input) -> u32 {
2929
input.iter().map(|[l, w, h]| 2 * (l * w + w * h + h * l) + l * w).sum()
3030
}
3131

32-
pub fn part2(input: &[Gift]) -> u32 {
32+
pub fn part2(input: &Input) -> u32 {
3333
input.iter().map(|[l, w, h]| 2 * (l + w) + (l * w * h)).sum()
3434
}

‎src/year2015/day03.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,16 @@ pub fn part2(input: &[Point]) -> usize {
2424
fn deliver(input: &[Point], predicate: fn(usize) -> bool) -> usize {
2525
let mut santa = ORIGIN;
2626
let mut robot = ORIGIN;
27-
let mut set = FastSet::with_capacity(10_000);
27+
28+
let mut set = FastSet::with_capacity(input.len());
2829
set.insert(ORIGIN);
2930

30-
for (index, point) in input.iter().enumerate() {
31+
for (index, &point) in input.iter().enumerate() {
3132
if predicate(index) {
32-
santa += *point;
33+
santa += point;
3334
set.insert(santa);
3435
} else {
35-
robot += *point;
36+
robot += point;
3637
set.insert(robot);
3738
}
3839
}

‎src/year2015/day05.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,30 @@ pub fn parse(input: &str) -> Vec<&[u8]> {
2929
}
3030

3131
pub fn part1(input: &[&[u8]]) -> usize {
32+
// Bitmask for vowels (a, e, i, o, u)
33+
const VOWEL_MASK: u32 = 0x0104111;
34+
// Bitmask for forbidden pairs
35+
const FORBIDDEN_MASK: u32 = 0x101000a;
36+
3237
let nice = |line: &&&[u8]| {
3338
let mut vowels = 0;
3439
let mut pairs = 0;
3540
let mut previous = 0;
3641

37-
for c in line.iter() {
42+
for &c in line.iter() {
3843
let current = 1 << (c - b'a');
39-
if 0x101000a & current & (previous << 1) != 0 {
44+
45+
if FORBIDDEN_MASK & current & (previous << 1) != 0 {
4046
return false;
4147
}
42-
if 0x0104111 & current != 0 {
48+
if VOWEL_MASK & current != 0 {
4349
vowels += 1;
4450
}
4551
if previous == current {
4652
pairs += 1;
47-
} else {
48-
previous = current;
4953
}
54+
55+
previous = current;
5056
}
5157

5258
vowels >= 3 && pairs >= 1
@@ -73,8 +79,10 @@ pub fn part2(input: &[&[u8]]) -> usize {
7379
let delta = position - pairs[index];
7480

7581
if delta > offset {
82+
// This is the first time we've seen the pair for this string.
7683
pairs[index] = position;
7784
} else if delta > 1 {
85+
// No overlapping means that the distance must be at least two.
7886
two_pair = true;
7987
}
8088
if first == third {

‎src/year2015/day08.rs

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,53 @@
11
//! # Matchsticks
22
//!
33
//! While [regular expressions](https://en.wikipedia.org/wiki/Regular_expression) may feel like a
4-
//! natural choice, it's much faster and easier to simply treat the input as a stream of raw
5-
//! ASCII `u8` bytes including newlines.
4+
//! natural choice, it's much faster and easier to simply treat the input as a single stream of raw
5+
//! ASCII `u8` bytes without splitting line by line.
66
//!
7-
//! For part one we run a small state machine using [`fold`] to keep track of the current and
8-
//! previous characters. If we encounter a hexadecimal escape then four characters become one so the
9-
//! difference increases by three. The sequences `\\` and `\"` both increase the difference by one.
10-
//! Each newline increases the difference by two since every line is enclosed with two quotes.
7+
//! For part one we skip over the first quote of each line. The last quote on each line increases
8+
//! the difference by two since every line is enclosed with two quotes. If we encounter a
9+
//! hexadecimal escape then four characters become one so the difference increases by three.
10+
//! The sequences `\\` and `\"` both increase the difference by one.
1111
//!
12-
//! Part two is even more straightforward with no need for statekeeping. Quotes and backslashes
13-
//! need to be escaped so increase the difference by one. As before each newline increases by the
14-
//! difference by two.
15-
//!
16-
//! [`fold`]: Iterator::fold
17-
const NEWLINE: u8 = 10;
18-
const QUOTE: u8 = 34;
19-
const SLASH: u8 = 92;
20-
const ESCAPE: u8 = 120;
12+
//! Part two is even more straightforward. Quotes and backslashes need to be escaped so increase
13+
//! the difference by one. Each newline increases by the difference by two.
14+
const NEWLINE: u8 = b'\n';
15+
const QUOTE: u8 = b'\"';
16+
const SLASH: u8 = b'\\';
17+
const ESCAPE: u8 = b'x';
2118

22-
pub fn parse(input: &str) -> &str {
23-
input
19+
pub fn parse(input: &str) -> &[u8] {
20+
input.as_bytes()
2421
}
2522

26-
pub fn part1(input: &str) -> u32 {
27-
let (_, result) = input.bytes().fold((false, 0), |(flag, count), b| match (flag, b) {
28-
(true, ESCAPE) => (false, count + 3),
29-
(true, _) => (false, count + 1),
30-
(false, SLASH) => (true, count),
31-
(false, NEWLINE) => (false, count + 2),
32-
_ => (false, count),
33-
});
23+
pub fn part1(input: &[u8]) -> usize {
24+
// Skip very first quote to prevent double counting.
25+
let mut index = 1;
26+
let mut result = 0;
27+
28+
while index < input.len() {
29+
let skip = match input[index] {
30+
SLASH => match input[index + 1] {
31+
ESCAPE => 4,
32+
_ => 2,
33+
},
34+
QUOTE => 3,
35+
_ => 1,
36+
};
37+
result += skip - 1;
38+
index += skip;
39+
}
40+
3441
result
3542
}
3643

37-
pub fn part2(input: &str) -> u32 {
44+
pub fn part2(input: &[u8]) -> u32 {
3845
input
39-
.bytes()
40-
.map(|b| match b {
46+
.iter()
47+
.map(|&b| match b {
48+
// Escape special characters.
4149
QUOTE | SLASH => 1,
50+
// Each line needs two enclosing quotes.
4251
NEWLINE => 2,
4352
_ => 0,
4453
})

‎src/year2015/day09.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,11 @@ pub fn parse(input: &str) -> Result {
6565
local_max = local_max.max(distance);
6666
};
6767

68+
// First trip.
6869
trip(0, slice[0]);
70+
// Last trip.
6971
trip(0, slice[slice.len() - 1]);
70-
72+
// Intermediate trips.
7173
for i in 1..slice.len() {
7274
trip(slice[i], slice[i - 1]);
7375
}

‎src/year2015/day10.rs

Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
//!
1313
//! Computing the result is simply multiplying the number of each element by its length. There are
1414
//! 92 elements total so we can use a fixed size array to store the decay chain information.
15+
//!
16+
//! It would be possible (but less fun) to precompute all possible 92 answers into a
17+
//! look up table.
1518
use crate::util::hash::*;
1619

1720
const ELEMENTS: &str = "\
@@ -113,34 +116,34 @@ type Result = (usize, usize);
113116
pub fn parse(input: &str) -> Result {
114117
let elements: Vec<Vec<_>> =
115118
ELEMENTS.lines().map(|line| line.split_ascii_whitespace().collect()).collect();
116-
let mut indices = FastMap::with_capacity(92);
119+
let mut indices = FastMap::with_capacity(92*2);
117120

121+
// Map both sequence and element name to indices.
118122
for (i, tokens) in elements.iter().enumerate() {
123+
indices.insert(tokens[0], i);
119124
indices.insert(tokens[2], i);
120125
}
121126

122-
let mut sequence = [""; 92];
123-
let mut decays = [[None; 6]; 92];
127+
// Build list of decay chains.
128+
let sizes: Vec<_> = elements.iter().map(|e| e[0].len()).collect();
129+
let decays: Vec<Vec<_>> =
130+
elements.iter().map(|e| e[4..].iter().map(|t| indices[t]).collect()).collect();
124131

125-
for (i, tokens) in elements.iter().enumerate() {
126-
sequence[i] = tokens[0];
127-
for (j, &token) in tokens.iter().skip(4).enumerate() {
128-
decays[i][j] = Some(indices[token]);
129-
}
130-
}
132+
// Each input is a single element.
133+
let mut current = [0; 92];
134+
current[indices[input.trim()]] = 1;
131135

132-
let mut current = initial_state(input, &sequence);
133136
for _ in 0..40 {
134137
current = step(&current, &decays);
135138
}
139+
let part1 = length(&current, &sizes);
136140

137-
let result1 = length(&current, &sequence);
138141
for _ in 0..10 {
139142
current = step(&current, &decays);
140143
}
144+
let part2 = length(&current, &sizes);
141145

142-
let result2 = length(&current, &sequence);
143-
(result1, result2)
146+
(part1, part2)
144147
}
145148

146149
pub fn part1(input: &Result) -> usize {
@@ -151,31 +154,20 @@ pub fn part2(input: &Result) -> usize {
151154
input.1
152155
}
153156

154-
fn initial_state(input: &str, sequence: &[&str]) -> [usize; 92] {
155-
let input = input.trim();
156-
let start = sequence.iter().position(|&s| s == input).unwrap();
157-
158-
let mut current = [0; 92];
159-
current[start] += 1;
160-
current
161-
}
162-
163-
fn step(current: &[usize; 92], decays: &[[Option<usize>; 6]; 92]) -> [usize; 92] {
157+
fn step(current: &[usize], decays: &[Vec<usize>]) -> [usize; 92] {
164158
let mut next = [0; 92];
165159

166-
for i in 0..92 {
167-
let c = current[i];
168-
if c > 0 {
169-
let mut iter = decays[i].iter();
170-
while let Some(Some(index)) = iter.next() {
171-
next[*index] += c;
160+
for (i, &count) in current.iter().enumerate() {
161+
if count > 0 {
162+
for &element in &decays[i] {
163+
next[element] += count;
172164
}
173165
}
174166
}
175167

176168
next
177169
}
178170

179-
fn length(current: &[usize;92], sequence: &[&str;92]) -> usize {
180-
current.iter().zip(sequence.iter()).map(|(c, s)| c * s.len()).sum()
171+
fn length(current: &[usize], sizes: &[usize]) -> usize {
172+
current.iter().zip(sizes.iter()).map(|(c, s)| c * s).sum()
181173
}

‎src/year2015/day11.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,10 @@ pub fn part2(input: &Input) -> &str {
4848
/// Sanitize the input to make sure it has no invalid characters. We increment the first invalid
4949
/// character found, for example `abcixyz` becomes `abcjaaa`.
5050
fn clean(mut password: Password) -> Password {
51-
let mut reset = false;
52-
53-
for digit in &mut password {
54-
if reset {
55-
*digit = b'a';
56-
} else if matches!(digit, b'i' | b'o' | b'l') {
57-
*digit += 1;
58-
reset = true;
59-
}
51+
if let Some(index) = password.iter().position(|&d| matches!(d, b'i' | b'o' | b'l')) {
52+
password[index] += 1;
53+
password[index + 1..].fill(b'a');
6054
}
61-
6255
password
6356
}
6457

‎src/year2015/day12.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ fn parse_object(input: &[u8], start: usize) -> Result {
7575
let mut ignore = false;
7676

7777
while input[index] != b'}' {
78-
let Result { next: first, .. } = parse_json(input, index + 1);
78+
let Result { next: first, .. } = parse_string(input, index + 1);
7979
let Result { next: second, ignore: red, value } = parse_json(input, first + 1);
8080
index = second;
8181
total += value;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /