rapport : le sudoku

Transcription

rapport : le sudoku
PATURANGE Yvan
LONGEARD Sébastien
RAPPORT :
LE SUDOKU
1
HISTORIQUE:
Pour ce projet, nous avons tenté plusieurs approches afin de générer la
grille de sudoku. Premièrement, nous avions dans l’optique de générer des
grilles de sudoku déjà complétées auxquelles nous aurions ensuite masqué un
certain nombre de valeurs. Ceci afin de pouvoir vérifier en temps réel si une
valeur ajoutée par le joueur respectait les règles en la comparant à la grille
générée en début de partie.
Après plusieurs essais plus ou moins infructueux, nous nous sommes
aperçus que cette solution n’était ni forcement la bonne ni la plus simple à
mettre en œuvre. En effet, cette solution présentait plusieurs inconvénient : la
difficulté intrinsèque à la génération aléatoire d’une grille de sudoku ainsi que la
relative utilité d’avoir une telle grille à disposition.
Effectivement, nous avons tenté de générer des grilles de plusieurs façons
et chaque problème rencontré après avoir pensé et mis en oeuvre un algorithme
nous contraignait à en augmenter la complexité.
Voici par ordre chronologique et donc par ordre de complexité croissante
les différents algorithmes que nous avons expérimentés :
Tout d’abord un algorithme de remplissage linéaire de la grille c'est-à-dire
en parcourant la grille de gauche à droite et de haut en bas vérifiant à chaque
fois que la valeur ajouté respectait les règles. Nous nous sommes aperçus que cet
algorithme se trouvait bloqué relativement vite car la case qu’il rencontrait ne
possédait plus de solution de remplissage possible.
Ensuite, il nous est venu l’idée de remplir les 3 sous carrés formant une
diagonale par rapport à la grille. Il était facile de remplir ces cases puisqu’elles
étaient libérées de toutes contraintes ce qui permettait de remplir 3*9=27 cases
sans effectuer aucun contrôle.
Les sous carrés marqués d’un X étaient remplis :
1 2 3
4 5 6
7 8 9
X 0 0
0 X 0
0 0X
Soit les sous carrés 1, 5 et 9.
C’est à ce moment la que nous est venu l’idée de créer une grille dite de
priorité qui se superpose sur la grille de sudoku. Cette grille calcule le nombre
de valeurs différentes que peut accueillir une case. Il nous était donc possible
désormais de remplir les cases ayant une priorité plus élevée (ayant le moins de
valeurs de remplissage différentes possible.) Néanmoins, appliqué d’abord
seulement aux sous carrés après initialisation de la diagonale de sous carré le
2
grille ne pouvait pas être totalement remplie car les cases restantes n’avais plus
de solutions cet algorithme permettait de remplir 7 sous carrés soit 63 cases. Les
sous carrés marqués d’un X étaient remplis :
1 2 3
4 5 6
7 8 9
XX 0
XXX
0XX
Soit les sous carrés 1, 2, 4, 5, 6, 8 et 9.
Ces deux fonctions nommées respectivement remplirDiag et completerGrille
sont présentes en bas du fichier fonctions_avancées.c.
L’idée suivante a été de réutiliser la grille de priorité mais de l’appliquer
cette fois à l’ensemble de la grille en abandonnant l’idée de remplir la diagonale
de sous carré auparavant. A la place une simple fonction remplissant la grille
avec quelques valeurs aléatoires (entre 5 et 15) servait d’amorce. Ainsi une fois
la grille amorcée, l’algorithme calcule pour toutes les cases le nombre de valeurs
réglementaires qu’elles peuvent contenir. Les cases possédant le moins de
valeurs différentes ont donc une priorité plus élevée et seront candidates au
remplissage. Si plusieurs cases ont une priorité identique, la fonction en choisi
une au hasard et la rempli avec une valeur prise au hasard parmi celles possibles.
Etant donné que cet algorithme ne fait pas de choix judicieux puisqu’il ne
compte que sur le hasard, il lui arrive de se trouver face à une impasse et donc il
lui arrive de ne pas réussir à remplir complètement la grille. Il possède
néanmoins un taux de succès fort acceptable vu la complexité qu’il représente.
De plus il doit être possible en relançant plusieurs fois l’algorithme de parvenir à
résoudre ce problème. Cette fonction nommée remplirGrille est aussi en bas du
fichier fonctions_avancées.c.
C’est à partir de se moment que nous nous sommes interrogé sur l’utilité
de générer une grille complète car nous n’avions aucun moyen de savoir si la
grille générée était l’unique solution de la grille présentée au joueur après avoir
masqué certaines valeurs. Une telle grille aurai certes été au moins une des
solutions possibles mais n’aidait en rien à vérifier que le joueur respectait les
règles lorsqu’il ajoutait une valeur dans la grille.
Nous avons donc finalement décidé de générer une grille comportant 25
valeurs prises au hasard car pour ce nombre, la répartition entre les différentes
cases reste bonne et chute très vite au delà, par exemple en initialisant la grille
avec 30 valeurs il y a de très fortes chances que la grille soit impossible a
résoudre.
Etant donné que pour le reste du projet nous n’avons pas rencontré de
problèmes majeurs, nous allons donc a présent détailler les structures de données
que nous avons utilisé pour stocker les différentes informations du programme.
3
STRUCTURES DE DONNEES :
La grille est un tableau d’entier de 10 cases sur 10, nous avons choisi de
déclarer une telle matrice pour simplifier la représentation de la grille. Nous
utilisons uniquement les cases de 1 à 9 au lieu de 0 à 8 ce choix à été fait
uniquement pour notre confort.
Les valeurs réglementaires sont déterminées grâce a trois tableaux d’entiers de
10 cases chacun stockant sous forme de booléen les valeurs présentes dans la
colonne, la ligne et le carré d’une case donnée.
Par exemple si la colonne dans laquelle se trouve la case contient les valeurs 2, 4
et 7 alors le tableau verifColonne aura ses cases 2, 4 et 7 initialisées à 1 et toutes
les autres cases initialisées à 0.
La grille de priorité est une matrice d’entiers de 10 par 10 par 2, assimilable à
deux grilles de 10 par 10 superposées. La première grille contient pour chaque
case un entier représentant le nombre de valeur différentes que la case peut
contenir en respectant les règles et la deuxième sert à déterminer quelles cases
ont été remplies. Un 0 pour une case vide et 1 pour une case remplie.
Le chargement et la sauvegarde de la grille se font dans le fichier
sauvegarde.txt qui contient toutes les valeurs de la grille misent bout a bout. La
sauvegarde écrit le fichier tandis que le chargement se contente de le lire.
Les coups joués sont stockés dans un fichier texte nommé historique.txt et
chaque coup est formaté de la façon suivante : colonne,ligne :valeur
Chaque coup est séparé dans le fichier par un espace. Une variable globale coup
est un entier qui stocke le nombre de coups stockés dans historique.txt. A
chaque fois qu’une valeur est ajoutée, coup augmente et lorsque le joueur veut
revenir en arrière, coup diminue d’autant que le joueur souhaite revenir en
arrière. Cette variable sert à se positionner correctement dans le fichier
historique.txt.
4
DETAILS DES FONCTIONS :
Les fonctions de base : se sont les fonctions qui a l’inverse des
fonctions avancées n’appellent aucune fonction non natives pendant
leur exécution.
Fonctions de remise à zéro ; les fonctions suivantes servent à remettre les
tableaux qu’on leur passe en argument à zéro et ne renvoient rien.
resetVerif : prend en argument un tableau de vérification (10 cases).
resetGrille : prend en argument une grille de jeu (10*10 cases).
resetPrio : prend en argument une grille de priorité (10*10*2 cases).
Fonctions de détermination du sous carrés auquel appartient une case et
vice versa.
getCarre : prend en argument les coordonnées d’une case et renvoie le sous carré
auquel elle appartient suivant la convention utilisée plus haut.
getCoordX : prend en argument le numéro d’un sous carré et renvoie le numéro
de la colonne de la case situé en haut a droite de ce carré.
getCoordY : prend en argument le numéro d’un sous carré et renvoie le numéro
de la ligne de la case situé en haut a droite de ce carré.
Fonctions de détermination de la priorité : calcule la priorité de toutes les
cases et détermine quelles cases ont la plus grande priorité.
calculPriorites : prend les trois tableaux de vérification de la colonne la ligne et
du carré et retourne le nombre de valeurs différentes qu’une case peut contenir.
getMinPrio : prend en argument le tableau de priorité et, dans un premier temps,
détermine la valeur de la priorité la plus basse puis, stocke les coordonnées de
toutes les cases ayant la priorité la plus basse avant de les afficher dans le but
d’aider le joueur.
5
Fonctions d’affichage : elles servent à améliorer la visibilité des données à
l’écran.
affGrille : affiche la grille de jeu a l’écran en séparant chaque sous carré pour
une meilleure lisibilité.
clr : efface l’écran.
wait : prend un entier temps en argument et interrompt l’exécution du
programme pendant temps ms
Fonctions de sauvegarde et de chargement : elle permettent au joueur de
sauvegarder ou chargée une grille de jeu.
sauvegarderGrille : sauvegarde la grille de jeu courante dans le fichier
sauvegarde.txt.
Les fonctions avancées : toutes utilisent au moins une des fonctions
présente dans fonctions_de_base.c.
menu : affiche et gère le menu.
ajouterValeur : ajoute la valeur entrée par le joueur aux coordonnées entrées par
le joueur. Appel les fonctions vérification et historique.
verification : vérifie que la valeur passée en argument est conforme aux règles
du jeu. Appel la fonction initVerif.
initVerif : Initialise les tableaux servant à vérifier la présence des valeurs dans la
colonne, la ligne ou le carre de la case passée en argument.
historique : ajoute le coup joué dans historique.txt.
chargerGrille : charge la grille enregistrée dans sauvegarde.txt. Appel la fonction
historique.
affHistorique : affiche l’historique des coups joués.
annulerCoup : annule un ou plusieurs coup suivant la demande du joueur.
6
aide : donne la liste des cases ayant la priorité la plus élevée dans un premier
temps et si le joueur le souhaite donne les valeurs qu’une case peut contenir.
Appel les fonctions determinerPriorite et affPrio.
determinerPriorite : rempli la grille de priorité en calculant la priorité pour
chaque cases de la grille de jeu.
affPrio : affiche la grille de priorité.
genererGrille : génère la grille de sudoku avec 25 valeurs aléatoires placées
elles-mêmes aléatoirement. Appel les fonctions initVerif et historique.
AMELIORATIONS ET CRITIQUES :
Ce programme rempli le cahier des charges dans sa totalité sans problèmes
décelés. Cependant il aurait été possible de proposer une solution au joueur en
créant une fonction qui sur le même mécanisme que l’aide remplirait les cases
ayant le moins de possibilités tout comme le fait la fonction remplirGrille. Mais
comme cette fonction n’était pas tout à fait au point et que ceci n’était pas
demandé dans le projet nous nous sommes abstenu d’ajouter une telle
fonctionnalité.
7

Documents pareils