J'ai trouvé une solution qui n'est probablement pas la plus efficace, mais qui fonctionne assez bien. Fondamentalement:
- Triez tous les mots par longueur, par ordre décroissant.
- Prenez le premier mot et placez-le sur le tableau.
- Prenez le mot suivant.
- Recherchez parmi tous les mots qui sont déjà sur le tableau et voyez s'il y a des intersections possibles (des lettres courantes) avec ce mot.
- S'il y a un emplacement possible pour ce mot, parcourez tous les mots qui se trouvent sur le tableau et vérifiez si le nouveau mot interfère.
- Si ce mot ne brise pas le tableau, placez-le là et passez à l'étape 3, sinon continuez à chercher un lieu (étape 4).
- Continuez cette boucle jusqu'à ce que tous les mots soient placés ou ne puissent pas être placés.
Cela fait des mots croisés fonctionnels, mais souvent assez médiocres. J'ai apporté un certain nombre de modifications à la recette de base ci-dessus pour obtenir un meilleur résultat.
- À la fin de la génération d'un mot croisé, attribuez-lui un score basé sur le nombre de mots placés (plus il y en a, mieux c'est), la taille du tableau (le plus petit sera le mieux) et le rapport entre la hauteur et la largeur (le plus proche à 1 le mieux). Générez un certain nombre de mots croisés, puis comparez leurs scores et choisissez le meilleur.
- Au lieu d'exécuter un nombre arbitraire d'itérations, j'ai décidé de créer autant de mots croisés que possible dans un laps de temps arbitraire. Si vous n'avez qu'une petite liste de mots, vous obtiendrez des dizaines de mots croisés possibles en 5 secondes. Un mot croisé plus grand ne peut être choisi que parmi 5 à 6 possibilités.
- Lorsque vous placez un nouveau mot, au lieu de le placer immédiatement après avoir trouvé un emplacement acceptable, attribuez à ce mot un score en fonction de l'augmentation de la taille de la grille et du nombre d'intersections (idéalement, vous voudriez que chaque mot soit traversé par 2-3 autres mots). Gardez une trace de toutes les positions et de leurs scores, puis choisissez la meilleure.
J'ai récemment écrit le mien en Python. Vous pouvez le trouver ici: http://bryanhelmig.com/python-crossword-puzzle-generator/ . Cela ne crée pas les mots croisés de style NYT dense, mais le style de mots croisés que vous pourriez trouver dans le livre de puzzle d'un enfant.
Contrairement à quelques algorithmes que j'ai découverts et qui implémentaient une méthode par force brute aléatoire pour placer des mots comme certains l'ont suggéré, j'ai essayé de mettre en œuvre une approche de force brute légèrement plus intelligente lors du placement des mots. Voici mon processus:
À la fin, vous avez un puzzle de mots croisés ou de recherche de mots décent, car ils sont à peu près les mêmes. Il a tendance à fonctionner plutôt bien, mais faites-moi savoir si vous avez des suggestions d'amélioration. Les réseaux plus grands fonctionnent exponentiellement plus lentement; de plus grandes listes de mots linéairement. Les listes de mots plus volumineuses ont également beaucoup plus de chances d'obtenir de meilleurs numéros de placement de mots.
la source
array.sort(key=f)
est stable, ce qui signifie (par exemple) que le simple tri d'une liste de mots alphabétique par longueur conserverait tous les mots de 8 lettres classés par ordre alphabétique.En fait, j'ai écrit un programme de génération de mots croisés il y a environ dix ans (c'était cryptique mais les mêmes règles s'appliqueraient pour les mots croisés normaux).
Il contenait une liste de mots (et des indices associés) stockés dans un fichier trié par utilisation décroissante à ce jour (de sorte que les mots les moins utilisés étaient en haut du fichier). Un modèle, essentiellement un masque de bits représentant les carrés noirs et libres, a été choisi au hasard dans un pool fourni par le client.
Ensuite, pour chaque mot non complet du puzzle (recherchez essentiellement le premier carré vide et voyez si celui à droite (à travers le mot) ou celui en dessous (mot en bas) est également vide), une recherche a été effectuée sur le fichier recherchant le premier mot qui correspondait, en tenant compte des lettres déjà présentes dans ce mot. S'il n'y avait pas de mot qui puisse convenir, vous venez de marquer le mot entier comme incomplet et de passer à autre chose.
À la fin, il y aurait des mots incomplets que le compilateur devrait remplir (et ajouter le mot et un indice au fichier si désiré). S'ils ne pouvaient pas venir avec des idées, ils pourraient modifier les mots croisés pour modifier les contraintes ou tout simplement demander manuellement une nouvelle génération totale.
Une fois que le fichier de mots / indices a atteint une certaine taille (et qu'il ajoutait 50 à 100 indices par jour pour ce client), il y avait rarement un cas de plus de deux ou trois corrections manuelles qui devaient être faites pour chaque mot croisé .
la source
Cet algorithme crée 50 mots croisés de flèches 6x9 denses en 60 secondes. Il utilise une base de données de mots (avec mot + astuces) et une base de données de tableaux (avec des tableaux préconfigurés).
Une plus grande base de données de mots réduit considérablement le temps de génération et certains types de tableaux sont plus difficiles à remplir! Les planches plus grandes nécessitent plus de temps pour être remplies correctement!
Exemple:
Carte 6x9 pré-configurée:
(# signifie un conseil dans une cellule,% signifie deux conseils dans une cellule, flèches non affichées)
Carte 6x9 générée:
Conseils [ligne, colonne]:
la source
Bien que ce soit une question plus ancienne, j'essaierai une réponse basée sur un travail similaire que j'ai effectué.
Il existe de nombreuses approches pour résoudre les problèmes de contraintes (qui appartiennent généralement à la classe de complexité NPC).
Ceci est lié à l'optimisation combinatoire et à la programmation par contraintes. Dans ce cas, les contraintes sont la géométrie du maillage et l'exigence que les mots soient uniques etc.
Les approches de randomisation / recuit peuvent également fonctionner (bien que dans le cadre approprié).
Une simplicité efficace pourrait bien être la sagesse ultime!
Les exigences étaient pour un compilateur de mots croisés plus ou moins complet et un constructeur (visuel WYSIWYG).
Laissant de côté la partie du constructeur WYSIWYG, le plan du compilateur était le suivant:
Charger les listes de mots disponibles (triées par longueur de mot, c'est-à-dire 2,3, .., 20)
Trouvez les espaces de mots (c'est-à-dire les mots de la grille) sur la grille construite par l'utilisateur (par exemple, mot à x, y de longueur L, horizontal ou vertical) (complexité O (N))
Calculer les points d'intersection des mots de la grille (qui doivent être remplis) (complexité O (N ^ 2))
Calculer les intersections des mots dans les listes de mots avec les différentes lettres de l'alphabet utilisé (cela permet de rechercher des mots correspondants en utilisant un modèle par exemple. Thèse Sik Cambon telle qu'utilisée par cwc ) (complexité O (WL * AL))
Les étapes .3 et .4 permettent d'effectuer cette tâche:
une. Les intersections des mots de la grille avec eux-mêmes permettent de créer un "modèle" pour essayer de trouver des correspondances dans la liste de mots associée des mots disponibles pour ce mot de la grille (en utilisant les lettres d'autres mots croisés avec ce mot qui sont déjà remplis à un certain étape de l'algorithme)
b. Les intersections des mots d'une liste de mots avec l'alphabet permettent de trouver des mots (candidats) correspondants qui correspondent à un "modèle" donné (par exemple 'A' en 1ère place et 'B' en 3ème place etc.)
Donc, avec ces structures de données implémentées, l'algorithme utilisé était comme ceci:
REMARQUE: si la grille et la base de données de mots sont constantes, les étapes précédentes ne peuvent être effectuées qu'une seule fois.
La première étape de l'algorithme est de sélectionner un emplacement de mots vide (mot de la grille) au hasard et de le remplir avec un mot candidat de sa liste de mots associée (la randomisation permet de produire différents solutons lors d'exécutions consécutives de l'algorithme) (complexité O (1) ou O ( N))
Pour chaque créneau de mots encore vide (qui ont des intersections avec des lots de mots déjà remplis), calculez un rapport de contrainte (cela peut varier, sth simple est le nombre de solutions disponibles à cette étape) et triez les lots de mots vides par ce rapport (complexité O (NlogN ) ou O (N))
Faites une boucle dans les espaces de mots vides calculés à l'étape précédente et essayez pour chacun d'entre eux un certain nombre de solutions annulées (en vous assurant que la "cohérence d'arc est conservée", c'est-à-dire que la grille a une solution après cette étape si ce mot est utilisé) et triez-les selon disponibilité maximale pour l'étape suivante (c'est-à-dire que l'étape suivante a un maximum de solutions possibles si ce mot est utilisé à ce moment-là à cet endroit, etc.) (complexité O (N * MaxCandidatesUsed))
Remplissez ce mot (marquez-le comme rempli et passez à l'étape 2)
Si aucun mot ne satisfait aux critères de l'étape .3, essayez de revenir en arrière vers une autre solution candidate d'une étape précédente (les critères peuvent varier ici) (complexité O (N))
Si un retour en arrière est trouvé, utilisez l'alternative et réinitialisez éventuellement tous les mots déjà remplis qui pourraient nécessiter une réinitialisation (marquez-les à nouveau comme non remplis) (complexité O (N))
Si aucun retour en arrière n'est trouvé, aucune solution ne peut être trouvée (au moins avec cette configuration, graine initiale etc.)
Sinon, lorsque tous les lots de mots sont remplis, vous avez une solution
Cet algorithme effectue une marche cohérente aléatoire de l'arbre de solution du problème. Si à un moment donné il y a une impasse, il fait un retour en arrière vers un nœud précédent et suit une autre route. Jusqu'à ce qu'une solution trouvée ou le nombre de candidats pour les différents nœuds soient épuisés.
La partie cohérence s'assure qu'une solution trouvée est bien une solution et la partie aléatoire permet de produire différentes solutions dans différentes exécutions et aussi en moyenne d'avoir de meilleures performances.
PS. tout cela (et d'autres) ont été implémentés en JavaScript pur (avec traitement parallèle et WYSIWYG)
PS2. L'algorithme peut être facilement parallélisé afin de produire plus d'une solution (différente) en même temps
J'espère que cela t'aides
la source
Pourquoi ne pas simplement utiliser une approche probabiliste aléatoire pour commencer. Commencez par un mot, puis choisissez à plusieurs reprises un mot au hasard et essayez de l'adapter à l'état actuel du puzzle sans casser les contraintes de taille etc. Si vous échouez, recommencez simplement.
Vous serez surpris de la fréquence à laquelle une approche de Monte Carlo comme celle-ci fonctionne.
la source
Voici un code JavaScript basé sur la réponse de nickf et le code Python de Bryan. Il suffit de le publier au cas où quelqu'un d'autre en aurait besoin dans js.
la source
Je générerais deux nombres: la longueur et le score au Scrabble. Supposons qu'un faible score au Scrabble signifie qu'il est plus facile de rejoindre (scores faibles = beaucoup de lettres courantes). Triez la liste par longueur décroissante et par score Scrabble croissant.
Ensuite, descendez simplement la liste. Si le mot ne croise pas avec un mot existant (vérifiez chaque mot par sa longueur et son score au Scrabble, respectivement), mettez-le dans la file d'attente et vérifiez le mot suivant.
Rincez et répétez, et cela devrait générer un mot croisé.
Bien sûr, je suis à peu près sûr que c'est O (n!) Et il n'est pas garanti de compléter les mots croisés pour vous, mais peut-être que quelqu'un peut l'améliorer.
la source
J'ai réfléchi à ce problème. Mon sentiment est que pour créer un mot croisé vraiment dense, vous ne pouvez pas espérer que votre liste de mots limitée suffira. Par conséquent, vous voudrez peut-être prendre un dictionnaire et le placer dans une structure de données "trie". Cela vous permettra de trouver facilement des mots qui remplissent les espaces à gauche. Dans un essai, il est assez efficace d'implémenter un parcours qui, par exemple, vous donne tous les mots de la forme "c? T".
Donc, ma pensée générale est la suivante: créer une sorte d'approche de force relativement brute comme certains l'ont décrit ici pour créer une croix de faible densité, et remplir les espaces avec des mots du dictionnaire.
Si quelqu'un d'autre a adopté cette approche, veuillez me le faire savoir.
la source
Je jouais avec le moteur de générateur de mots croisés, et j'ai trouvé que c'était le plus important:
0.
!/usr/bin/python
une.
allwords.sort(key=len, reverse=True)
b. Créez un élément / objet comme un curseur qui se déplacera autour de la matrice pour une orientation facile à moins que vous ne vouliez itérer par choix aléatoire plus tard.
la première, prenez la première paire et placez-les en travers et en bas de 0,0; stockez le premier comme notre «leader» actuel de mots croisés.
déplacer le curseur par ordre diagonal ou aléatoire avec une plus grande probabilité diagonale vers la prochaine cellule vide
itérer sur les mots comme et utiliser la longueur de l'espace libre pour définir la longueur maximale des mots:
temp=[] for w_size in range( len( w_space ), 2, -1 ) : # t for w in [ word for word in allwords if len(word) == w_size ] : # if w not in temp and putTheWord( w, w_space ) : # temp.append( w )
pour comparer le mot à l'espace libre, j'ai utilisé, c'est-à-dire:
après chaque mot utilisé avec succès, changez de direction. Bouclez alors que toutes les cellules sont remplies OU vous manquez de mots OU par limite d'itérations alors:
# CHANGE ALL WORDS LIST inexOf1stWord = allwords.index( leading_w ) allwords = allwords[:inexOf1stWord+1][:] + allwords[inexOf1stWord+1:][:]
... et répétez de nouveaux mots croisés.
Faites le système de notation par facilité de remplissage et quelques calculs d'estimation. Donnez le score pour le mot croisé actuel et restreignez le choix ultérieur en l'ajoutant à la liste des mots croisés créés si le score est satisfait par votre système de notation.
Après la première session d'itération, parcourez à nouveau la liste des mots croisés créés pour terminer le travail.
En utilisant plus de paramètres, la vitesse peut être améliorée par un facteur énorme.
la source
J'obtiendrais un index de chaque lettre utilisée par chaque mot pour connaître les croix possibles. Ensuite, je choisirais le mot le plus grand et l'utiliserais comme base. Sélectionnez le prochain grand et traversez-le. Rincez et répétez. C'est probablement un problème NP.
Une autre idée consiste à créer un algorithme génétique où la métrique de force est le nombre de mots que vous pouvez mettre dans la grille.
La partie difficile que je trouve est de savoir quand connaître une certaine liste ne peut pas être franchie.
la source
Celui-ci apparaît comme un projet dans le cours AI CS50 de Harvard. L'idée est de formuler le problème de génération de mots croisés comme un problème de satisfaction de contraintes et de le résoudre par retour arrière avec différentes heuristiques pour réduire l'espace de recherche.
Pour commencer, nous avons besoin de quelques fichiers d'entrée:
»
»
Un vocabulaire d'entrée (liste de mots / dictionnaire) à partir duquel les mots candidats seront choisis (comme celui illustré ci-dessous).
a abandon ability able abortion about above abroad absence absolute absolutely ...
Maintenant, le CSP est défini et doit être résolu comme suit:
Ce qui suit montre la sortie obtenue à l'aide d'une implémentation de l'algorithme de résolution CSP:
»
L'animation suivante montre les étapes de retour en arrière:
En voici un autre avec une liste de mots en langue Bangla (bengali):
la source
J'ai codé une solution JavaScript / jQuery à ce problème:
Exemple de démonstration: http://www.earthfluent.com/crossword-puzzle-demo.html
Code source: https://github.com/HoldOffHunger/jquery-crossword-puzzle-generator
L'intention de l'algorithme que j'ai utilisé:
Je décrirai l'algorithme que j'ai utilisé:
Regroupez les mots selon ceux qui partagent une lettre commune.
À partir de ces groupes, créez des ensembles d'une nouvelle structure de données ("blocs de mots"), qui est un mot principal (qui traverse tous les autres mots), puis les autres mots (qui traversent le mot principal).
Commencez le puzzle de mots croisés avec le tout premier de ces blocs de mots dans la position tout en haut à gauche du puzzle de mots croisés.
Pour le reste des blocs de mots, en partant de la position la plus en bas à droite du mot croisé, déplacez-vous vers le haut et vers la gauche, jusqu'à ce qu'il n'y ait plus d'emplacements disponibles à remplir. S'il y a plus de colonnes vides vers le haut que vers la gauche, déplacez-vous vers le haut et vice versa.
la source
var crosswords = generateCrosswordBlockSources(puzzlewords);
. Consignez simplement cette valeur sur la console. N'oubliez pas, il y a un "cheat-mode" dans le jeu, où vous pouvez simplement cliquer sur "Révéler la réponse", pour obtenir la valeur immédiatement.