Graph traversal nonsense should be the kind of stuff Dusa is great at, and indeed this seemed to go straightforwardly for me on a day that some folks got stumped on the Part 2. Most of my issues were that there wasn’t just one way to solve the problem, so I did a bit of unfocused exploration.
First step was to explode the input into charAt (pair X Y) is Ch
facts. So here we’d have:
charAt (pair 0 0) is "7"
charAt (pair 1 0) is "-"
charAt (pair 2 0) is "F"
01234
0 7-F7-
1 .FJ|7
2 SJLL7
3 |F--J
4 LJ.LJ
With that in place, we list out the ways in which the 6 relevant characters imply connections in the x and y directions.
**connectX "L" 1. connectY "L" -1.
connectX "J" -1. connectY "J" -1.
connectX "F" 1. connectY "F" 1.
connectX "7" -1. connectY "7" 1.
connectY "|" -1. connectY "|" 1.
connectX "-" -1. connectX "-" 1.**
From this, we’ll generate an edge
relation. This requires a bit of duplication — everything is described once for the x direction and once for the y direction.
Here’s the x direction version: there’s an edge if there’s an agreement that there is a connection in both the forwards and backwards directions.
**edge A B :-
*# Check for forwards connection*
charAt A is Ch, A == pair X1 Y,
connectX Ch Delta, X2 == plus X1 Delta,
*# Check for backwards connection*
B == pair X2 Y, charAt B is Ch2,
connectX Ch2 (minus 0 Delta).**
Once that’s in place we’re off to the races of using Dusa for graph algorithms. But where shall we start? The distinguished starting point is marked with an “S” character:
**start is A :- charAt A is "S".**
and so the first step we take will be to one of the two neighbors that have a connection to that character. (Again, this is the x-direction version and there’s a y-direction version too.)
**edge start (pair X Y) :-
charAt (pair X Y) is Ch,
connectX Ch Delta,
start == pair (plus X Delta) Y.**
The first set of rules were naturally symmetric, and the connected-to-start rules are not. We could solve this with a scalpel, especially if we supported multiple conclusions so the rule above could say edge (pair X Y) start
as well as edge start (pair X Y)
. But no matter, we can also solve it with a hammer and force the relation to be symmetric:
**edge A B :- edge B A.**
It’s helpful for both parts to for us to trace our way around the loop in one direction, and which direction doesn’t matter. But that’s Dusa’s whole thing: we can create an after
relation that starts at the start
and proceeds to an arbitrary edge connected to start
, and henceforch all the way around the loop:
**after start is { A? } :- edge start A.
after B is C :-
after A is B,
edge B C,
C != A.**