Expand description
§Parabolic Reflector Dish
To solve part two we look for a cycle where the dish returns to a previously seen state.
By storing each dish and a index in a HashMap
we can calculate the offset and length of the
cycle then use that to find to state at the billionth step.
Calculating the state needs to be done sequentially so we use some tricks to make it as fast as possible.
First the location of each each ball is stored in a vec
. My input had ~2,000 balls compared to
10,000 grid squares total, so this approach reduces the amount of data to scan by 5x. The 2D
coordinates are converted so a 1D number, for example the index of a ball on the second row
second column would be 1 * 100 + 1 = 101.
Next for each possible tilt orientation (north, south, east and west) an approach similar to a prefix sum is used. Each edge or fixed rock is assigned an index. We expand the grid by 2 in each direction (one for each edge) to handles the edges. For example, using west (left):
..#.#..
is represented in fixed_west
as (noticing the extra 0 for the left edge)
0 0 0 1 1 2 2 2
The the number of balls the come to rest against each fixed point is counted, for example:
OO#.#OO
is stored in roll_west
similar to:
2 0 2
This approach has two huge advantages:
First, the number of balls resting against each fixed point completely represents the state of the
grid in a very compact format. For example my input has ~1600 fixed points. Using 2 bytes per
point needs 3.2K total to represent the grid, compared to 100 * 100 = 10K for the simple approach.
3x less data is 3x faster to hash when storing states in a HashMap
looking for duplicates.
Second, calculating the new position of a ball is very fast. For each ball:
- Use
fixed_*
to lookup the index in the correspondingroll_*
vec. - This stores the current index of the last ball resting against that fixed point.
- Increment this value by ±1 for horizontal movement or ±width for vertical movement and then update the new location of this ball.
For example, tilting a single row west, processing each ball from left to right where each line represent the new state would look like:
grid rounded fixed_west roll_west
.O#..O.OO.#..O [1 5 7 8 13] [0 0 1 1 1 1 1 1 1 1 2 2 2 2] [-1 2 10]
O.#..O.OO.#..O [0 5 7 8 13] [0 0 1 1 1 1 1 1 1 1 2 2 2 2] [0 2 10]
O.#O...OO.#..O [0 3 7 8 13] [0 0 1 1 1 1 1 1 1 1 2 2 2 2] [0 3 10]
O.#OO...O.#..O [0 3 4 8 13] [0 0 1 1 1 1 1 1 1 1 2 2 2 2] [0 4 10]
O.#OOO....#..O [0 3 4 5 13] [0 0 1 1 1 1 1 1 1 1 2 2 2 2] [0 5 10]
O.#OOO....#O.. [0 3 4 5 11] [0 0 1 1 1 1 1 1 1 1 2 2 2 2] [0 5 11]
Structs§
Functions§
- tilt 🔒Very fast calculation of new state after tilting in the specified direction.