Takes input as (target)(source, list)
. Prints all possible routes. Or prints nothing if there's no solution.
f=t=>F=(s,t,l,p=[],d)=>s==t?print(p):l.map((S,i)=>(g=(m,n)=>m*n?1+Math.min(g(m-1,n),g(m,--n),g(--m,n)-(S[m]==s[n])):m+n)(S.length,s.length)^d||f^d||F(S,t,L=[...l],[...p,L.splice(i,1)],1))
Try it online!Try it online!
###Commented
t => // t = target string
F = ( // F is a recursive function taking:
s, // s = source string
l, // l[] = list of words
p = [], // p[] = path
d // d = expected Levenshtein distance between s and the
) => // next word (initially undefined, so coerced to 0)
s == t ? // if s is equal to t:
print(p) // stop recursion and print the path
: // else:
l.map((S, i) => // for each word S at index i in l[]:
( g = // g = recursive function computing the Levenshtein
(m, n) => // distance between S and s
m * n ? // if both m and n are not equal to 0:
1 + Math.min( // add 1 to the result + the minimum of:
g(m - 1, n), // g(m - 1, n)
g(m, --n), // g(m, n - 1)
g(--m, n) - // g(m - 1, n - 1), minus 1 if ...
(S[m] == s[n]) // ... S[m - 1] is equal to s[n - 1]
) // end of Math.min()
: // else:
m + n // return either m or n
)(S.length, s.length) // initial call to g with m = S.length, n = s.length
^ d || // unless the distance is not equal to d,
F( // do a recursive call to F with:
S, // the new source string S
L = [...l], // a copy L[] of l[]
[...p, L.splice(i, 1)], // the updated path (removes S from L[])
1 // an expected distance of 1
) // end of recursive call
) // end of map()