Raggiungibilità di Word Changer


13

Word Changer è un gioco in cui stai cercando di trasformare una parola in un'altra tramite modifiche a carattere singolo, con ogni passaggio che è la sua parola. Per questa sfida, le modifiche possono essere sostituzioni, inserzioni o eliminazioni. Ad esempio, WINNER → LOSER può essere eseguito con questo percorso (potrebbero essercene altri):

WINNER
DINNER
DINER
DINE
LINE
LONE
LOSE
LOSER

Frase in un altro modo, devi essere in grado di raggiungere una parola dall'altra passando solo attraverso altre parole a una distanza di Levenshtein pari a 1 ogni volta.

Coding

Ti verrà fornito un elenco di parole e due parole e devi generare un percorso valido da una parola all'altra se esiste una rotta o un valore costante distinto o un comportamento coerente se non esiste alcuna rotta.

  • Si può presumere che le parole di input siano entrambe nell'elenco delle parole
  • L'elenco delle parole può essere preso in qualsiasi formato piatto conveniente.
    • Elenchi, insiemi, tentativi, stringhe separate da spazi e file separati da linee sono tutti validi (ad esempio), ma un grafico precalcolato dell'adiacenza di Levenshtein non lo è.
  • La route di output dovrebbe includere entrambe le parole di input, ma l'inizio e la fine non contano.
  • Se non viene trovato alcun percorso, è possibile generare una costante specifica, un valore errato, un elenco vuoto, generare un'eccezione, uscire con un codice diverso da zero o qualsiasi altro comportamento che si verifica a tempo finito.
  • Il percorso non deve essere ottimale e non è richiesto quale percorso debba essere intrapreso
  • La complessità computazionale non ha importanza, tuttavia il programma deve essere garantito in modo da terminare entro un tempo limitato. (anche se andrebbe oltre la morte di calore dell'universo)
  • Puoi presumere che tutte le parole siano interamente composte da lettere nello stesso caso

Esempi di casi di test

  • CAT → CANE; [CAT, DOG, COG, COT, FROG, GROG, BOG]
    • GATTO, COT, COG, CANE
  • BAGNO → DOCCIA; [BAGNO, DOCCIA, HATH, HAT, BAT, SAT, SAW, SOW, SHOW, HOW]
    • Nessun percorso trovato
  • BREAK → FIX; [BREAK, FIX, BEAK, BREAD, READ, BEAD, RED, BED, BAD, BID, FAD, FAX]
    • BREAK, BREAD, BEAD, BAD, FAD, FAX, FIX
  • COSTRUISCI → DISTRUGGI; [COSTRUISCI, DISTRUGGI, COSTRUITO, INCORPORATO, GUILD, GILD, GILL, BILL, DILL, FILL, DESTRUCT, STRUCTURE, COSTRUCT]
    • Nessun percorso trovato
  • SCHEDA → SCHEDA; [CARD, BOARD, BARD]
    • SCHEDA, BARD, SCHEDA
  • DEMONE → ANGEL; [DEMONE, ANGELO]
    • Nessun percorso trovato
  • ULTIMO → PASSATO; [LAST, PAST, BLAST, CAST, BLACK, GHOST, POST, BOAST]
    • ULTIMO, PASSATO
  • INSERISCI → ELIMINA; Questa lista di parole
    • INSERISCI, INVERTI, INVENT, INBENT, UNBENT, UNBEND, UNBIND, UNKIND, UNKING, INKING, IRKING, DIRKING, DARKING, DARLING, ARLING, AILING, SIRING, SERING, SERINE, NERINE, NERITE, CERITE, CERATE, DERATE, DELATE, ELIMINA


1
Possiamo produrre un elenco di percorsi validi o dovrebbe essere un percorso?
Emigna,

@Emigna qualsiasi percorso farà. Come ho detto "Il percorso non deve essere ottimale"
Beefster,

Dobbiamo includere la parola iniziale e finale nell'output? I percorsi inizieranno e finiranno sempre allo stesso modo!
Magic Octopus Urn

1
@MagicOctopusUrn "Il percorso di output dovrebbe includere entrambe le parole di input, ma che inizia e finisce non importa."
Beefster,

Risposte:


5

05AB1E , 23 21 20 byte

Stampa un elenco di percorsi validi.
Salvato 2 byte grazie a Kevin Cruijssen .

怜€`ʒü.LP}ʒ¬²Qsθ³Q*

Provalo online!


È possibile salvare 2 byte cambiando Dævyœ«}in 怜€` . (Non so perché entrambe le mappe separatamente funzionino bene, ma æεœ`}non è vero, ma è comunque lo stesso conteggio byte.)
Kevin Cruijssen

Peccato che il prodotto di []sia 1invece di 0(non troppo sorprendente, però) o che un controllo uguale con una lista vuota apparentemente si traduca in una lista vuota invece di 0(questa che vedo come un bug ..) .. Altrimenti avresti potuto combinare il filtro e find_first per salvare un altro byte:怜€`.Δü.LPy¬²Qsθ³QP
Kevin Cruijssen il

@KevinCruijssen: grazie! Non sono sicuro del motivo per cui non ho pensato di utilizzare . Penso che il controllo uguale porti ad un elenco vuoto a causa della vettorializzazione. Forse dovrebbe esserci un caso speciale per l'elenco vuoto, ma forse sarebbe inaspettato in altri casi.
Emigna,

1
Fa qualcosa di simile a questo lavoro per 17: provalo online!
Magic Octopus Urn

1
@MagicOctopusUrn: Sfortunatamente, dobbiamo includere tutte le parole del percorso nell'output.
Emigna,

4

JavaScript (V8) ,  177  176 byte

Accetta input come (target)(source, list). Stampa tutti i percorsi possibili. O non stampa nulla se non c'è soluzione.

t=>F=(s,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(S,L=[...l],[...p,L.splice(i,1)],1))

Provalo online!

Commentate

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()


3

Python 2 , 155 byte

f=lambda a,b,W,r=[]:a==b and r+[a]or reduce(lambda q,w:q or any({a,a[:i]+a[i+1:]}&{w,w[:i]+w[i+1:]}for i in range(len(a+w)))and f(w,b,W-{a},r+[a]),W-{a},0)

Provalo online!

Accetta due parole e un insieme di parole come input; restituisce una route (non ottimale) se ne esiste una come elenco di stringhe, altrimenti restituisce False.

Questo frammento:

any({a,a[:i]+a[i+1:]}&{w,w[:i]+w[i+1:]}for i in range(len(a+w)))

è Truese e solo se a==wo aha una distanza di Levenshtein 1da w.



2

Python 2 , 163 byte

Se viene trovata una route, viene emessa su stderr e il programma termina con il codice di uscita 1.
Se non esiste una route, non vi è alcun output e il programma termina con il codice di uscita 0.

s,e,d=input();r=[[s]]
for x in r:t=x[-1];t==e>exit(x);r+=[x+[w]for w in d-set(x)for a,b in(t,w),(w,t)for i in range(len(b)*2)if a==b[:i/2]+a[i/2:][:i%2]+b[i/2+1:]]

Provalo online!


1

Python 3 , 217 214 212 201 byte

-11 byte grazie a un suggerimento di xnor

d=lambda a,b:min(d(a[1:],b[1:])+(a[0]!=b[0]),d(a[1:],b)+1,d(a,b[1:])+1)if b>""<a else len(a+b)
def g(a,b,l,p=[]):
	if a==b:yield[a]+p
	for c in(a!=b)*l:
		if(c in p)+d(a,c)==1:yield from g(c,b,l,[a]+p)

Provalo online!


0

Gelatina , 38 byte

⁵ḟ,€0ị$ṭ¹-Ƥ$€e€/ẸƊƇḢ€
Wṭ@ⱮÇßƊe@⁴oṆƲ?€Ẏ

Provalo online!

Un programma completo che accetta tre argomenti. La prima è la parola iniziale e viene fornita come [["START"]]. Il secondo argomento è l'ultima parola, fornita come "END". Il terzo argomento è l'elenco di parole, fornito come parole tra virgolette, separate da virgola.

Il programma restituisce un elenco di elenchi, con ciascun elenco che rappresenta un percorso valido dall'inizio alla fine. Se non esiste un percorso valido, la risposta è un elenco vuoto.

Nel collegamento TIO, c'è un testo a piè di pagina per visualizzare il risultato in modo corretto con ogni parola separata da spazi e ogni elenco di parole separate da nuove righe. Se si preferisce una stampa dell'elenco sottostante, è possibile farlo come ÇŒṘ.

A differenza di 05ABIE, non esiste un built-in per la distanza di Levenshtein, quindi questo programma confronta i risultati con un singolo carattere mancante, un po 'simile alla soluzione di @ ChasBrown , anche se con un tocco Jelly.

Spiegazione

Collegamento helper: collegamento monadico che accetta un elenco di parole e restituisce un elenco di possibili elenchi estesi o un elenco vuoto se non è possibile alcuna ulteriore estensione

⁵ḟ                      | Filter the word list to remove words already used
  ,€0ị$                 | Pair each word with the last word in the current path
                  ƊƇ    | Filter these pairs such that
              e€/Ẹ      |   there exists any
       ṭ¹-Ƥ$€           |   match between the original words or any outfix with a single character removed
                    Ḣ€  | Take the first word of each of these pairs (i.e. the possible extensions of the route)

Collegamento principale

              €         | For each of the current paths
            Ʋ?          | If:
       e@⁴              |   The path contains the end word
          oṆ            |   Or the path is empty (i.e. could not be extended)
W                       | Return the path wrapped in a list (which will be stripped by the final Ẏ)
 ṭ@ⱮÇ                   | Otherwise, look for possible extensions using the helper link, and add onto the end of the path
     ßƊ                 | And then feed all of these paths back through this link
               Ẏ        | Strip back one layer of lists (needed because each recursion nests the path one list deeper)

0

Swift 4.2 / Xcode 10.2.1 , 387 byte

func d(l:String,m:String)->Bool{return (0..<l.count).contains{var c=l;c.remove(at:c.index(c.startIndex,offsetBy:$0));return c==m}};func f(r:[String])->[String]{if b==r.last!{return r};return w.lazy.map{!r.contains($0)&&(d(l:r.last!,m:$0)||d(l:$0,m:r.last!)||(r.last!.count==$0.count&&zip(r.last!,$0).filter{$0 != $1}.count==1)) ? f(r:r+[$0]):[]}.first{!$0.isEmpty} ?? []};return f(r:[a])

Provalo online!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.