AoC 2021 D21: Dirac Dice
| Problem statement | Source code | Tags: Dynamic programming
← Previous Back to AoC Index Next →
Part 1
For part 1, I had a bit of fun and overengineered the solution with classes and generator functions. None of this turned out to be useful for part 2.
Here's a die. Iterating it yields the next value. Closing it returns the total number of rolls. (When was the last time you used a finally block or a return in a generator function or... them combined? This feels like an abomination in every way. Heck, ESLint would even be unhappy about it.)
And here's a player.
The game itself is straightforward.
Part 2
Part 2 required a different approach entirely. It is somewhat like day 6 and day 14 in that we have many copies of the identical state which propagate the same way, so we just need to put them into bins and count how many are in each bin. The state here is the positions and scores of both players, as a 4D array:
Initially, there is one universe with both players at their starting positions and zero score:
Then, we simulate the game turn by turn, alternating between players. Because each time, the current player's score increases by at least 1, the game ends in at most 42 turns for both players combined.
The states are propagated by enumerating all possible combinations of the current state:
Now, for each state, we enumerate all possible rolls of the three dice. The number of worlds for each roll sum is as follows:
For each roll, we update the new state accordingly. If a player's score reaches 21, we increment their win count instead.
Note that we have to encode the state as a joint state of both players. If we track states for each player separately, then a dice roll of player 1 would not multiply the number of universes for each state of player 2, leading to a lower count.