TD: Sudoku

Transcription

TD: Sudoku
TD: Sudoku
1 Position du problème
On propose de réaliser un algorithme permettant la résolution d’un sudoku: il s’agit de compléter une grille
9×9 à l’aide des chiffres 1 à 9, chaque chiffre ne pouvant être utilisé qu’une fois dans chaque ligne, dans chaque
colonne et dans chacun des neufs blocs 3 ×3 constituant le sudoku.
Exemple:
9
4
1 3
8 9 5 4 6 1 3 2 7
2
4
9 5
2 3 4 7 9 5 8 1 6
1
5
1 7 6 2 8 3 9 4 5
3
2
9 5 8 3 4 7 1 6 2
⇒
7
6 1
7 4 2 6 1 9 5 8 3
6 1 3
4 7
6 1 3 8 5 2 4 7 9
8
5 3
2
1
4 8 7 5 3 6 2 9 1
5
9
2
5 6 9 1 2 8 7 3 4
3
4 6
3 2 1 9 7 4 6 5 8
On définit un sudoku par une matrice A, en attribuant la valeur 0 à une case vide. On définit la
variable Ensemble comme l’ensemble des chiffres de 1 à 9. On introduira la fonction DisponibilitesSurLigne
qui donne l’ensemble des chiffres qu’il reste à placer sur la ligne no i. De la même façon, on introduira les
fonctions DisponibilitesSurColonne (sur la colonne no j), DisponibilitesSurBloc (sur chaque bloc) et
DisponibilitesSurCase (sur la case (i, j)).
La résolution d’un sudoku se fait en utilisant alternativement plusieurs méthodes:
1. On se fixe une case (i, j): si la case est vide et si la fonction DisponibilitesSurCase ne donne qu’une
seule possibilité pour cette case, alors on la remplit. On réitère pour toutes les cases.
2. On se fixe une ligne i et l’on appelle Dispo l’ensemble des chiffres qu’il reste à placer sur cette ligne. Pour
chaque élément de Dispo, on balaye les colonnes j et l’on compte le nombre de cases vides susceptibles de
recevoir cet élément. S’il n’y a qu’une seule case qui convient, alors on lui affecte l’élément. On réitère
pour toutes les lignes.
De la même façon, on se fixe une colonne j, on cherche les disponibilités de cette colonne et, pour chaque
élément de Dispo, on balaye les lignes pour voir s’il n’y a qu’une seule possibilité de placer l’élément.
De même, on se fixe un bloc, on cherche les disponibilités de ce bloc et, pour chaque élément de Dispo, on
balaye les cases du bloc pour voir s’il n’y a qu’une seule possibilité de placer l’élément.
3. Si l’utilisation alternative des méthodes 1 et 2 ne suffit pas à remplir complètement la grille (voir ci-dessous),
il faut faire des hypothèses sur certaines cases (méthode 3).
5
1
4 3 8
5 6 1 2 4 3 8
7 5 6 1 2 4 3 8 9
Méthodes:
Méthodes: 2 4 1 8 3 9 7 6 5
2
8
2 4 1 8 3
6 5
3
3 8
6
1
3 8
6
1 2 4
3 8 9 6 7 5 1 2 4
⇒
⇒
2
9
5
1
2 4 9
5
8
1 3 2 4 9 6 5 7 8
1 et 2
1 et 2
4
8
2
4
8
1 2
4 6 5 3 8 7 9 1 2
7
1
7
1 2 4
6
9 7 8 5 1 2 4 3 6
6
3
6 2 4
3 8
1
6 2 4 7 5 3 8 9 1
2 4
5
9
2 4 1 6 5 3
8 9 7 2 4 1 6 5 3
1 3
5 1 3
6 8 2 4
5 1 3 9 6 8 2 4 7
• On définira la fonction Trouve pour vérifier si la grille est complète (aucune case n’a la valeur 0) ainsi
que la fonction Possible pour vérifier si l’hypothèse faite n’aboutit pas à une impasse (aucune case telle
que l’ensemble des DisponibilitesSurCase soit vide).
• La méthode 3 consiste à chercher, dans la grille, la case vide qui possède le plus petit ensemble
DisponibilitesSurCase. On essaye successivement les différents éléments de cet ensemble et, pour chaque
cas, on applique les méthodes 1 et 2. Si l’hypothèse conduit à un résultat Possible alors: soit on affiche
la solution (si Trouve), soit on reprend la méthode 3 (sinon).
Il s’agit donc d’un algorithme récursif: la procédure s’appelle elle-même jusqu’à ce qu’elle trouve ou qu’elle
1
ISEN-Brest. Kany.
TD: Sudoku
aboutisse à une impasse.
Normalement, si sudoku a été bien conçu, toutes les hypothèses doivent conduire à une impasse sauf une
qui doit permettre de compléter toute la grille (Trouve).
• Ce programme peut aussi être utilisé pour créer des sudokus: il suffit de choisir 25 cases de façon aléatoire
et de leur attribuer des valeurs quelconques (mais sans incompatibilités).
S’il n’y a aucune solution (la méthode 3 n’aboutit qu’à des impasses: pas d’hypothèse Possible), alors on
supprime l’une des cases et l’on recommence.
S’il y a plusieurs solutions (la méthode 3 aboutit à plusieurs Trouve), alors on fixe la valeur d’une case
supplémentaire (en la choisissant grâce à DisponibilitesSurCase).
2 Code avec Mathematica
Sudoku
In[1]:= Ensemble={1,2,3,4,5,6,7,8,9};
DisponibilitesSurLigne[A ,i ]:=Complement[Ensemble,Table[A[[i,j]],{j,1,9}]];
DisponibilitesSurColonne[A ,j ]:= Complement[Ensemble,Table[A[[i,j]],{i,1,9}]];
DisponibilitesSurBloc[A ,i ,j ]:=Module[{k,ElementsBloc},
ElementsBloc={}; For[k=1,k<=3,k++,
ElementsBloc=Union[ElementsBloc,Table[A[[3*i-3+k,3*j-3+l]],{l,1,3}]]];
Complement[Ensemble,ElementsBloc]];
Bloc[i ]:=Quotient[i+2,3];
DisponibilitesSurCase[A ,i ,j ]:= If[A[[i,j]]==0,
Intersection[DisponibilitesSurLigne[A,i],DisponibilitesSurColonne[A,j],
DisponibilitesSurBloc[A,Bloc[i],Bloc[j]]],{A[[i,j]]}];
In[7]:= Scan1[AA ]:=Module[{A,i,j,Dispo,Fin}, A=AA;Fin=False; While[Not[Fin], Fin=True;
For[i=1,i<=9,i++, For[j=1,j<=9,j++, If[A[[i,j]]==0,Dispo=DisponibilitesSurCase[A,i,j];
If[Length[Dispo]==1,A=ReplacePart[A,Dispo[[1]],{i,j}]; Fin=False];]; ]; ]; ];
Return[A];];
In[8]:= Scan2[AA ]:=Module[{A,i,j,k,l,num,nummax,Dispo,n,nbn,r,s,rr,ss}, A=AA;
For[i=1,i<=9,i++, Dispo=DisponibilitesSurLigne[A,i]; nummax=Length[Dispo];
For[num=1,num<=nummax,num++, n=Dispo[[num]];nbn=0; For[j=1,j<=9 && nbn<=1,j++,
If[A[[i,j]]==0 && MemberQ[DisponibilitesSurCase[A,i,j],n],nbn++; r=j;];];
If[nbn==1,A=ReplacePart[A,n,{i,r}];]; ]; ];
For[j=1,j<=9,j++, Dispo=DisponibilitesSurColonne[A,j]; nummax=Length[Dispo];
For[num=1,num<=nummax,num++, n=Dispo[[num]];nbn=0; For[i=1,i<=9 && nbn<=1,i++,
If[A[[i,j]]==0 && MemberQ[DisponibilitesSurCase[A,i,j],n],nbn++; r=i;];];
If[nbn==1,A=ReplacePart[A,n,{r,j}];]; ]; ];
For[i=1,i<=3,i++, For[j=1,j<=3,j++, Dispo=DisponibilitesSurBloc[A,i,j];
nummax=Length[Dispo]; For[num=1,num<=nummax,num++, n=Dispo[[num]];nbn=0;
For[k=1,k<=3,k=k+1, For[l=1,l<=3 && nbn<=1,l++, r=3*i-3+k;s=3*j-3+l;
If[A[[r,s]]==0 && MemberQ[DisponibilitesSurCase[A,r,s],n],nbn++;rr=r; ss=s;];]]
If[nbn==1,A=ReplacePart[A,n,{rr,ss}];]; ]; ]; ];Return[A]];
In[9]:= ResolutionSimple[AA ]:=Module[{A,B,Fin}, A=AA; Fin=False;
While[Not[Fin],B=A;A=Scan2[Scan1[A]];Fin=If[B==A,True,False];];Return[A]];
In[10]:= A={
{0,9,0,4,0,1,3,0,0},{2,0,4,0,9,5,0,0,0},{1,0,0,0,0,0,0,0,5},
{0,0,0,3,0,0,0,0,2},{7,0,0,6,1,0,0,0,0},{6,1,3,0,0,0,4,7,0},
{0,8,0,5,3,0,2,0,1},{5,0,9,0,2,0,0,0,0},{3,0,0,0,0,4,6,0,0}};
MatrixForm[A] MatrixForm[ResolutionSimple[A]]
2
ISEN-Brest. Kany.
TD: Sudoku
Out[12]//MatrixForm=
0 9 0 4 0 1 3 0 0
2 0 4 0 9 5 0 0 0
1 0 0 0 0 0 0 0 5
0 0 0 3 0 0 0 0 2
7 0 0 6 1 0 0 0 0
6 1 3 0 0 0 4 7 0
0 8 0 5 3 0 2 0 1
5 0 9 0 2 0 0 0 0
3 0 0 0 0 4 6 0 0
Out[13]//MatrixForm=
8 9 5 4 6 1 3 2 7
2 3 4 7 9 5 8 1 6
1 7 6 2 8 3 9 4 5
9 5 8 3 4 7 1 6 2
7 4 2 6 1 9 5 8 3
6 1 3 8 5 2 4 7 9
4 8 7 5 3 6 2 9 1
5 6 9 1 2 8 7 3 4
3 2 1 9 7 4 6 5 8
In[14]:= Possible[A ]:=Module[{i,j,Resultat,Fin}, Resultat=True;Fin=False;i=1;j=1;
While[Not[Fin],If[Length[DisponibilitesSurCase[A,i,j]]==0, Resultat=False;Fin=True,
j++;If[j==10,j=1;i++;If[i==10,Fin=True];];];]; Return[Resultat];];
In[15]:= Trouve[A ]:=Module[{i,j,Resultat,Fin}, Resultat=True;Fin=False;i=1;j=1;
While[Not[Fin],If[A[[i,j]]==0, Resultat=False;Fin=True,
j++;If[j==10,j=1;i++;If[i==10,Fin=True];];];]; Return[Resultat];];
In[16]:= Scan3[AA ]:=Module[{A,B,C,i,j,k,kmax,m,r,s,Dispo,Dispom}, A=AA;m=9;
For[i=1,i<=9,i++, For[j=1,j<=9&&m>2,j++,
Dispo=DisponibilitesSurCase[A,i,j];
If[Length[Dispo]<m&&Length[Dispo]>1,m=Length[Dispo];r=i;s=j;Dispom=Dispo]]];
kmax=Length[Dispom]; For[k=1,k<=kmax,k++,
B=A;C=ReplacePart[B,Dispom[[k]],{r,s}]; B=ResolutionSimple[C];
If[Possible[B],If[Trouve[B],Print[MatrixForm[B]];NbreSol++,Scan3[B];];];]; NbreSol];
In[17]:= ResolutionAvancee[AA ]:=Module[{A}, A=AA;NbreSol=0; ResolutionSimple[A];
If[Trouve[A],NbreSol++;Print[MatrixForm[A]],If[Possible[A],Scan3[A];];]; NbreSol];
In[18]:= A={
{0,5,0,1,0,4,3,8,0},{2,0,0,8,0,0,0,0,0},{3,8,0,6,0,0,1,0,0},
{0,0,2,0,9,0,5,0,0},{4,0,0,0,8,0,0,0,2},{0,7,0,0,1,0,0,0,0},
{6,0,0,0,0,3,0,0,0},{0,0,0,2,4,0,0,5,0},{0,1,3,0,0,0,0,0,0}};
MatrixForm[A]; MatrixForm[ResolutionSimple[A]] ResolutionAvancee[A]
Out[21]//MatrixForm=
0 5 0 1 0 4 3 8 0
2 0 0 8 0 0 0 0 0
3 8 0 6 0 0 1 0 0
0 0 2 0 9 0 5 0 0
4 0 0 0 8 0 0 0 2
0 7 0 0 1 0 0 0 0
6 0 0 0 0 3 0 0 0
0 0 0 2 4 0 0 5 0
0 1 3 0 0 0 0 0 0
3
ISEN-Brest. Kany.
TD: Sudoku
Out[22]//MatrixForm=
0 5 6 1 2 4 3 8 0
2 4 1 8 3 0 0 6 5
3 8 0 6 0 0 1 2 4
1 0 2 4 9 0 5 0 8
4 0 0 0 8 0 0 1 2
0 7 0 0 1 2 4 0 6
6 2 4 0 0 3 8 0 1
0 9 0 2 4 1 6 5 3
5 1 3 0 6 8 2 4 0
Out[23]//MatrixForm=
7 5 6 1 2 4 3 8 9
2 4 1 8 3 9 7 6 5
3 8 9 6 7 5 1 2 4
1 3 2 4 9 6 5 7 8
4 6 5 3 8 7 9 1 2
9 7 8 5 1 2 4 3 6
6 2 4 7 5 3 8 9 1
8 9 7 2 4 1 6 5 3
5 1 3 9 6 8 2 4 7
Out[24]= 1
3 Code avec Python
# -*- coding: utf-8 -*import numpy as np
from matplotlib.cbook import flatten
4