Gagnant trouvé
Il semble que nous ayons un gagnant! À moins que quiconque ne prévoie de contester le solveur Sudoku le plus rapide au monde, l'utilisateur 53x15 gagne avec le solveur incroyablement rapide Tdoku. Pour tous ceux qui travaillent encore sur leurs solveurs, je vais toujours comparer les nouvelles soumissions quand j'en aurai le temps.
Le défi
Le but d'un jeu de Sudoku est de remplir le tableau avec les chiffres 1-9, un dans chaque cellule, de telle sorte que chaque ligne, colonne et case ne contienne chaque numéro qu'une seule fois. Un aspect très important d'un puzzle Sudoku est qu'il ne devrait y avoir qu'une seule solution valide.
Le but de ce défi est simple, vous devez résoudre un ensemble de puzzles Sudoku le plus rapidement possible. Cependant, vous ne résoudrez pas n'importe quel vieux Sudoku, vous résoudrez les puzzles de Sudoku les plus difficiles qui existent, les Sudokus à 17 indices. Voici un exemple:
Règles
Langue
Vous êtes libre d'utiliser n'importe quelle langue. Si je n'ai pas de compilateur installé pour votre langue, vous devriez être en mesure de fournir un ensemble d'instructions de ligne de commande nécessaires pour installer un environnement dans lequel votre script peut être exécuté sous Linux .
Machine de référence
La référence sera exécutée sur un Dell XPS 9560, Intel Core i7-7700HQ 2,8 GHz (3,8 GHz boost) 4 cœurs, 8 threads, 16 Go de RAM. GTX 1050 4GB. La machine exécute Ubuntu 19.04. Voici la uname
sortie, pour toute personne intéressée.
Linux 5.0.0-25-generic #26-Ubuntu SMP Thu Aug 1 12:04:58 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
Contribution
L'entrée sera donnée sous forme de fichier. Il peut être trouvé ici . Le fichier contient 49151 puzzles Sudoku. La première ligne du fichier est le nombre de puzzles, et chaque ligne qui suit est de 81 caractères et représente un puzzle. Les cellules inconnues le sont 0
et les cellules connues le sont 1-9
.
Votre programme devrait pouvoir prendre le nom de fichier comme argument, ou avoir l'entrée de fichier depuis STDIN , pour faciliter la vérification manuelle de votre solution. Veuillez inclure une instruction sur la façon dont votre programme prend des données.
Calendrier / notation
À partir des discussions dans les commentaires et de quelques réflexions, les critères de notation ont été modifiés pour correspondre à la durée de l'ensemble de votre programme. Votre programme devrait produire le fichier de sortie avec le hachage correct même pendant la notation officielle. Cela n'interfère avec aucune solution existante et ne change pas le classement tel qu'il est actuellement. Toute réflexion sur le système de notation est appréciée.
Si deux solutions ont des scores similaires pour des runs individuels, je lancerai plusieurs benchmarks, et le temps moyen sera le score final. Si les scores moyens diffèrent de moins de 2%, je considérerai cela comme un match nul.
Si l'exécution de votre solution prend plus d'une heure, elle ne sera pas officiellement notée. Dans ces cas, vous êtes responsable de signaler la machine sur laquelle il a fonctionné et votre score. Pour un solveur optimisé, cela ne devrait pas être un problème.
EDIT : Il a été porté à mon attention que s'il est difficile, le problème posé n'est pas le plus difficile qui soit. Si le temps est disponible, je vais essayer de comparer les solutions présentées ici par rapport à l'ensemble de casse-tête plus difficile, et ajouter le score à chaque soumission. Cependant, ce ne sera pas un score officiel, et c'est juste pour le plaisir.
Vérification
Votre solution sera vérifiée par une somme de contrôle MD5 / SHA256. Votre script devrait être capable de générer un fichier contenant tous les puzzles et leurs solutions. Cependant, le fichier sera également inspecté manuellement, alors n'essayez pas d'obtenir une collision de hachage. Votre fichier de sortie doit correspondre:
MD5: 41704fd7d8fd0723a45ffbb2dbbfa488
SHA256:0bc8dda364db7b99f389b42383e37b411d9fa022204d124cb3c8959eba252f05
Le fichier sera au format:
<num_puzzles>
<unsolved_puzzle#1>,<solved_puzzle#1>
<unsolved_puzzle#2>,<solved_puzzle#2>
...
<unsolved_puzzle#n>,<solved_puzzle#n>
avec une seule nouvelle ligne de fin.
Ce qui n'est pas autorisé
Vous n'êtes en aucun cas autorisé à coder en dur les solutions . Votre algorithme devrait être applicable sur n'importe quel jeu de puzzles Sudoku, à la fois Sudokus facile et plus difficile. Cependant, c'est très bien si votre solution est lente pour des puzzles plus faciles.
Vous n'êtes pas autorisé à avoir un programme non déterministe . Vous êtes autorisé à utiliser un générateur de nombres aléatoires, mais la valeur de départ du générateur doit être fixe. Cette règle vise à garantir que les mesures sont plus précises et présentent moins de variance. (Merci à Peter Taylor pour le conseil)
Vous n'êtes pas autorisé à utiliser des ressources externes ou des requêtes Web pendant l'exécution de votre programme. Tout devrait être autonome. Cela ne s'applique pas aux bibliothèques et packages installés, qui sont autorisés.
Autre info
Si vous souhaitez qu'un autre ensemble de test vérifie votre solution, voici 10000 Sudokus plus faciles . Voici leurs solutions .
MD5: 3cb465ef6077c4fcab5bd6ae3bc50d62
SHA256:0bc8dda364db7b99f389b42383e37b411d9fa022204d124cb3c8959eba252f05
Si vous avez des questions, n'hésitez pas à me les poser, et j'essaierai de clarifier tout malentendu.
Réponses:
C ++ - Score officiel de 0.201s
L'utilisation de Tdoku ( code ; design ; benchmarks ) donne ces résultats:
Tdoku a été optimisé pour les instances de Sudoku difficiles. Mais notez, contrairement à l'énoncé du problème, que 17 énigmes sont loin d'être les Sudoku les plus difficiles. En fait, ils sont parmi les plus faciles, la majorité n'exigeant aucun retour en arrière. Voir certains des autres jeux de données de référence dans le projet Tdoku pour les puzzles qui sont réellement difficiles.
Notez également que si Tdoku est le solveur le plus rapide que je connaisse pour les puzzles difficiles, ce n'est pas le plus rapide pour 17 puzzles d'indice. Pour ceux-ci, je pense que le plus rapide est ce projet de rouille , un dérivé de JCZSolve, qui a été optimisé pour 17 puzzles d'indice pendant le développement. Selon la plate-forme, il peut être 5 à 25% plus rapide que Tdoku pour ces puzzles.
la source
Node.js ,
8.231s6.735s score officielPrend le nom de fichier comme argument. Le fichier d'entrée peut déjà contenir les solutions dans le format décrit dans le défi, auquel cas le programme les comparera avec ses propres solutions.
Les résultats sont enregistrés dans 'sudoku.log' .
Code
Exemple de sortie
Testé sur un Intel Core i7 7500U à 2,70 GHz.
la source
Python 3 (avec dlx ) 4min 46.870s score officiel
(single core i7-3610QM ici)
Évidemment battable avec un langage compilé comme C, et en utilisant le threading, mais c'est un début ...
sudoku
est un module que j'ai placé sur github (copié en bas de cet article) qui utilisedlx
sous le capot.Usage
sudoku.py
quelque part sur votre chemin (à partir du lien git hub ou copiez-le ci-dessous)testSolver.py
quelque part sur votre cheminSi nécessaire, canalisez la sortie requise dans la spécification de défi vers un fichier:
sudoku.py (oui, il y a des fonctionnalités supplémentaires ici autres que la résolution)
la source
Python 3 + Z3 - 10min 45.657s score officiel
environ 1000 sur mon ordinateur portable.
Installer la dépendance
Courir
Je ne sais pas comment améliorer ses performances, car il vient de se résoudre comme par magie ...
la source
C -
2.228s1.690s score officielbasé sur @ Arnauld
compiler et exécuter:
la source
C - 12min 28.374s score officiel
fonctionne sur environ
30m15m sur mon i5-7200U et produit le hachage md5 correctcompiler (de préférence avec clang v6) et exécuter:
la source
memcpy
là-dedans et une récurrence en cours. Je vais essayer de le vérifier aujourd'hui.Java - 4.056s score officiel
L'idée principale est de ne jamais allouer de mémoire lorsqu'elle n'est pas nécessaire. La seule exception concerne les primitives, qui devraient de toute façon être optimisées par le compilateur. Tout le reste est stocké sous forme de masques et de tableaux d'opérations effectués à chaque étape, qui peuvent être annulés lorsque l'étape de récursivité est terminée.
Environ la moitié de tous les sudokus sont résolus complètement sans retour en arrière, mais si je pousse ce nombre plus haut, le temps global semble être plus lent. Je prévois de réécrire cela en C ++ et d'optimiser encore plus, mais ce solveur devient un monstre.
Je voulais implémenter autant de cache que possible, ce qui entraînait certains problèmes. Par exemple, s'il y a deux cellules sur la même ligne qui ne peuvent avoir que le nombre 6, alors nous avons atteint un cas impossible et devons revenir au retour arrière. Mais comme j'ai calculé toutes les options en un seul balayage, puis placé des nombres dans des cellules avec une seule possibilité, je n'ai pas vérifié que j'avais placé un nombre dans la même ligne juste avant. Cela a conduit à des solutions impossibles.
Avec tout ce qui est contenu dans les tableaux définis en haut, l'utilisation de la mémoire du solveur réel est d'environ 216 Ko. La partie principale de l'utilisation de la mémoire provient du tableau contenant tous les puzzles et des gestionnaires d'E / S en Java.
EDIT : J'ai maintenant une version qui est traduite en C ++, mais ce n'est pas beaucoup plus rapide. Le temps officiel est d'environ 3,5 secondes, ce qui n'est pas une énorme amélioration. Je pense que le principal problème avec mon implémentation est que je garde mes masques sous forme de tableaux plutôt que de masques de bit. J'essaierai d'analyser la solution d'Arnauld pour voir ce qui peut être fait pour l'améliorer.
la source
C ++ avec Minisat (2.2.1-5) - score officiel de 11.735s
C'est loin d'être aussi rapide qu'un algorithme spécialisé, mais c'est une approche différente, un point de référence intéressant et facile à comprendre.
$ clang ++ -o résoudre -lminisat solver_minisat.cc
la source