Sudoku/README.md

401 lines
14 KiB
Markdown
Raw Normal View History

2021-01-06 19:10:54 +01:00
# Autour des Sudoku
Diverses variations autour des Sudoku.
2021-01-07 11:13:30 +01:00
## 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 ».
2021-01-07 11:13:30 +01:00
* `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.
2021-01-07 11:13:30 +01:00
* `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
2021-01-07 11:13:30 +01:00
#### 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', 0, 6)`. Cela signifie que lors de la résolution, la première case remplie a été celle de coordonnée (0, 6) (première ligne, septième colonne) 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`)
2021-01-07 11:13:30 +01:00
+-------+-------+-------+
| 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.
2021-01-07 11:13:30 +01:00
![Arbre de résolution d'un sudoku difficile](images/sudokufiendish.png)