7
votes
Day 19: Not Enough Minerals
Today's problem description: https://adventofcode.com/2022/day/19
Please post your solutions in your own top-level comment. Here's a template you can copy-paste into your comment to format it nicely, with the code collapsed by default inside an expandable section with syntax highlighting (you can replace python
with any of the "short names" listed in this page of supported languages):
<details>
<summary>Part 1</summary>
```python
Your code here.
```
</details>
So does anyone have any idea how to solve this one efficiently? This is the first time I've seen zero people on the private leaderboard solve either part within a half day or so.
I took a stab at it by always building the "highest-value" available mining robot each minute, which got me somewhat close to the expected value on the test input—I got 29 vs the expected 33.
My brute force approach which recursively tries every available action at each minute unsurprisingly is too slow even on the test input, since the number of branches to try is absolutely huge for even 1 blueprint.
Clearly the key is knowing when to hoard resources to build a higher-tier robot earlier, rather than building way too many ore robots, but how?
I looked at /r/adventofcode.
Solution hints
It's BFS or DFS with heuristics to prune the state space that needs to be explored into something of a manageable size.
People have solved the puzzle with all sorts of different heuristics, and it's mostly just trial and error. Many found success by branching on what robot to aim for building next rather than trying to make that decision at every step. It allows you to fast-forward through the steps where nothing gets built.
This does not spark joy; I'll be skipping this one.
This one looked like it would be similar to Day 16, but I underestimated how long it would take again.
I wasn't going to do any more of the puzzles because each takes at least an hour (this one took me close to 3h), but I sensed an opportunity to use an algorithm I had never found practical use for so far, and I had some time to kill.
Algorithm
Iterated Width
Width-based Planning is a search method that was, among other things, used successfully to play ATARI games in almost-realtime. The idea is to use a Breadth-First Search with a novelty pruning rule.
Each state is associated with features or atoms that are true for that state (e.g. "geodes=7"). The algorithm is called with increasing widths starting from 1. New states are pruned if there is no n-tuple of features (of size width) that has not already been seen during the search.
So if a state has the atoms 'A', 'B' and 'C', then IW(1) prunes the state if A, B and C have been seen before, and IW(2) prunes a state if (A, B), (A, C), and (B, C) have all been seen before. It is known that many problems have a low intrinsic width, so they are solvable using few calls to the IW search procedure, even if they have many different features.
I elected to use the complete search state of the problem (i.e. one atom for each robot and ore count, as well as the time remaining, and the current robot in production).
Apart from not knowing whether it would work at all, the main problem was that IW is an algorithm that is used for planning when you know the goal state, and here we didn't, so there was no way to know when to stop increasing the width parameter. This is probably highly unsound, but I stopped incrementing once the same result was returned twice in succession, and that worked.
The running time for both parts together is between 15 and 20 seconds, and that's with using multiple cores, so that could be better...
Part 1 & 2 (Rust)