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 2439fa7

Browse files
Year 2022 speed and code quality improvements
1 parent a8f4b25 commit 2439fa7

File tree

5 files changed

+101
-101
lines changed

5 files changed

+101
-101
lines changed

‎README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,11 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
152152
| 11 | [Monkey in the Middle](https://adventofcode.com/2022/day/11) | [Source](src/year2022/day11.rs) | 1173 |
153153
| 12 | [Hill Climbing Algorithm](https://adventofcode.com/2022/day/12) | [Source](src/year2022/day12.rs) | 57 |
154154
| 13 | [Distress Signal](https://adventofcode.com/2022/day/13) | [Source](src/year2022/day13.rs) | 15 |
155-
| 14 | [Regolith Reservoir](https://adventofcode.com/2022/day/14) | [Source](src/year2022/day14.rs) | 205 |
155+
| 14 | [Regolith Reservoir](https://adventofcode.com/2022/day/14) | [Source](src/year2022/day14.rs) | 146 |
156156
| 15 | [Beacon Exclusion Zone](https://adventofcode.com/2022/day/15) | [Source](src/year2022/day15.rs) | 2 |
157157
| 16 | [Proboscidea Volcanium](https://adventofcode.com/2022/day/16) | [Source](src/year2022/day16.rs) | 59 |
158158
| 17 | [Pyroclastic Flow](https://adventofcode.com/2022/day/17) | [Source](src/year2022/day17.rs) | 71 |
159-
| 18 | [Boiling Boulders](https://adventofcode.com/2022/day/18) | [Source](src/year2022/day18.rs) | 121 |
159+
| 18 | [Boiling Boulders](https://adventofcode.com/2022/day/18) | [Source](src/year2022/day18.rs) | 52 |
160160
| 19 | [Not Enough Minerals](https://adventofcode.com/2022/day/19) | [Source](src/year2022/day19.rs) | 74 |
161161
| 20 | [Grove Positioning System](https://adventofcode.com/2022/day/20) | [Source](src/year2022/day20.rs) | 3785 |
162162
| 21 | [Monkey Math](https://adventofcode.com/2022/day/21) | [Source](src/year2022/day21.rs) | 64 |

‎src/year2022/day09.rs

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,26 @@ use crate::util::parse::*;
77
use crate::util::point::*;
88

99
type Pair = (Point, i32);
10-
type Input = ([i32;4], Vec<Pair>);
10+
type Input = (i32,i32,i32,i32, Vec<Pair>);
1111

1212
/// Converts input lines into a pair of [`Point`] and integer amount, to indicate direction and
1313
/// magnitude respectively. Then determines the maximum extent of the head so that we can allocate
1414
/// a two dimensional grid.
1515
pub fn parse(input: &str) -> Input {
1616
let first = input.bytes().filter(u8::is_ascii_alphabetic).map(Point::from);
1717
let second = input.iter_signed::<i32>();
18-
let pairs = first.zip(second).collect();
18+
let pairs:Vec<_> = first.zip(second).collect();
1919

2020
// Determine maximum extents
21-
let mut x1 = i32::MAX;
22-
let mut y1 = i32::MAX;
23-
let mut x2 = i32::MIN;
24-
let mut y2 = i32::MIN;
25-
let mut point = ORIGIN;
21+
let (x1, y1, x2, y2, _) = pairs.iter().fold(
22+
(i32::MAX, i32::MAX, i32::MIN, i32::MIN, ORIGIN),
23+
|(x1, y1, x2, y2, point), &(step, amount)| {
24+
let next = point + step * amount;
25+
(x1.min(next.x), y1.min(next.y), x2.max(next.x), y2.max(next.y), next)
26+
},
27+
);
2628

27-
for &(step, amount) in &pairs {
28-
point += step * amount;
29-
x1 = x1.min(point.x);
30-
y1 = y1.min(point.y);
31-
x2 = x2.max(point.x);
32-
y2 = y2.max(point.y);
33-
}
34-
35-
([x1, y1, x2, y2], pairs)
29+
(x1, y1, x2, y2, pairs)
3630
}
3731

3832
/// Simulate a rope length of 2
@@ -54,7 +48,7 @@ pub fn part2(input: &Input) -> u32 {
5448
/// Using const generics for the rope length allows the compiler to optimize the loop and speeds
5549
/// things up by about 40%.
5650
fn simulate<const N: usize>(input: &Input) -> u32 {
57-
let ([x1, y1, x2, y2], pairs) = input;
51+
let (x1, y1, x2, y2, pairs) = input;
5852
let width = x2 - x1 + 1;
5953
let height = y2 - y1 + 1;
6054
let start = Point::new(-x1, -y1);

‎src/year2022/day10.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@ pub fn part1(input: &[i32]) -> i32 {
2626

2727
/// Returns pixels as a multi-line [`String`] so that the entire function can be integration tested.
2828
pub fn part2(input: &[i32]) -> String {
29-
let to_char = |(i, c):(usize,&i32)| {
30-
if((i asi32) - c).abs() <= 1{'#'}else{'.'}
31-
};
32-
letmut result = input
33-
.chunks_exact(40)
34-
.map(|row| row.iter().enumerate().map(to_char).collect())
35-
.collect::<Vec<String>>()
36-
.join("\n");
37-
result.insert(0,'\n');
29+
let mut result = String::new();
30+
31+
for row in input.chunks_exact(40){
32+
result.push('\n');
33+
for(i,&c)in row.iter().enumerate(){
34+
result.push(if((i asi32) - c).abs() <= 1{'#'}else{'.'});
35+
}
36+
}
37+
3838
result
3939
}

‎src/year2022/day14.rs

Lines changed: 48 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
//! the whole pile.
1616
//!
1717
//! We instead simulate in `O(n)` complexity by recursively check each grain's underneath
18-
//! neighbors until we have a conclusive result then propagating that back up the call stack,
18+
//! neighbors until we have a conclusive result then propagating that back up the stack,
1919
//! for example:
2020
//!
2121
//! ```none
@@ -31,6 +31,7 @@
3131
//! * `Falling` Grains of sand that will continue to fall continously forever.
3232
//! * `Stopped` Both original rock walls and any grains of sand that have come to rest.
3333
use crate::util::parse::*;
34+
use Kind::*;
3435

3536
#[derive(Clone, Copy, PartialEq, Eq)]
3637
enum Kind {
@@ -43,89 +44,86 @@ enum Kind {
4344
pub struct Cave {
4445
width: usize,
4546
height: usize,
46-
size: usize,
4747
kind: Vec<Kind>,
48-
floor: Kind,
49-
count: u32,
50-
}
51-
52-
impl Cave {
53-
fn fall(&mut self, index: usize) -> Kind {
54-
// Check in order: center, left then right
55-
let result = self.check(index + self.width)
56-
&& self.check(index + self.width - 1)
57-
&& self.check(index + self.width + 1);
58-
59-
// If all 3 bottom neighbors are stopped then so are we.
60-
// Cache the result into the grid then propagate result back up the call stack.
61-
if result {
62-
self.count += 1;
63-
self.kind[index] = Kind::Stopped;
64-
Kind::Stopped
65-
} else {
66-
self.kind[index] = Kind::Falling;
67-
Kind::Falling
68-
}
69-
}
70-
71-
// Returns `true` if cell is stopped.
72-
fn check(&mut self, index: usize) -> bool {
73-
let kind = if index >= self.size {
74-
// If we've reached the "floor" then return that.
75-
self.floor
76-
} else if self.kind[index] == Kind::Air {
77-
// If we're unknown then recursively check our own underneath neighbors
78-
self.fall(index)
79-
} else {
80-
// Otherwise use the cached value.
81-
self.kind[index]
82-
};
83-
kind == Kind::Stopped
84-
}
8548
}
8649

8750
/// Creates a 2D grid cave exactly the maximum possible size.
8851
pub fn parse(input: &str) -> Cave {
8952
let unsigned = |line: &str| line.iter_unsigned().collect();
9053
let points: Vec<Vec<usize>> = input.lines().map(unsigned).collect();
9154
let max_y = points.iter().flat_map(|row| row.iter().skip(1).step_by(2)).max().unwrap();
55+
9256
// Floor is 2 below the bottommost wall.
9357
let height = max_y + 2;
9458
// Allow enough horizontal room to spread out.
9559
let width = 2 * height + 1;
96-
let size = width * height;
97-
let mut kind = vec![Kind::Air; size];
9860

9961
// Draw each of the walls.
62+
let mut kind = vec![Air; width * height];
63+
10064
for row in points {
10165
for window in row.windows(4).step_by(2) {
10266
if let &[x1, y1, x2, y2] = window {
103-
for x in x1.min(x2)..=x1.max(x2) {
67+
if x1 == x2 {
10468
for y in y1.min(y2)..=y1.max(y2) {
105-
kind[(width * y) + (x + height - 500)] = Kind::Stopped;
69+
kind[width * y + x1 + height - 500] = Stopped;
70+
}
71+
} else {
72+
for x in x1.min(x2)..=x1.max(x2) {
73+
kind[width * y1 + x + height - 500] = Stopped;
10674
}
10775
}
10876
}
10977
}
11078
}
11179

112-
Cave { width, height, size,kind,floor:Kind::Air,count:0 }
80+
Cave { width, height, kind }
11381
}
11482

11583
/// If a grain of sand reaches the floor it will fall forever.
11684
pub fn part1(input: &Cave) -> u32 {
117-
simulate(input, Kind::Falling)
85+
simulate(input, Falling)
11886
}
11987

12088
/// The floor is solid rock.
12189
pub fn part2(input: &Cave) -> u32 {
122-
simulate(input, Kind::Stopped)
90+
simulate(input, Stopped)
12391
}
12492

12593
fn simulate(input: &Cave, floor: Kind) -> u32 {
126-
let mut cave = input.clone();
127-
cave.floor = floor;
94+
let Cave { width, height, mut kind } = input.clone();
95+
let mut count = 0;
96+
12897
// Height is also the x coordinate of the central starting location for grains.
129-
cave.fall(cave.height);
130-
cave.count
98+
let mut todo = Vec::with_capacity(1_000);
99+
todo.push(height);
100+
101+
'outer: while let Some(index) = todo.pop() {
102+
// Check in order: center, left then right
103+
for next in [index + width, index + width - 1, index + width + 1] {
104+
// If we've reached the "floor" then return that.
105+
let tile = if next >= kind.len() { floor } else { kind[next] };
106+
107+
match tile {
108+
// If we're unknown then check underneath neighbors first then re-check this tile.
109+
Air => {
110+
todo.push(index);
111+
todo.push(next);
112+
continue 'outer;
113+
}
114+
// Any falling tile underneath means that this tile is also falling.
115+
Falling => {
116+
kind[index] = Falling;
117+
continue 'outer;
118+
}
119+
Stopped => (),
120+
}
121+
}
122+
123+
// If all 3 tiles underneath are stopped then this tile is also stopped.
124+
kind[index] = Stopped;
125+
count += 1;
126+
}
127+
128+
count
131129
}

‎src/year2022/day18.rs

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
use crate::util::iter::*;
1010
use crate::util::parse::*;
1111

12-
const SIZE: usize = 22;
12+
const SIZE: usize = 24;
1313

14-
pub fn parse(input: &str) -> Vec<u32> {
14+
pub fn parse(input: &str) -> Vec<u8> {
1515
let mut cube = vec![0; SIZE * SIZE * SIZE];
1616
// Leave a 1 layer boundary around the outside for the part two flood fill
1717
// and also so that we don't have to use boundary checks when checking neighbors.
@@ -21,49 +21,57 @@ pub fn parse(input: &str) -> Vec<u32> {
2121
cube
2222
}
2323

24-
pub fn part1(input: &[u32]) -> u32 {
24+
pub fn part1(input: &[u8]) -> u32 {
2525
// The exposed surface area is the 6 faces of the cubes minus any neighbors.
2626
count(input, |x| 6 - x)
2727
}
2828

29-
pub fn part2(input: &[u32]) -> u32 {
30-
let mut cube = input.to_vec();
29+
pub fn part2(input: &[u8]) -> u32 {
3130
// "Paint" the outside of the cube with water drops.
32-
flood_fill(&mut cube, 0);
31+
// Use 8 as the nearest power of two greater than 6.
32+
let mut cube = input.to_vec();
33+
cube[0] = 8;
34+
35+
let mut todo = Vec::new();
36+
todo.push(0);
37+
38+
while let Some(index) = todo.pop() {
39+
let mut flood_fill = |next| {
40+
if next < input.len() && cube[next] == 0 {
41+
cube[next] = 8;
42+
todo.push(next);
43+
}
44+
};
45+
46+
// We may wrap around but that index will be out of bounds.
47+
flood_fill(index.wrapping_sub(1));
48+
flood_fill(index + 1);
49+
flood_fill(index.wrapping_sub(SIZE));
50+
flood_fill(index + SIZE);
51+
flood_fill(index.wrapping_sub(SIZE * SIZE));
52+
flood_fill(index + SIZE * SIZE);
53+
}
54+
3355
// Divide by 8 so that we only count water cubes.
3456
count(&cube, |x| x >> 3)
3557
}
3658

37-
fn count(cube: &[u32], adjust: fn(u32) -> u32) -> u32 {
59+
fn count(cube: &[u8], adjust: fn(u32) -> u32) -> u32 {
3860
let mut total = 0;
3961

4062
for i in 0..cube.len() {
4163
if cube[i] == 1 {
4264
// No need for boundary checks as all cubes are at least 1 away from the edge.
4365
total += adjust(
44-
cube[i - 1]
66+
(cube[i - 1]
4567
+ cube[i + 1]
4668
+ cube[i - SIZE]
4769
+ cube[i + SIZE]
4870
+ cube[i - SIZE * SIZE]
49-
+ cube[i + SIZE * SIZE],
71+
+ cube[i + SIZE * SIZE])asu32,
5072
);
5173
}
5274
}
5375

5476
total
5577
}
56-
57-
fn flood_fill(cube: &mut [u32], i: usize) {
58-
if cube.get(i) == Some(&0) {
59-
// Use 8 as the nearest power of two greater than 6.
60-
cube[i] = 8;
61-
// We may wrap around to an opposite edge but that will also be water.
62-
flood_fill(cube, i.saturating_sub(1));
63-
flood_fill(cube, i + 1);
64-
flood_fill(cube, i.saturating_sub(SIZE));
65-
flood_fill(cube, i + SIZE);
66-
flood_fill(cube, i.saturating_sub(SIZE * SIZE));
67-
flood_fill(cube, i + SIZE * SIZE);
68-
}
69-
}

0 commit comments

Comments
(0)

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