Projet Intelligence Artificielle : le sudoku
Auteurs :
DOUCHANT Fabrice
ELMECHRAFI Mohammed Chafiq
Sommaire :
I. Présentation du projet
II. Etapes de la réalisation du projet
III. Comparaison entre l’algorithme BackTrack et Forward-Checking
IV. Descriptions des algorithmes de génération.
V. Conclusion
I. Présentation du projet :
Ce projet est basé sur le jeu du sudoku, il consiste à créer un programme pour
résoudre les sukodus puis un autre pour générer aléatoirement des grilles. Pour ce
faire, nous modélisons le problème sous forme d’un CSP (X, D, C, R) :
X : = {x0, x2, …, x80} : une case de la grille du sudoku
D : = {1, 2, …, 9} : valeur possible pour une case
C : = Cxy, x et y appartiennent a X et ……… !!!!!!
R : = Rxy tel que x y
II. Etapes de la réalisation du projet :
a. Résolution d’un sudoku (recherche d’une solution) :
Pour résoudre un sudoku, nous avons implémenté 2 algorithmes :
BackTrack (BT) et Forward-Checking (FC).
Réponses aux questions du sujet :
(iii) Forward-Checking est plus rapide que BackTrack en règle générale mais il est
possible (aucun exemple cependant) que BT soit plus rapide si, lors du déroulement
de l’algorithme, aucune variable n’est instanciée par une valeur du domaine qui
violent les contraintes (ce qui revient à parcourir le même arbre que FC). Dans ce
cas la, vu qu’aucun tests n’est effectue avant l’instanciation des variables
(contrairement à FC), l’algorithme est alors plus rapide.
Dans le cas général, FC effectue parcours mois de nœuds que BT (ou sinon le
même nombre : cf. explication ci-dessus) mais effectue toujours plus de tests (tests
des instances de domaines possibles)
(iv) Les algorithmes BT et FC instancient les variables les unes après les autres dans
un ordre donné. Il est à peut près sur que ces algorithmes effectuerons des retours
en arrières dans l’arbre qu’ils parcourent, il est donc impossible d’affirmer à l’aide de
ces algorithmes que la grille est déductible ou pas. Il faut donc utiliser un autre
algorithme pour pouvoir effectuer ce teste.
b. Génération aléatoire :
Pour générer aléatoirement une grille de sudoku (contenu de 17 à 81
chiffres) valide, il faut qu’elle satisfasse ces 2 propriétés :
- avoir exactement une solution
- cette solution pour être trouver uniquement grâce a des déductions
Pour satisfaire la première propriété, nous avons utilisé un algorithme amélioré de
Forward-Checking qui compte les nombres de solutions possibles, puis pour la
deuxième propriété nous avons créer un nouvelle algorithme qui rifie si la grille est
déductible ou non.
Pour commencer, nous avons décidé de générer aléatoirement (tout en respectant
les contraintes) une grille de 15 chiffres, puis a l’aide de FC, nous gênerons 1 grille
possible qui devient alors la solution a la future grille générée. Nous avons choisis de
générer 15 chiffres car plus il y a de variables générées aléatoirement, moins il est
possible de trouver une solution possible puisque nous faisons alors face au
problème de chevauchement des domaines :
Exemple : parmi les variables non instanciées, x y et z sont 3 variables en relation les
unes avec les autres (soumis aux contraintes). Il est possible que lors de
l’instanciation des autres variables, les domaines de ces variables deviennent
identiques et ne contiennent que 2 valeurs : k et l. Le sudoku n’aura donc plus de
solution possible puisque les 3 variables se partagent seulement 2 valeurs possibles
(donc une variable aura un domaine vide).
Ensuite, nous supprimons au fur et a mesure des variables tout en mettant les
domaines des autres variables a jour. Des qu’une variable a été supprimée, nous
appelons l’algorithme de déduction pour vérifier que la grille est toujours déductible.
Si c’est le cas nous appelons alors l’algorithme Forward-Checking afin qu’il s’assure
que le grille n’a qu’une seule solution. Nous effectuons les appels à ces algorithmes
dans cet ordre car l’algorithme de déduction est plus rapide que FC. Les variables
supprimés sont sélectionné au hasard mais toutefois, nous avons vérifie que 1
variable ne soit pas testé 2 fois et que si toute les variables on été testées, cela
revient a dire que la grille ne peut plus être allégée.
III. Comparaison entre l’algorithme BT et FC :
L’algorithme BackTrack génère un arbre en essayant d’instancier au fur et à
mesure les variables : On choisit pour chaque variable une valeur dans le
domaine puis on regarde si cette instanciation respecte les contraintes. Si c’est le
cas, on passe à une variable suivante. Sinon on change la valeur de la variable
jusqu'à ce que toutes les valeurs du domaine aient été « essayées ». Dans ce cas là,
on revient à la dernière variable instanciée et on affecte à cette variable une nouvelle
valeur de son domaine (on ne re-affecte pas deux fois la même valeur). Ainsi de
suite jusqu’à ce que l’on est instancié toutes les variables et que les contraintes
n’aient pas été violées (on a donc une solution) ou jusqu’à ce que l’arbre est été
parcouru dans sa totalité (aucune solution).
L’algorithme Forward-Checking se repose sur le même principe que BT mais le
choix de la valeur du domaine est différent. On effectue une sélection des valeurs qui
ne pourront pas aboutir en mettant à jour les domaines à chaque instanciation d’une
variable (on met à jour les domaines en relation avec cette variable). Ainsi on
parcourt moins de branches qu’avec BT et on gagne du temps. Cependant les tests
effectués pour mettre à jour les domaines ont un coup, c’est pour cela que l’utilisation
de BT ou de FC dépend de l’arbre généré : la différence du nombre de nœuds
parcourus en moins par FC peut/ou ne peut pas être bénéfique comparés aux tests
effectués.
Dans notre cas : le sudoku, FC obtient souvent (toujours, selon les tests
effectués) un meilleur résultat au niveau du temps (et bien sur un nombre inférieur de
nœuds parcourus).
VI. Descriptions des algorithmes de génération :
Pour générer des grilles de sudoku, nous avons utiliser plusieurs fonctions
(plusieurs algorithmes). Ces algorithmes sont décris dans le code. Cependant nous
allons expliquer dans les grandes lignes leurs fonctionnements dans l’ordre
chronologiques de leur apparition :
a. Génération d’une grille « complète » :
Nous voulons dans un premier temps générer une grille complète afin
d’enlever par la suite les variables qui la contiennent (pour arriver au nombre voulu
de variables dans la grille).
Nous avons donc choisi aléatoirement 15 variables dans une grille vide et nous leurs
avons affectées une valeur valide dans leur domaine respectif (valeur valide car les
domaines sont mises à jour au fur et à mesure). Nous avons choisi d’instancier 15
variables car plus le nombres de variables est grand, plus les chances que la grille
ne soit pas valide sont importantes. Une grille peut ne plus être valide si les
domaines se chevauchent. Pour clarifier ce point, voici un exemple :
Exemple : prenons trois variables (cela peut être plus : à partir de deux) en
contraintes les unes avec les autres. Disons que ces variables ont chacune un
domaine égale, domaine restreint à deux variables. Si on affecte à la première
variable une des deux valeurs du domaine et que l’on met à jour les autres
domaines. Les deux autres variables voient leurs domaines diminuer et passer à une
valeur possible. Si on affecte ensuite la deuxième variable, la dernière variable n’a
plus de valeur possible et la grille est donc invalide.
Nous n’avons pas choisi moins que 15 variables car nous utilisons ensuite FC pour
générer une grille (en choisissant la valeur du domaine de 1 à 9) et si le nombre est
trop petit, les grilles vont se ressembler d’une génération à l’autre.
A chaque instanciation d’une variable, nous effectuons un seul test, à savoir si aucun
domaine n’est vide. Si c’est le cas, on instancie une autre variable.
Le test de chevauchement des domaines n’est pas effectué au fur et à mesure de la
génération car nous nous sommes aperçus que ce test est trop coûteux : mieux vaut
effectuer une nouvelle génération.
Dès que ces 15 variables ont é instanciées, nous faisons appel à FC pour qu’il
nous génère une grille complète (les 81 variables sont instanciées). Si FC ne trouve
aucune solution, nous générons une nouvelle grille.
b. Déroulement de la fonction de suppression :
Dès que la grille complète est générée, nous passons à la
suppression de variables. Cette fonction est constituée de plusieurs étapes. Il faut :
supprimer aléatoirement une variable, mettre à jour les domaines. Puis on teste en
premier lieu si la grille reste déductible (l’utilisateur qui devra la résoudre n’aura
aucun choix hasardeux à faire). Si ce teste est positif, on vérifie que la grille ne
possède qu’une seule solution (sinon la grille n’est pas valide).
Dès qu’un de ces tests indique que la grille est invalide, on choisit une autre variable
et ceci jusqu’à ce que l’on est obtenu le nombre de variables voulu ou que toutes les
variables on été testées (dans ce cas on génère une nouvelle grille).
En effet, plus l’utilisateur demande un grille ne contenant que très peu de chiffres,
plus le calcul sera long car selon la grille complète générée au départ, cette grille
admet un minimum de chiffres avant de devenir invalide (exemple : il n’existe
qu’environ 1000 grilles valides contenant 17 chiffres).
c. Fonction de déductibilité :
Cette fonction a pour but de savoir si la grille est déductible ou pas. Pour le
savoir, on instancie toutes les variables ayant un domaine qui contient qu’une seule
valeur, puis on met à jour les autres domaines. On réitère cette opération jusqu’à ce
qu’aucune variable ne puisse plus être instanciée (à la manière d’un algorithme
inductif). Puis on regarde s’il reste des variables non instanciées. Dans ce cas la
grille n’est pas déductible.
d. Fonction du nombre de solutions :
Cette fonction a pour but de savoir combien de solution à la grille. Dans
notre cas, on ne recherche que deux solutions possibles (si l’algorithme trouve deux
solutions, la grille n’est plus valide). Elle est emprunt en grande partie de la fonction
Forward-Checking. Des qu’une solution est trouvée, on continue en changeant la
dernière variable possible.
V. Conclusion :
Ce projet nous a beaucoup intéressé déjà du fait du jeu traité (le sudoku est à la
mode et on aime bien y jouer) et du coté pratique qui reflète bien la théorie étudiée
pendant les cours.
Cependant, nous nous sommes heurtés à quelques problèmes : premièrement
l’algorithme BackTrack itératif (nous avions déjà programmé l’algorithme récursif).
Puis lors de la génération de grilles : nous pensions en premier lieu partir d’une grille
vide et lui rajouter au fur et à mesure les chiffres, mais nous n’aurions pas pu tester
la validité de la grille (déductibilité et unique solution) qu’après avoir instanciées les
variables (algorithme lent).
Tous ces problèmes étant résolus, le programme est fonctionnel.
1 / 5 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !