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.

Core solution

First step was to explode the input into charAt (pair X Y) is Ch facts. So here we’d have:

  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.**

Generating edges

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.**

Winding around the loop

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.**

Part 1 solution