# Autour des Sudoku Diverses variations autour des Sudoku. ## Licence Tous les documents se trouvent ici avec la licence [![Creative Commons CC BY-NC-SA](images/cc-by-nc-sa.png)](https://creativecommons.org/licenses/by-nc-sa/4.0/). ## Description des fichiers * `sudoku_grid.py` : module définissant une classe `SudokuGrid` pour représenter les grilles de Sudoku. * `sudoku_solver.py` : module définissant une fonction `solve` pour la résolution des grilles de Sudoku. * `sudoku_mondrian.py` : module permettant de produire des images représentant des grilles de Sudoku colorées « à la Mondrian ». * `main1.py` : script de résolution d'une grille décrite en argument sur la ligne de commande. * `main2.py` : script de résolution d'une grille contenue dans un fichier. Les solutions sont affichées dans le terminal. * `main3.py` : script de résolution de toutes les grilles contenues dans un fichier. Les solutions sont inscrites dans un fichier. * `main4.py` : script de résolution d'une grille décrite sur la ligne de commande, et qui produit une image représentant la recherche des solutions. * `main5.py` : scripy de résolution d'une grille décrite sur la ligne de commande, qui visualise le remplissage progressif de la grille. * `main6.py` : script produisant une représentation « à la Mondrian » d'une grille décrite sur la ligne de commande. * `bdd/sudokus.bdd` : un fichier texte contenant la description de 5000 grilles de Sudoku ayant toutes une seule solution. * `bdd/sudoku17.bdd` : un fichier texte contenant la description de 49151 grilles de Sudoku n'ayant que 17 cases remplis et ayant toutes une seule solution. ## Solveurs de Sudoku ### Exemples d'utilisation Tous les exemples qui suivent s'exécutent dans un terminal de commandes (shell). Ils ont tous été testés sur une machine Linux (Debian). Dans les exemples qui suivent, le symbole `$` désigne le prompt du terminal. Et les fichiers `main?.py` sont supposés avoir le droit d'exécution (si ce n'est pas le cas, il faut remplacer `./main?.py` par `python3 main?.py`. #### Résoudre une grille de Sudoku décrite sur la ligne de commande Avec le script `main1.py` on peut résoudre toute grille de Sudoku décrite sur la ligne de commande. Une grille de Sudoku est décrite sur la ligne de commande par une succession de 81 caractères compris entre `0` et `9` (`0` pour une case vide). Les neuf premiers caractères représentent la première ligne de la grille, les neuf suivants la deuxième ligne, etc ... À titre d'exemples, avec la grille +-------+-------+-------+ | 9 . 6 | . 2 8 | . . 3 | | . 4 . | 5 . . | . . 1 | | . 8 . | 9 . . | . 4 . | +-------+-------+-------+ | 6 . . | . . . | . 7 . | | . . 8 | 2 . 6 | 9 . . | | . 3 . | . . . | . . 5 | +-------+-------+-------+ | . 5 . | . . 3 | . 6 . | | 1 . . | . . 2 | . 8 . | | 2 . . | 8 7 . | 5 . . | +-------+-------+-------+ on obtient une seule solution $ ./main1.py 906028003040500001080900040600000070008206900030000005050003060100002080200870500 Sudoku to solve +-------+-------+-------+ | 9 . 6 | . 2 8 | . . 3 | | . 4 . | 5 . . | . . 1 | | . 8 . | 9 . . | . 4 . | +-------+-------+-------+ | 6 . . | . . . | . 7 . | | . . 8 | 2 . 6 | 9 . . | | . 3 . | . . . | . . 5 | +-------+-------+-------+ | . 5 . | . . 3 | . 6 . | | 1 . . | . . 2 | . 8 . | | 2 . . | 8 7 . | 5 . . | +-------+-------+-------+ Number of solution(s): 1 -- Solution 1 +-------+-------+-------+ | 9 1 6 | 4 2 8 | 7 5 3 | | 3 4 2 | 5 6 7 | 8 9 1 | | 7 8 5 | 9 3 1 | 2 4 6 | +-------+-------+-------+ | 6 2 9 | 3 4 5 | 1 7 8 | | 5 7 8 | 2 1 6 | 9 3 4 | | 4 3 1 | 7 8 9 | 6 2 5 | +-------+-------+-------+ | 8 5 7 | 1 9 3 | 4 6 2 | | 1 9 4 | 6 5 2 | 3 8 7 | | 2 6 3 | 8 7 4 | 5 1 9 | +-------+-------+-------+ -- Et avec la grille +-------+-------+-------+ | 9 . 6 | . 2 8 | . . 3 | | . 4 . | 5 . . | . . 1 | | . 8 . | 9 . . | . 4 . | +-------+-------+-------+ | 6 . . | . . . | . 7 . | | . . 8 | 2 . 6 | 9 . . | | . 3 . | . . . | . . 5 | +-------+-------+-------+ | . 5 . | . . 3 | . 6 . | | 1 . . | . . 2 | . 8 . | | 2 . . | 8 7 . | . . . | +-------+-------+-------+ on obtient deux solutions $ ./main1.py 906028003040500001080900040600000070008206900030000005050003060100002080200870000 Sudoku to solve +-------+-------+-------+ | 9 . 6 | . 2 8 | . . 3 | | . 4 . | 5 . . | . . 1 | | . 8 . | 9 . . | . 4 . | +-------+-------+-------+ | 6 . . | . . . | . 7 . | | . . 8 | 2 . 6 | 9 . . | | . 3 . | . . . | . . 5 | +-------+-------+-------+ | . 5 . | . . 3 | . 6 . | | 1 . . | . . 2 | . 8 . | | 2 . . | 8 7 . | . . . | +-------+-------+-------+ Number of solution(s): 2 -- Solution 1 +-------+-------+-------+ | 9 1 6 | 4 2 8 | 7 5 3 | | 3 4 2 | 5 6 7 | 8 9 1 | | 7 8 5 | 9 3 1 | 2 4 6 | +-------+-------+-------+ | 6 2 9 | 3 4 5 | 1 7 8 | | 5 7 8 | 2 1 6 | 9 3 4 | | 4 3 1 | 7 8 9 | 6 2 5 | +-------+-------+-------+ | 8 5 7 | 1 9 3 | 4 6 2 | | 1 9 4 | 6 5 2 | 3 8 7 | | 2 6 3 | 8 7 4 | 5 1 9 | +-------+-------+-------+ -- Solution 2 +-------+-------+-------+ | 9 1 6 | 4 2 8 | 7 5 3 | | 3 4 2 | 5 6 7 | 8 9 1 | | 7 8 5 | 9 3 1 | 2 4 6 | +-------+-------+-------+ | 6 2 9 | 3 5 4 | 1 7 8 | | 5 7 8 | 2 1 6 | 9 3 4 | | 4 3 1 | 7 8 9 | 6 2 5 | +-------+-------+-------+ | 8 5 7 | 1 9 3 | 4 6 2 | | 1 9 3 | 6 4 2 | 5 8 7 | | 2 6 4 | 8 7 5 | 3 1 9 | +-------+-------+-------+ -- Enfin avec la grille +-------+-------+-------+ | 9 7 6 | . 2 8 | . . 3 | | . 4 . | 5 . . | . . 1 | | . 8 . | 9 . . | . 4 . | +-------+-------+-------+ | 6 . . | . . . | . 7 . | | . . 8 | 2 . 6 | 9 . . | | . 3 . | . . . | . . 5 | +-------+-------+-------+ | . 5 . | . . 3 | . 6 . | | 1 . . | . . 2 | . 8 . | | 2 . . | 8 7 . | 5 . . | +-------+-------+-------+ on n'obtient aucune solution $ ./main1.py 976028003040500001080900040600000070008206900030000005050003060100002080200870500 Sudoku to solve +-------+-------+-------+ | 9 7 6 | . 2 8 | . . 3 | | . 4 . | 5 . . | . . 1 | | . 8 . | 9 . . | . 4 . | +-------+-------+-------+ | 6 . . | . . . | . 7 . | | . . 8 | 2 . 6 | 9 . . | | . 3 . | . . . | . . 5 | +-------+-------+-------+ | . 5 . | . . 3 | . 6 . | | 1 . . | . . 2 | . 8 . | | 2 . . | 8 7 . | 5 . . | +-------+-------+-------+ Number of solution(s): 0 -- #### Résoudre une grille de Sudoku décrite dans un fichier texte Les grilles de Sudoku peuvent être décrites dans des fichiers texte. C'est le cas des deux fichiers `bdd/sudokus.bdd` et `bdd/sudoku17.bdd` qui contiennent chacun plusieurs milliers de grilles de Sudoku. Ces grilles sont décrites comme précédemment par des chaînes de 81 caractères compris entre `0` et `9`. Une description peut être précédée par un `:` et dans ce cas les caractères qui précèdent sont ignorés. Voici comment résoudre la première grille du fichier `bdd/sudokus.bdd` $ ./main2.py bdd/sudokus.bdd 0 Sudoku to solve +-------+-------+-------+ | 4 9 . | . . 1 | . . 7 | | . . . | . 4 5 | . 3 . | | 3 8 2 | 6 . . | . 5 . | +-------+-------+-------+ | . . 3 | . 7 . | 4 . 1 | | 8 . . | 9 . 2 | . . 5 | | 9 . 7 | . 3 . | 6 . . | +-------+-------+-------+ | . 3 . | . . 6 | 5 2 9 | | . 2 . | 8 5 . | . . . | | 5 . . | 7 . . | . 1 3 | +-------+-------+-------+ Number of solution(s): 1 -- Solution 1 +-------+-------+-------+ | 4 9 5 | 3 8 1 | 2 6 7 | | 6 7 1 | 2 4 5 | 9 3 8 | | 3 8 2 | 6 9 7 | 1 5 4 | +-------+-------+-------+ | 2 6 3 | 5 7 8 | 4 9 1 | | 8 1 4 | 9 6 2 | 3 7 5 | | 9 5 7 | 1 3 4 | 6 8 2 | +-------+-------+-------+ | 7 3 8 | 4 1 6 | 5 2 9 | | 1 2 9 | 8 5 3 | 7 4 6 | | 5 4 6 | 7 2 9 | 8 1 3 | +-------+-------+-------+ -- #### Résoudre toutes les grilles décrites dans un fichier Le script `main3.py` permet de résoudre toutes les grilles décrites dans un fichier dont on donne le nom dans la ligne de commandes. $ ./main3.py bdd/sudokus.bdd L'exécution de cette commande n'affiche rien. Elle se contente de produire un fichier dont le nom est celui passé en argument suivi de l'extension `.sol`. Chaque ligne de ce fichier contient 1. les 81 caractères de la grille d'origine (avec éventuellement quelques mentions qui la précèdent) suivis d'un `:` ; 2. le caractère `y` si la solution est unique ou le caractère `n` s'il n'y a aucune ou plus d'une solution ; 3. les solutions séparées par des `:`. Voici les trois premières lignes du fichier `bdd/sudokus.bdd.sol` produit par la commande précédente : easy:490001007000045030382600050003070401800902005907030600030006529020850000500700013:y:495381267671245938382697154263578491814962375957134682738416529129853746546729813 fiendish:020500730000490050500000000019207005060000070400908120000000006080029000096005040:y:921586734637491258548372691819237465263154879475968123152743986384629517796815342 hard:050008460004000038000030107000920003020000050700086000208090000460000900015700080:y:352178469174269538896435127581924673629317854743586291238691745467853912915742386 Toutes les grilles sont résolues #### Visualiser la recherche de solution avec le script `main4.py` Pour utiliser ce script il est supposé que la suite logicielle [graphviz](https://graphviz.org/) est installée. Le script `main4.py` permet de produire une image représentant l'arbre de recherche des solutions parcouru par l'algorithme de résolution mis en œuvre dans le module `sudoku_solver`. Son utilisation nécessite deux arguments sur la ligne de commande : 1. une chaîne de 81 caractères représentant la grille à résoudre 2. un nom pour les deux fichiers qui seront produits. Ce nom sera automatiquement complété de l'extension `.dot` pour l'un de ces deux fichiers qui contiendra une description de l'arbre dans le langage de description de graphes de `graphviz`. L'autre fichier qui aura un nom complété de l'extension `.png` contiendra une image au format PNG de cet arbre. Voici ce qu'on obtient en reprenant les trois exemples précédents. Exemple 1 $ ./main4.py 906028003040500001080900040600000070008206900030000005050003060100002080200870500 images/arbre_exple1 Sudoku to solve +-------+-------+-------+ | 9 . 6 | . 2 8 | . . 3 | | . 4 . | 5 . . | . . 1 | | . 8 . | 9 . . | . 4 . | +-------+-------+-------+ | 6 . . | . . . | . 7 . | | . . 8 | 2 . 6 | 9 . . | | . 3 . | . . . | . . 5 | +-------+-------+-------+ | . 5 . | . . 3 | . 6 . | | 1 . . | . . 2 | . 8 . | | 2 . . | 8 7 . | 5 . . | +-------+-------+-------+ Number of solution(s): 1 -- Solution 1 +-------+-------+-------+ | 9 1 6 | 4 2 8 | 7 5 3 | | 3 4 2 | 5 6 7 | 8 9 1 | | 7 8 5 | 9 3 1 | 2 4 6 | +-------+-------+-------+ | 6 2 9 | 3 4 5 | 1 7 8 | | 5 7 8 | 2 1 6 | 9 3 4 | | 4 3 1 | 7 8 9 | 6 2 5 | +-------+-------+-------+ | 8 5 7 | 1 9 3 | 4 6 2 | | 1 9 4 | 6 5 2 | 3 8 7 | | 2 6 3 | 8 7 4 | 5 1 9 | +-------+-------+-------+ -- Et voici l'image produite qui montre un arbre filiforme (signe que le sudoku est facile). La grille initiale est marquée en rouge en haut, et l'unique solution est marquée en vert en bas. Le premier nœud accessible depuis le nœud rouge de départ porte la mention `('7', 6, 0)`. Cela signifie que lors de la résolution, la première case remplie a été celle de coordonnée (6, 0) (septième colonne, première ligne) et qu'on y a placé le chiffre 7. ![arbre de résolution de l'exemple 1](images/arbre_exple1.png) Exemple 2 $ ./main4.py 906028003040500001080900040600000070008206900030000005050003060100002080200870000 images/arbre_exple2 Sudoku to solve +-------+-------+-------+ | 9 . 6 | . 2 8 | . . 3 | | . 4 . | 5 . . | . . 1 | | . 8 . | 9 . . | . 4 . | +-------+-------+-------+ | 6 . . | . . . | . 7 . | | . . 8 | 2 . 6 | 9 . . | | . 3 . | . . . | . . 5 | +-------+-------+-------+ | . 5 . | . . 3 | . 6 . | | 1 . . | . . 2 | . 8 . | | 2 . . | 8 7 . | . . . | +-------+-------+-------+ Number of solution(s): 2 -- Solution 1 +-------+-------+-------+ | 9 1 6 | 4 2 8 | 7 5 3 | | 3 4 2 | 5 6 7 | 8 9 1 | | 7 8 5 | 9 3 1 | 2 4 6 | +-------+-------+-------+ | 6 2 9 | 3 4 5 | 1 7 8 | | 5 7 8 | 2 1 6 | 9 3 4 | | 4 3 1 | 7 8 9 | 6 2 5 | +-------+-------+-------+ | 8 5 7 | 1 9 3 | 4 6 2 | | 1 9 4 | 6 5 2 | 3 8 7 | | 2 6 3 | 8 7 4 | 5 1 9 | +-------+-------+-------+ -- Solution 2 +-------+-------+-------+ | 9 1 6 | 4 2 8 | 7 5 3 | | 3 4 2 | 5 6 7 | 8 9 1 | | 7 8 5 | 9 3 1 | 2 4 6 | +-------+-------+-------+ | 6 2 9 | 3 5 4 | 1 7 8 | | 5 7 8 | 2 1 6 | 9 3 4 | | 4 3 1 | 7 8 9 | 6 2 5 | +-------+-------+-------+ | 8 5 7 | 1 9 3 | 4 6 2 | | 1 9 3 | 6 4 2 | 5 8 7 | | 2 6 4 | 8 7 5 | 3 1 9 | +-------+-------+-------+ L'image produite montre que pendant un certain nombre d'étapes le parcours a été linéaire (aucun choix), puis une alternative s'est révélée chaque branche de cette alternative aboutissant à une solution, d'où les deux nœuds verts. ![arbre de résolution de l'exemple 2](images/arbre_exple2.png) Exemple 3 $ ./main4.py 976028003040500001080900040600000070008206900030000005050003060100002080200870500 images/arbre_exple3 Sudoku to solve +-------+-------+-------+ | 9 7 6 | . 2 8 | . . 3 | | . 4 . | 5 . . | . . 1 | | . 8 . | 9 . . | . 4 . | +-------+-------+-------+ | 6 . . | . . . | . 7 . | | . . 8 | 2 . 6 | 9 . . | | . 3 . | . . . | . . 5 | +-------+-------+-------+ | . 5 . | . . 3 | . 6 . | | 1 . . | . . 2 | . 8 . | | 2 . . | 8 7 . | 5 . . | +-------+-------+-------+ Number of solution(s): 0 -- L'image produite montre un arbre ne comprenant qu'un seul nœud dont aucun vert. Cela provient du fait qu'une case impossible à remplir en respectant les contraintes a été découverte : la case (0, 6). ![arbre de résolution de l'exemple 3](images/arbre_exple3.png) Avec la grille ci-dessous (grille de la ligne 43 du fichier `bdd/sudokus.bdd`) +-------+-------+-------+ | 2 . . | . 5 . | 8 4 . | | . 1 . | 7 9 . | 5 . . | | . . . | . . 4 | . . . | +-------+-------+-------+ | . 8 1 | . . . | 2 . 9 | | 3 . . | . . . | . . 5 | | 7 . 6 | . . . | 3 1 . | +-------+-------+-------+ | . . . | 9 . . | . . . | | . . 8 | . 2 3 | . 5 . | | . 6 3 | . 1 . | . . 7 | +-------+-------+-------+ l'arbre de résolution révèle que cette grille n'a qu'une seule solution (un seul nœud vert), mais les nombreux branchements révèlent aussi de nombreuses impasses (fausse route) empruntées durant la recherche. ![Arbre de résolution d'un sudoku difficile](images/sudokufiendish.png) #### Visualiser la recherche de solution avec `main5.py` Ce scrit exploite les [codes ANSI](https://en.wikipedia.org/wiki/ANSI_escape_code). Le script `main5.py` prend deux paramètres sur la ligne de commandes 1. la description de la grille de Sudoku à résoudre sous forme d'une chaîne de 81 caractères ; 2. un nombre exprimant la durée de pause (en secondes) entre deux coups successifs. Il produit en sortie un affichage de la grille sur la sortie standard que l'on peut voir se remplir petit à petit (après avoir tapé la touche Entrée). #### Grille de Sudoku colorée « à la Mondrian » avec `main6.py` Le script `main6.py` prend un ou deux paramètres sur la ligne de commandes 1. la description de la grille de Sudoku à résoudre sous forme d'une chaîne de 81 caractères ; 2. et optionnellement un nom de fichier dans lequel l'image produite sera sauvegardée. L'extension donnée au nom de fichier détermine le format se sauvegarde. Ces extensions peuvent être `.png`, `.jpg`, `.gif` et d'autres encore supportées par le module `PIL`. Par exemple, la commande $ ./main6.py 906028003040500001080900040600000070008206900030000005050003060100002080200870500 images/mondrian_exple1.png produit l'ouverture d'une fenêtre montrant l'image ![coloriage de la grille de l'exemple 1](images/mondrian_exple1.png) et un fichier nommé `mondrian_exple1.png` dans le dossier `images`. #### Création d'un GIF animé $ ./main7.py 906028003040500001080900040600000070008206900030000005050003060100002080200870500 images/mondrian_exple1_resolution ![resolution animée de la grille de l'exemple 1](images/mondrian_exple1_reolution.gif)