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 f9fd77b

Browse files
Year 2019 speed and code quality improvements
1 parent b9350b6 commit f9fd77b

File tree

9 files changed

+129
-162
lines changed

9 files changed

+129
-162
lines changed

‎README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,18 +238,18 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
238238
| 1 | [The Tyranny of the Rocket Equation](https://adventofcode.com/2019/day/1) | [Source](src/year2019/day01.rs) | 1 |
239239
| 2 | [1202 Program Alarm](https://adventofcode.com/2019/day/2) | [Source](src/year2019/day02.rs) | 1 |
240240
| 3 | [Crossed Wires](https://adventofcode.com/2019/day/3) | [Source](src/year2019/day03.rs) | 17 |
241-
| 4 | [Secure Container](https://adventofcode.com/2019/day/4) | [Source](src/year2019/day04.rs) | 12 |
241+
| 4 | [Secure Container](https://adventofcode.com/2019/day/4) | [Source](src/year2019/day04.rs) | 7 |
242242
| 5 | [Sunny with a Chance of Asteroids](https://adventofcode.com/2019/day/5) | [Source](src/year2019/day05.rs) | 3 |
243243
| 6 | [Universal Orbit Map](https://adventofcode.com/2019/day/6) | [Source](src/year2019/day06.rs) | 29 |
244244
| 7 | [Amplification Circuit](https://adventofcode.com/2019/day/7) | [Source](src/year2019/day07.rs) | 79 |
245245
| 8 | [Space Image Format](https://adventofcode.com/2019/day/8) | [Source](src/year2019/day08.rs) | 4 |
246246
| 9 | [Sensor Boost](https://adventofcode.com/2019/day/9) | [Source](src/year2019/day09.rs) | 1008 |
247247
| 10 | [Monitoring Station](https://adventofcode.com/2019/day/10) | [Source](src/year2019/day10.rs) | 1092 |
248-
| 11 | [Space Police](https://adventofcode.com/2019/day/11) | [Source](src/year2019/day11.rs) | 341 |
249-
| 12 | [The N-Body Problem](https://adventofcode.com/2019/day/12) | [Source](src/year2019/day12.rs) | 1309 |
248+
| 11 | [Space Police](https://adventofcode.com/2019/day/11) | [Source](src/year2019/day11.rs) | 320 |
249+
| 12 | [The N-Body Problem](https://adventofcode.com/2019/day/12) | [Source](src/year2019/day12.rs) | 838 |
250250
| 13 | [Care Package](https://adventofcode.com/2019/day/13) | [Source](src/year2019/day13.rs) | 2527 |
251251
| 14 | [Space Stoichiometry](https://adventofcode.com/2019/day/14) | [Source](src/year2019/day14.rs) | 17 |
252-
| 15 | [Oxygen System](https://adventofcode.com/2019/day/15) | [Source](src/year2019/day15.rs) | 360 |
252+
| 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 |
255255
| 18 | [Many-Worlds Interpretation](https://adventofcode.com/2019/day/18) | [Source](src/year2019/day18.rs) | 1157 |

‎src/year2019/day02.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ fn search(input: &Input, x1: i32, x2: i32, y1: i32, y2: i32) -> Option<i32> {
6060

6161
let x = x1.midpoint(x2);
6262
let y = y1.midpoint(y2);
63-
let [a, b, c] = input;
63+
let [a, b, c] = *input;
6464
let result = a * x + b * y + c;
6565

6666
match result.cmp(&19690720) {

‎src/year2019/day04.rs

Lines changed: 33 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -3,89 +3,54 @@
33
//! We speed things up by only checking numbers that have digits in non-decreasing order for pairs.
44
//! These numbers become rapidly less dense as the password value increases and there
55
//! are only 3003 total of these numbers with 6 digits.
6+
use crate::util::iter::*;
67
use crate::util::parse::*;
7-
use crate::util::slice::*;
88

9-
pub fn parse(input: &str) -> Vec<u32> {
10-
input.iter_unsigned().collect()
11-
}
12-
13-
/// Password must contain at least one pair.
14-
pub fn part1(input: &[u32]) -> u32 {
15-
let predicate = |first: bool, second: bool, third: bool, fourth: bool, fifth: bool| {
16-
first || second || third || fourth || fifth
17-
};
18-
passwords(input, predicate)
19-
}
9+
type Input = (u32, u32);
2010

21-
/// Password must contain at least one pair that's not part of a larger group.
22-
pub fn part2(input: &[u32]) -> u32 {
23-
let predicate = |first: bool, second: bool, third: bool, fourth: bool, fifth: bool| {
24-
(first && !second)
25-
|| (!first && second && !third)
26-
|| (!second && third && !fourth)
27-
|| (!third && fourth && !fifth)
28-
|| (!fourth && fifth)
29-
};
30-
passwords(input, predicate)
31-
}
11+
pub fn parse(input: &str) -> Input {
12+
let [start, end] = input.iter_unsigned::<u32>().chunk::<2>().next().unwrap();
3213

33-
fn passwords(input: &[u32], predicate: impl Fn(bool, bool, bool, bool, bool) -> bool) -> u32 {
34-
let start = input[0];
35-
let end = input[1];
14+
let mut digits = to_digits(start);
15+
let end = to_digits(end);
3616

37-
// Split into six digits.
38-
let mut digits = [
39-
start / 100000,
40-
(start / 10000) % 10,
41-
(start / 1000) % 10,
42-
(start / 100) % 10,
43-
(start / 10) % 10,
44-
start % 10,
45-
];
17+
let mut part_one = 0;
18+
let mut part_two = 0;
4619

4720
// Increase the starting number to the next number that has all digits in non-decreasing order
4821
// to ensure that the incrementing logic in the search loop works correctly.
4922
// For example 223450 => 223455, 120568 => 122222 and 439999 => 444444.
50-
for i in 1..6 {
51-
if digits[i] < digits[i - 1] {
52-
for j in i..6 {
53-
digits[j] = digits[i - 1];
54-
}
55-
break;
56-
}
23+
if let Some(index) = digits.windows(2).position(|w| w[0] > w[1]) {
24+
let next = digits[index];
25+
digits[index..].fill(next);
5726
}
5827

59-
let mut n = 0;
60-
let mut count = 0;
61-
62-
while n <= end {
63-
// Check current number
64-
let first = digits[0] == digits[1];
65-
let second = digits[1] == digits[2];
66-
let third = digits[2] == digits[3];
67-
let fourth = digits[3] == digits[4];
68-
let fifth = digits[4] == digits[5];
28+
while digits <= end {
29+
// Build a 5 bit binary mask with a `1` if two adjacent digits are equal.
30+
let mask = digits.windows(2).fold(0, |acc, w| (acc << 1) | (w[0] == w[1]) as u32);
6931

70-
if predicate(first, second, third, fourth, fifth) {
71-
count += 1;
72-
}
32+
// Password must contain at least one pair.
33+
part_one += (mask != 0) as u32;
34+
// Password must contain at least one pair that's not part of a larger group.
35+
part_two += (mask & !(mask >> 1) & !(mask << 1) != 0) as u32;
7336

7437
// Find the next number with all digits in non-decreasing order.
75-
let mut i = 5;
76-
whiledigits[i] == 9{
77-
i -= 1;
78-
}
38+
let index = digits.iter().rposition(|&d| d < b'9').unwrap();
39+
let next = digits[index] + 1;
40+
digits[index..].fill(next);
41+
}
7942

80-
let next = digits[i] + 1;
81-
while i <= 5 {
82-
digits[i] = next;
83-
i += 1;
84-
}
43+
(part_one, part_two)
44+
}
8545

86-
// Convert number to `u32`.
87-
n = digits.fold_decimal();
88-
}
46+
pub fn part1(input: &Input) -> u32 {
47+
input.0
48+
}
49+
50+
pub fn part2(input: &Input) -> u32 {
51+
input.1
52+
}
8953

90-
count
54+
fn to_digits(n: u32) -> [u8; 6] {
55+
format!("{n:06}").into_bytes().try_into().unwrap()
9156
}

‎src/year2019/day06.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ pub fn parse(input: &str) -> Vec<usize> {
4949
let mut parent = vec![0; lines.len() + 2];
5050

5151
for line in lines {
52-
let left = lookup(&line[..3]);
53-
let right = lookup(&line[4..]);
52+
let left = lookup(&line[0..3]);
53+
let right = lookup(&line[4..7]);
5454
parent[right] = left;
5555
}
5656

@@ -71,8 +71,8 @@ pub fn part1(input: &[usize]) -> usize {
7171
}
7272

7373
let cache = &mut vec![None; input.len()];
74-
cache[0] = Some(0);
75-
cache[1] = Some(0);
74+
cache[0] = Some(0);// Special empty value
75+
cache[1] = Some(0);// COM
7676
(0..input.len()).map(|index| orbits(input, cache, index)).sum()
7777
}
7878

‎src/year2019/day08.rs

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
//! # Space Image Format
2+
const WIDTH: usize = 25;
3+
const HEIGHT: usize = 6;
4+
const LAYER_SIZE: usize = WIDTH * HEIGHT;
25

3-
pub fn parse(input: &str) -> &str {
4-
input
6+
pub fn parse(input: &str) -> &[u8] {
7+
input.as_bytes()
58
}
69

710
/// Each layer is 25 * 6 = 150 bytes and there are 100 layers total.
@@ -10,64 +13,56 @@ pub fn parse(input: &str) -> &str {
1013
/// so we must handle the last 6 bytes specially.
1114
///
1215
/// [`count_ones`]: u64::count_ones
13-
pub fn part1(input: &str) -> u32 {
14-
let bytes = input.as_bytes();
15-
let mut index = 0;
16-
let mut ones = 0;
17-
let mut twos = 0;
16+
pub fn part1(input: &[u8]) -> u32 {
1817
let mut most = 0;
1918
let mut result = 0;
2019

21-
for _ in 0..100 {
20+
for layer in input.chunks_exact(LAYER_SIZE) {
21+
let mut ones = 0;
22+
let mut twos = 0;
23+
2224
// First 144 of 150 bytes.
23-
for _ in 0..18 {
24-
let slice = &bytes[index..(index + 8)];
25+
for slice in layer.chunks_exact(8) {
2526
let n = u64::from_be_bytes(slice.try_into().unwrap());
2627
ones += (n & 0x0101010101010101).count_ones();
2728
twos += (n & 0x0202020202020202).count_ones();
28-
index += 8;
2929
}
3030

3131
// Handle remaining 6 bytes.
3232
// The masks exclude the most significant 2 bytes to prevent double counting.
33-
let slice = &bytes[(index - 2)..(index + 6)];
33+
let slice = &layer[142..150];
3434
let n = u64::from_be_bytes(slice.try_into().unwrap());
3535
ones += (n & 0x0000010101010101).count_ones();
3636
twos += (n & 0x0000020202020202).count_ones();
37-
index += 6;
3837

3938
if ones + twos > most {
4039
most = ones + twos;
4140
result = ones * twos;
4241
}
43-
44-
ones = 0;
45-
twos = 0;
4642
}
4743

4844
result
4945
}
5046

5147
/// Since a black or white pixel covers those in lower layers, it's faster to check each pixel
5248
/// stopping as soon as we hit a non-transparent value.
53-
pub fn part2(input: &str) -> String {
54-
let bytes = input.as_bytes();
55-
let mut image = ['.';150];
49+
pub fn part2(input: &[u8]) -> String {
50+
// Ensure enough capacity including newlines.
51+
let mut result = String::with_capacity((WIDTH + 1)*HEIGHT);
5652

57-
for (i, pixel)in image.iter_mut().enumerate() {
58-
letmut j = i;
53+
for y in 0..HEIGHT {
54+
result.push('\n');
5955

60-
while bytes[j] == b'2' {
61-
j += 150;
62-
}
56+
for x in 0..WIDTH {
57+
let mut i = WIDTH * y + x;
58+
59+
while input[i] == b'2' {
60+
i += LAYER_SIZE;
61+
}
6362

64-
if bytes[j] == b'1' {
65-
*pixel = '#';
63+
result.push(if input[i] == b'1' { '#' } else { '.' });
6664
}
6765
}
6866

69-
let mut result =
70-
image.chunks_exact(25).map(|row| row.iter().collect()).collect::<Vec<String>>().join("\n");
71-
result.insert(0, '\n');
7267
result
7368
}

‎src/year2019/day11.rs

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//!
33
//! This problem is a variant of [Langton's Ant](https://en.wikipedia.org/wiki/Langton%27s_ant).
44
use super::intcode::*;
5+
use crate::util::grid::*;
56
use crate::util::hash::*;
67
use crate::util::parse::*;
78
use crate::util::point::*;
@@ -21,38 +22,24 @@ pub fn part2(input: &[i64]) -> String {
2122
let panels: Vec<_> = hull.iter().filter(|&(_, &v)| v == 1).map(|(&k, _)| k).collect();
2223

2324
// Get maximum extents
24-
let mut x1 = i32::MAX;
25-
let mut x2 = i32::MIN;
26-
let mut y1 = i32::MAX;
27-
let mut y2 = i32::MIN;
28-
29-
for &point in &panels {
30-
x1 = x1.min(point.x);
31-
x2 = x2.max(point.x);
32-
y1 = y1.min(point.y);
33-
y2 = y2.max(point.y);
34-
}
25+
let (x1, x2, y1, y2) = panels.iter().fold(
26+
(i32::MAX, i32::MIN, i32::MAX, i32::MIN),
27+
|(min_x, max_x, min_y, max_y), p| {
28+
(min_x.min(p.x), max_x.max(p.x), min_y.min(p.y), max_y.max(p.y))
29+
},
30+
);
3531

3632
// Convert panels to characters
37-
let width = (x2 - x1 + 1) as usize;
38-
let height = (y2 - y1 + 1) as usize;
39-
let offset = Point::new(x1, y1);
40-
let mut image = vec!['.'; width * height];
33+
let width = x2 - x1 + 2; // Leave room for newline character.
34+
let height = y2 - y1 + 1;
35+
let mut image = Grid::new(width, height, b'.');
4136

42-
for &point in &panels {
43-
let adjusted = point - offset;
44-
let index = (width * adjusted.y as usize) + (adjusted.x as usize);
45-
image[index] = '#';
46-
}
37+
let offset = Point::new(x1 - 1, y1);
38+
panels.iter().for_each(|&point| image[point - offset] = b'#');
39+
40+
(0..height).for_each(|y| image[Point::new(0, y)] = b'\n');
4741

48-
// Convert to multiline string
49-
let mut result = image
50-
.chunks_exact(width)
51-
.map(|row| row.iter().collect())
52-
.collect::<Vec<String>>()
53-
.join("\n");
54-
result.insert(0, '\n');
55-
result
42+
String::from_utf8(image.bytes).unwrap()
5643
}
5744

5845
fn paint(input: &[i64], initial: i64) -> FastMap<Point, i64> {
@@ -64,12 +51,12 @@ fn paint(input: &[i64], initial: i64) -> FastMap<Point, i64> {
6451
hull.insert(position, initial);
6552

6653
loop {
67-
let panel = hull.get(&position).unwrap_or(&0);
54+
let panel = hull.entry(position).or_default();
6855
computer.input(*panel);
6956

7057
match computer.run() {
7158
State::Output(color) => {
72-
hull.insert(position,color);
59+
*panel = color;
7360
}
7461
_ => break,
7562
}

‎src/year2019/day12.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
//! [`signum`]: i32::signum
1717
use crate::util::math::*;
1818
use crate::util::parse::*;
19+
use std::array::from_fn;
1920

2021
type Axis = [i32; 8];
2122
type Input = [Axis; 3];
@@ -39,16 +40,16 @@ pub fn part1(input: &Input) -> i32 {
3940
z = step(z);
4041
}
4142

42-
let e:Vec<_> = (0..8).map(|i| x[i].abs() + y[i].abs() + z[i].abs()).collect();
43-
e[0] * e[4] + e[1] * e[5] + e[2] * e[6] + e[3] * e[7]
43+
let [p0, p1, p2, p3, v0, v1, v2, v3] = from_fn(|i| x[i].abs() + y[i].abs() + z[i].abs());
44+
p0 * v0 + p1 * v1 + p2 * v2 + p3 * v3
4445
}
4546

4647
pub fn part2(input: &Input) -> usize {
4748
let [mut x, mut y, mut z] = *input;
4849
let [mut a, mut b, mut c] = [0, 0, 0];
4950
let mut count = 0;
5051

51-
while a == 0 || b == 0 || c == 0 {
52+
while a * b * c == 0 {
5253
count += 1;
5354

5455
if a == 0 {
@@ -81,10 +82,17 @@ fn step(axis: Axis) -> Axis {
8182
// "p" is position and "v" velocity
8283
let [p0, p1, p2, p3, v0, v1, v2, v3] = axis;
8384

84-
let n0 = v0 + (p1 - p0).signum() + (p2 - p0).signum() + (p3 - p0).signum();
85-
let n1 = v1 + (p0 - p1).signum() + (p2 - p1).signum() + (p3 - p1).signum();
86-
let n2 = v2 + (p0 - p2).signum() + (p1 - p2).signum() + (p3 - p2).signum();
87-
let n3 = v3 + (p0 - p3).signum() + (p1 - p3).signum() + (p2 - p3).signum();
85+
let a = (p1 - p0).signum();
86+
let b = (p2 - p0).signum();
87+
let c = (p3 - p0).signum();
88+
let d = (p2 - p1).signum();
89+
let e = (p3 - p1).signum();
90+
let f = (p3 - p2).signum();
91+
92+
let n0 = v0 + a + b + c;
93+
let n1 = v1 - a + d + e;
94+
let n2 = v2 - b - d + f;
95+
let n3 = v3 - c - e - f;
8896

8997
[p0 + n0, p1 + n1, p2 + n2, p3 + n3, n0, n1, n2, n3]
9098
}

0 commit comments

Comments
(0)

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