Generate self-avoiding loops of a specific length

APL (Dyalog Extended), 39 bytes


Try it online!

The output is a matrix of characters, one path on a line.

How it works

{∧'LURD'⊇⍨m⌿⍨(⍲∘⍧=⊢/)⍤1+\0J1*m←⍉4⊤⍳4*⍵}  ⍝ Input ⍵←n

m←⍉4⊤⍳4*⍵  ⍝ A matrix of all length-n combinations of 0..3
     ⍳4*⍵  ⍝ 0..4^n-1
   4⊤      ⍝ Convert each to base 4 (each goes to a column)
m←⍉        ⍝ Transpose and assign to m

                        0J1*m  ⍝ Power of i (directions on complex plane)
                      +\       ⍝ Cumulative sum; the path of the robot
            (      )⍤1  ⍝ Test each row:
                 ⊢/     ⍝   the last number (real+imag is always even)
                =       ⍝   equals
             ⍲∘⍧        ⍝   NAND of the nub-sieve
                        ⍝   (0 if all numbers are unique, 1 otherwise)
                        ⍝ The condition is satisfied only if both are 0
         m⌿⍨  ⍝  Extract the rows that satisfy the above
 'LURD'⊇⍨     ⍝  Index each number into the string 'LURD'
∧             ⍝  Ascending sort

Python 2, 119 106 104 bytes

def f(n,s="",p=0,*v):
 if p==n<1:print s
 for d in"DLRU":p in v or 0<n<f(n-1,s+d,p+1j**(ord(d)%15),p,*v)

Try it online!

Same idea in Python 3:

Python 3, 102 100 bytes

-2 bytes thanks to @ovs!

def f(n,s="",p=0,*v):p==n<1==print(s);p in v or[f(n-1,s+d,p+1j**(ord(d)%15),p,*v)for d in"DLRU"if n]

Try it online!

A recursive function that prints the results to STDOUT. Keep track of s, p, v which are the current sequence, the current position (as a complex number), and the list of visited positions respectively.

The sequence is printed when n == 0 and the position is back to 0, aka p==n<1.

Otherwise, if there is still moves and no self-intersection (n > 0 and p not in v), the function tries to move the current position in 4 directions, and recurs. Given the character d that is one of the 4 character D, L, R, U, the direction is determined as

1j ** (ord(d) % 15)


d  ord(d)  ord(d)%15  1j**...
D   68        8         1
L   76        1         1j
R   82        7        -1j
U   85        10       -1

Husk, 21 bytes


Try it online!


A string over RULD encodes a self-avoiding loop if and only if the only contiguous substring with an equal number of R and L, and of U and D, is the entire string. I loop over all strings of the given length and check this condition by brute force.

fS=oḟȯE½M#₁Q`π₁  Implicit input n
            `π₁  Length-n words over string "RULD" (from second line).
f                Keep those that satisfy this:
           Q       List of substrings
   oḟ              Get the first one that satisfies this:
        M#₁          Counts of each letter in "RULD"
       ½             Split in half
     ȯE              The halves (counts of R,U vs counts of L,D) are equal
 S=                That equals the string, which is the last substring in the list