125 votos

Algoritmo para generar un crucigrama

Dada una lista de palabras, ¿cómo las organizarías en una cuadrícula de crucigrama?

No tendría que ser como un crucigrama "correcto" que sea simétrico o algo por el estilo: básicamente simplemente mostrar una posición inicial y dirección para cada palabra.

65voto

nickf Puntos 185423

Se me ocurrió una solución que probablemente no sea la más eficiente, pero funciona lo suficientemente bien. Básicamente:

  1. Ordena todas las palabras por longitud, de forma descendente.
  2. Toma la primera palabra y colócala en el tablero.
  3. Toma la siguiente palabra.
  4. Busca a través de todas las palabras que ya están en el tablero y ve si hay alguna intersección posible (alguna letra en común) con esta palabra.
  5. Si hay una ubicación posible para esta palabra, recorre todas las palabras que están en el tablero y verifica si la nueva palabra interfiere.
  6. Si esta palabra no rompe el tablero, entonces colócala allí y ve al paso 3, de lo contrario, continúa buscando un lugar (paso 4).
  7. Continúa este ciclo hasta que todas las palabras estén colocadas o no se puedan colocar.

Esto hace un crucigrama funcional, aunque a menudo bastante pobre. Hubo varias modificaciones que hice a la receta básica anterior para obtener un mejor resultado.

  • Al final de generar un crucigrama, dale una puntuación basada en cuántas de las palabras fueron colocadas (cuantas más mejor), qué tan grande es el tablero (cuanto más pequeño mejor) y la relación entre altura y anchura (cuanto más cerca de 1 mejor). Genera varios crucigramas y luego compara sus puntuaciones y elige el mejor.
    • En lugar de ejecutar un número arbitrario de iteraciones, he decidido crear tantos crucigramas como sea posible en una cantidad arbitraria de tiempo. Si solo tienes una lista de palabras pequeña, entonces obtendrás docenas de posibles crucigramas en 5 segundos. Un crucigrama más grande solo se elegiría entre 5-6 posibilidades.
  • Cuando colocas una nueva palabra, en lugar de colocarla inmediatamente al encontrar una ubicación aceptable, dale a esa ubicación de la palabra una puntuación basada en cuánto aumenta el tamaño de la cuadrícula y cuántas intersecciones hay (idealmente querrías que cada palabra sea cruzada por 2-3 otras palabras). Lleva un registro de todas las posiciones y sus puntuaciones y luego elige la mejor.

24voto

Bryan Puntos 343

Acabo de escribir mi propio en Python recientemente. Puedes encontrarlo aquí: http://bryanhelmig.com/python-crossword-puzzle-generator/. No crea crucigramas densos al estilo del NYT, sino más bien del tipo que podrías encontrar en un libro de pasatiempos para niños.

A diferencia de algunos algoritmos que encontré que implementaban un método de fuerza bruta aleatorio para colocar palabras como algunos han sugerido, intenté implementar un enfoque de fuerza bruta ligeramente más inteligente en la colocación de palabras. Aquí está mi proceso:

  1. Crear una cuadrícula de cualquier tamaño y una lista de palabras.
  2. Barajar la lista de palabras y luego ordenar las palabras de más largas a más cortas.
  3. Colocar la primera y más larga palabra en la posición más a la izquierda arriba, 1,1 (vertical u horizontal).
  4. Pasar a la siguiente palabra, recorrer cada letra de la palabra y cada celda de la cuadrícula buscando coincidencias letra a letra.
  5. Cuando se encuentre una coincidencia, simplemente añadir esa posición a una lista de coordenadas sugeridas para esa palabra.
  6. Recorrer la lista de coordenadas sugeridas y "calificar" la colocación de la palabra según cuántas otras palabras cruce. Calificaciones de 0 indican una mala colocación (adyacente a palabras existentes) o que no hubo cruces de palabras.
  7. Volver al paso #4 hasta que la lista de palabras se haya agotado. Pase opcional.
  8. Deberíamos tener ahora un crucigrama, pero la calidad puede ser irregular debido a algunas de las colocaciones aleatorias. Por lo tanto, almacenamos este crucigrama y volvemos al paso #2. Si el siguiente crucigrama tiene más palabras colocadas en el tablero, reemplaza al crucigrama almacenado. Esto está limitado en tiempo (encontrar el mejor crucigrama en x segundos).

Al final, tendrás un crucigrama decente o un rompecabezas de búsqueda de palabras, ya que son prácticamente lo mismo. Tiende a funcionar bastante bien, pero avísame si tienes alguna sugerencia de mejora. Cuadrículas más grandes se ejecutan de manera exponencial más lenta; listas de palabras más grandes de manera lineal. Las listas de palabras más grandes también tienen una probabilidad mucho mayor de obtener mejores números de colocación de palabras.

20voto

paxdiablo Puntos 341644

En realidad escribí un programa generador de crucigramas hace unos diez años (era enigmático pero las mismas reglas se aplicarían para crucigramas normales).

Tenía una lista de palabras (y pistas asociadas) almacenadas en un archivo ordenadas por uso descendente hasta la fecha (para que las palabras menos usadas estuvieran en la parte superior del archivo). Se elegía un template, básicamente una máscara de bits que representaba los cuadrados negros y libres, al azar de un conjunto proporcionado por el cliente.

Luego, para cada palabra incompleta en el rompecabezas (básicamente encontrar el primer cuadrado en blanco y ver si el de la derecha (palabra horizontal) o el de abajo (palabra vertical) también estaba en blanco), se hacía una búsqueda en el archivo en busca de la primera palabra que encajara, teniendo en cuenta las letras ya en esa palabra. Si no había una palabra que pudiera encajar, simplemente se marcaba toda la palabra como incompleta y se pasaba a la siguiente.

Al final habría algunas palabras incompletas que el compilador tendría que completar (y agregar la palabra y una pista al archivo si así lo deseaba). Si no podían encontrar ninguna idea, podrían editar el crucigrama manualmente para cambiar las restricciones o simplemente solicitar una regeneración total.

Una vez que el archivo de palabras/pistas alcanzó cierto tamaño (y se agregaban 50-100 pistas al día para este cliente), rara vez hubo más de dos o tres correcciones manuales que debían hacerse para cada crucigrama.

9voto

Yogi Puntos 1083

¿Por qué no utilizar un enfoque probabilístico aleatorio para empezar? Comienza con una palabra, y luego elige repetidamente una palabra al azar e intenta encajarla en el estado actual del rompecabezas sin romper las restricciones de tamaño, etc. Si fallas, simplemente comienza de nuevo.

Te sorprenderá cuántas veces un enfoque de Monte Carlo como este funciona.

5voto

Eric Puntos 35647

Generaría dos números: Longitud y Puntuación de Scrabble. Supongamos que una puntuación baja de Scrabble significa que es más fácil unirse en (puntuaciones bajas = muchas letras comunes). Ordene la lista por longitud descendente y puntuación de Scrabble ascendente.

A continuación, simplemente vaya por la lista. Si la palabra no se cruza con una palabra existente (verifique contra cada palabra por su longitud y puntuación de Scrabble, respectivamente), entonces colóquela en la cola y verifique la siguiente palabra.

Repite esto y esto debería generar un crucigrama.

Por supuesto, estoy bastante seguro de que esto es O(n!) y no está garantizado que complete el crucigrama para ti, pero quizás alguien pueda mejorarlo.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X