Word Spinner Puzzle

10

Este es un rompecabezas de palabras.

Su programa debe aceptar dos palabras en la entrada estándar.
La palabra uno es la palabra de inicio. La palabra dos es la palabra final.

Desde la palabra inicial, debe llegar a la palabra final cambiando / agregando / eliminando una letra a la vez. Después de cada modificación, debe formar una nueva palabra válida. Las letras agregadas se agregan al principio o al final. Puede eliminar letras de cualquier ubicación (pero la palabra no debe caer debajo de tres letras de longitud). Nota: No puede reorganizar las letras para formar una palabra.

La salida del programa es la secuencia de palabras para llegar desde la palabra inicial hasta la final.

Ejemplo:

Input:
    Post Shot

Output:
    Post
    cost
    coat
    goat
    got
    hot
    shot

Ganador:

  • El programa debe ejecutarse en un tiempo razonable (menos de 10 segundos).
  • El programa que puede generar la secuencia de salida más corta para las palabras premiadas.
    • Zink -> Silicio
  • Si más de un programa obtiene la secuencia más corta, entonces el programa más corto en caracteres (ignorando el espacio en blanco).
  • Si todavía tenemos más de una fecha / hora de presentación del programa se utilizará.

Notas:

Martin York
fuente
puede ser "post-> pot-> hot-> shot" es más corto.
USTED
@ S.Mark: Entonces tu algoritmo vence al mío y tú ganas. Lo anterior es un ejemplo de una posible solución. Una solución más corta supera a una solución más larga.
Martin York
¿intencionalmente? lo siento, me equivoqué.
USTED
2
¿Podría resolverlo en espacios en blanco para 0 programas de tamaño?
@Tim Nordenfur: Me encantaría ver una implementación de espacios en blanco. Nota. Hay dos reglas antes de la duración del programa para decidir el ganador. Pero si cumple con esos requisitos :-)
Martin York

Respuestas:

2

Python, 288 caracteres

(sin contar la línea de lectura del diccionario)

X=set(open('websters-dictionary').read().upper().split())

(S,E)=raw_input().upper().split()
G={S:0}
def A(w,x):
 if x not in G and x in X:G[x]=w
while E not in G:
 for w in G.copy():
  for i in range(len(w)):
   for c in"ABCDEFGHIJKLMNOPQRSTUVWXYZ":A(w,w[:i]+c+w[i+1:]);A(w,w[:i]+w[i+1:]);A(w,c+w);A(w,w+c)
s=''
while E:s=E+'\n'+s;E=G[E]
print s

para el desafío zinkde silicon:

ZINK
PINK
PANK
PANI
PANIC
PINIC
SINIC
SINICO
SILICO
SILICON

Hay algunas palabras extrañas en ese diccionario ...

Keith Randall
fuente
En realidad no verifiqué el contenido. Intenté encontrar un diccionario que todos pudieran usar.
Martin York
prueba con guester overturn(toma un tiempo) o regatta gyrally(no regresa) ;-)
Arnaud Le Blanc
Sí, algunas combinaciones llevan un tiempo. El tiempo se alarga a medida que la solución más corta se alarga. Y el último no tiene solución: no hay especificaciones para lo que debería suceder en ese caso :) Sin embargo, es bastante fácil de modificar para manejarlo (guarde un controlador en G.copy () y compare G con él al final del ciclo )
Keith Randall
16

traceroute - 10 caracteres

traceroute 

detalle

post#traceroute shot

Type escape sequence to abort.
Tracing the route to shot (1.1.4.2)

  1 pot (1.1.1.2) 40 msec 68 msec 24 msec
  2 hot (1.1.3.2) 16 msec 32 msec 24 msec
  3 shot (1.1.4.2) 52 msec *  92 msec

Los enrutadores están preconfigurados con OSPF habilitado y organizado de esta manera.

ingrese la descripción de la imagen aquí

Y sí, necesito 233614 enrutadores para admitir completamente todas las palabras. :-)


fuente
Muy inteligente pero fallas la regla de los 10 segundos. Le tomará más de 10 segundos configurar todos los enrutadores. :-) Cuál es la ruta desde: Zink -> Silicon
Martin York
@ Martin, por favor ignore el tiempo de configuración, es como construir un diccionario, jeje, rutas para Zink -> Silicon es zink->pink->pank->pani->panic->pinic->sinic->sinico->silico->siliconrealmente estoy tratando con el algoritmo Dijkstra (que se usa en OSPF) y puede encontrar esa ruta alrededor de 1s, lo haré publícalo en una publicación separada más tarde, una vez que haya jugado golf.
USTED
3

PHP - 886 689 644 612

Carga de diccionario:

<?php foreach(file('websters-dictionary') as $line) {
    $word = strtolower(trim($line));
    if (strlen($word) < 3) continue;
    $c[$word] = 1;
}

Código real (solo concat ambos):

list($d,$e)=explode(' ',strtolower(trim(`cat`)));$f=range(@a,@z);function w($a,&$g){global$c;if(isset($c[$a]))$g[]=$a;}$h[$d]=$b=@levenshtein;$i=new SplPriorityQueue;$i->insert($d,0);$j[$d]=0;$k[$d]=$b($d,$e);while($h){if(isset($c[$l=$i->extract()])){unset($h[$l],$c[$l]);if($l==$e){for(;$m=@$n[$o[]=$l];$l=$m);die(implode("\n",array_reverse($o)));}for($p=strlen($l),$g=array();$p--;){w(substr_replace($q=$l,"",$p,1),$g);foreach($f as$r){$q[$p]=$r;w($q,$g);w($r.$l,$g);w($l.$r,$g);}}foreach($g as$m){$s=$j[$l]+1;if(!isset($h[$m])||$s<$j[$m]){$n[$m]=$l;$i->insert($m,-(($k[$m]=$b($m,$e))+$j[$m]=$s));}$h[$m]=1;}}}

uso:

php puzzle.php <<< 'Zink Silicon'
# or
echo 'Zink Silicon'|php puzzle.php

Resultado:

zink
pink
pank
pani
panic
pinic
sinic
sinico
silico
silicon
(0.23s)

Esto debería ejecutarse en menos de 0.5 segundos para 'Zink Silicon', y menos de 1 segundo para la mayoría de los casos (a veces más tiempo cuando no existe una solución, pero aún así regresa).

Esto utiliza el algoritmo A * con distancia levenshtein para estimar los límites inferiores de las distancias.

Algunas pruebas interesantes:

  • vas arm-> vas bas bar barm arm(con una palabra más larga que inicio y fin)
  • oxy pom -> oxy poxy poy pom
  • regatta gyrally -> (ninguno, pero el script termina correctamente)
  • aal presolution -> +8 caracteres
  • lenticulated aal -> -9 caracteres
  • acarology lowness -> 46 saltos
  • caniniform lowness -> 51 saltos
  • cauliform lowness -> 52 saltos
  • overfoul lowness -> 54 saltos
  • dance facia -> algunas palabras en el camino tienen 4 caracteres más que ambos inicio / fin
usuario300
fuente
Prueba Zink Silicon
Martin York
Esto debería funcionar, ahora :-)
Arnaud Le Blanc
Encontraré una máquina más grande:PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 71 bytes)
Martin York
Acabas de llegar a la configuración de 128M memory_limit ;-) Pruébalo php -dmemory_limit=256M.
Arnaud Le Blanc
had->handno es un movimiento válido, solo puede agregar una letra al principio o al final. Lo mismo para vest->verst:-)
Arnaud Le Blanc
3

Pitón

Como no pude jugar golf en los códigos dijkstra para comprimir a unos pocos cientos de bytes, aquí hay una versión mía sin golf.

import sys, heapq, time

# dijkstra algorithm from 
# http://code.activestate.com/recipes/119466-dijkstras-algorithm-for-shortest-paths/
def dijkstra(G, start, end):
   def flatten(L):
      while len(L) > 0:
         yield L[0]
         L = L[1]

   q = [(0, start, ())]
   visited = set()
   while True:
      (cost, v1, path) = heapq.heappop(q)
      if v1 not in visited:
         visited.add(v1)
         if v1 == end:
            return list(flatten(path))[::-1] + [v1]
         path = (v1, path)
         for (v2, cost2) in G[v1].iteritems():
            if v2 not in visited:
               heapq.heappush(q, (cost + cost2, v2, path))

nodes = tuple(sys.argv[1:])

print "Generating connections,",
current_time = time.time()

words = set(x for x in open("websters-dictionary", "rb").read().lower().split() if 3 <= len(x) <= max(5, *[len(l)+1 for l in nodes]))

print len(words), "nodes found"

def error():
    sys.exit("Unreachable Route between '%s' and '%s'" % nodes)

if not all(node in words for node in nodes):
    error()

# following codes are modified version of
# http://norvig.com/spell-correct.html
alphabet = 'abcdefghijklmnopqrstuvwxyz'

def edits(word):
   splits = [(word[:i], word[i:]) for i in range(len(word) + 1)]
   deletes = [a + b[1:] for a, b in splits if b]
   replaces = [a + c + b[1:] for a, b in splits for c in alphabet if b]
   prepends = [c+word for c in alphabet]
   appends = [word+c for c in alphabet]
   return words & set(deletes + replaces + prepends + appends)

# Generate connections between nodes to pass to dijkstra algorithm
G = dict((x, dict((y, 1) for y in edits(x))) for x in words)

print "All connections generated, %0.2fs taken" % (time.time() - current_time)
current_time = time.time()

try:
    route = dijkstra(G, *nodes)
    print '\n'.join(route)
    print "%d hops, %0.2fs taken to search shortest path between '%s' & '%s'" % (len(route), time.time() - current_time, nodes[0], nodes[1])
except IndexError:
    error()

Pruebas

$ python codegolf-693.py post shot
Generating connections, 15930 nodes found
All connections generated, 2.09s taken
post
host
hot
shot
4 hops, 0.04s taken to search shortest path between 'post' & 'shot'

$ python codegolf-693.py zink silicon
Generating connections, 86565 nodes found
All connections generated, 13.91s taken
zink
pink
pank
pani
panic
pinic
sinic
sinico
silico
silicon
10 hops, 0.75s taken to search shortest path between 'zink' & 'silicon'

Se agregaron las pruebas de user300

$ python codegolf-693.py vas arm
Generating connections, 15930 nodes found
All connections generated, 2.06s taken
vas
bas
bam
aam
arm
5 hops, 0.07s taken to search shortest path between 'vas' & 'arm'

$ python codegolf-693.py oxy pom
Generating connections, 15930 nodes found
All connections generated, 2.05s taken
oxy
poxy
pox
pom
4 hops, 0.01s taken to search shortest path between 'oxy' & 'pom'

$ python codegolf-693.py regatta gyrally
Generating connections, 86565 nodes found
All connections generated, 13.95s taken
Unreachable Route between 'regatta' and 'gyrally'

Algo mas

$ python codegolf-693.py gap shrend
Generating connections, 56783 nodes found
All connections generated, 8.16s taken
gap
rap
crap
craw
crew
screw
shrew
shrewd
shrend
9 hops, 0.67s taken to search shortest path between 'gap' & 'shrend'

$ python codegolf-693.py guester overturn
Generating connections, 118828 nodes found
All connections generated, 19.63s taken
guester
guesten
gesten
geste
gest
gast
east
ease
erse
verse
verset
overset
oversee
overseed
oversend
oversand
overhand
overhard
overcard
overcare
overtare
overture
overturn
23 hops, 0.82s taken to search shortest path between 'guester' & 'overturn'

fuente
3 <= len(x) <= max(map(len, [nodea, nodeb]))¿está garantizado que el camino nunca atravesará una palabra más que las palabras de inicio y fin?
Arnaud Le Blanc
Tratar con oxy pom; camino más corto es oxy->poxy->poy->pom. También parece que permite permutaciones e inserciones en cualquier lugar, que no están permitidas :-)
Arnaud Le Blanc
@ user300, permutaciones fijas y partes de inserciones, copié y pegué demasiado, gracias ;-) y estoy estableciendo el límite inicial a 5 caracteres y permitiendo +1 más caracteres de inicio y finalización de palabras, avíseme si eso todavía es un problema. Gracias.
TU