Advent of Code 2023 - Day 19Aplenty
| Problem statement | Source code | Tags: BFS/DFSGeometry
Part 1
I parse the input to a mapping from name to the rules, where each rule contains a cond and a target.
For part 1, I just use eval. It's actually trivial to parse these conditions, but what other opportunity do you have to use eval?
Now I just repeatedly apply, see if I end up at A.
Part 2
Let's think about the process of applying these rules. Each time I go down a path, I know additional information about the input. For example, in → qqz → hdj → pv → A tells me that s >= 1351, s < 2771 && m < 1801, m < 839, a < 1717. Therefore, if we label each edge by its condition, then a path from in to A corresponds to a conjunction of conditions specifying a region of the input space. If we find all paths from in to A, we can take the union of these regions, which is the set of all inputs that lead to A.
There's a pitfall: the conditions aren't mutually exclusive. However, they are applied in order, so if we took a later rule, we know that the earlier rules didn't apply—so the edge condition actually contains the negation of all earlier conditions. For example, the rule from qqz to hdj itself just says m < 1801, but the previous rule says s > 2770 and it didn't apply, so we know s < 2771, so the edge has condition s < 2771 && m < 1801.
I built a reverse graph, and then did a DFS from A to in.
This generates a list of paths, such as:
Now we just need to find the union of these regions. This is similar to 2021 day 22: each path corresponds to a cuboid in 4D space (bounded by ), and we want to find the volume of the union of these cuboids. We can use the same approach as in that problem: maintain a list of "on" and "off" cuboids, and for each new cuboid, add it to the list and add the intersection with each existing cuboid with the opposite sign.