Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Exercice][Débutant - Intermediaire] Démineur

mini-projet

    13 septembre 2010 à 15:37:10

    Citation : realmagma


    Une remarque, il manque quelques commentaires au niveau du deuxième code: ton fichier cursesui.py



    À quel niveau ?
    Il n'y a que la fonction main que je n'ai pas documentée, parce que son utilité est triviale (elle sert tout bêtement à lancer le programme une fois que ncurses a été initialisé au sein la fonction curses.wrapper() )...

    Citation : realmagma


    Pour info, je n'ai toujours pas commencé mon interface graphique, je suis en désaccord avec tkinter.



    Bon courage, personnellement je m'en suis détourné au bout d'une demi-heure, en constatant à quel point ce module était peu commode à utiliser, comparativement à d'autres modules/bibliothèques de GUI comme PyGTK ou PyQt...
    Mais ce n'est que mon avis personnel. :-°
    • Partager sur Facebook
    • Partager sur Twitter
    Zeste de Savoir, le site qui en a dans le citron !
      13 septembre 2010 à 16:06:36

      Citation

      Bon courage, personnellement je m'en suis détourné au bout d'une demi-heure, en constatant à quel point ce module était peu commode


      => Très chiant à utiliser oui ! :lol:

      Citation


      comparativement à d'autres modules/bibliothèques de GUI comme PyGTK ou PyQt...


      => Je vais voir ça, car je ne les ai jamais utilisé.

      Que me conseils-tu ?
      Quelles diférences il y a t-il en PyGTK et PyQT ?
      • Partager sur Facebook
      • Partager sur Twitter
        13 septembre 2010 à 16:46:01

        PyGTK est peut-être plus direct d'accès que PyQt, mais le second framework est beaucoup plus poussé et complet.

        Je ne peux pas vraiment donner de conseil, ça dépend de beaucoup de facteurs...

        Si tu travailles dans un environnement Gnome (il me semble que c'est le cas), pour débuter, PyGTK est un bon choix.

        Le seul inconvénient de Qt (que ce soit en C++ ou en Python) c'est que c'est un framework complet qui va (si tu veux l'utiliser "correctement") influencer complètement tes applications, pas seulement l'interface graphique. Je pense donc qu'il est plus sain d'aborder ce framework une fois que tu as des bases solides dans le langage que tu utilises, pas parce qu'il est compliqué (ce qui n'est pas le cas) mais parce qu'un framework aussi complet a souvent comme effet de "masquer" le reste du langage.
        • Partager sur Facebook
        • Partager sur Twitter
        Zeste de Savoir, le site qui en a dans le citron !
          13 septembre 2010 à 16:53:01

          OK, je te remercie pour ces explications. Je vais regarder du côté de PyGTK, il m'a l'air plus simple que PyQT (et en plus je suis un grand débutant).
          Le temps que je lise le tutoriel que je comprenne comment il fonctionne il me faudra au moins un bon mois (et encore tout dépend du temps que j'ai) :p

          Merci. :)
          • Partager sur Facebook
          • Partager sur Twitter
            13 septembre 2010 à 16:58:50

            Citation : realmagma


            Le temps que je lise le tutoriel que je comprenne comment il fonctionne il me faudra au moins un bon mois



            Soit tu te sous-estimes, soit tu te laisses impressionner par la programmation de GUI, mais je pense que pour comprendre le principe des GUI une bonne semaine est très largement suffisante, le reste n'étant que des habitudes à prendre avec la pratique.

            Une fois que tu as compris ce que sont un widget et une fonction de callback (et cette dernière est beaucoup plus simple à appréhender en Python où "tout est objet" qu'en C — langage dans lequel j'ai fait mes premières armes en GTK, où ça implique la compréhension et l'utilisation de pointeurs sur fonctions... bref, beurk! —), tout roule.
            • Partager sur Facebook
            • Partager sur Twitter
            Zeste de Savoir, le site qui en a dans le citron !
              17 septembre 2010 à 9:35:20

              *bump*

              Alors, où en êtes-vous ? :p
              • Partager sur Facebook
              • Partager sur Twitter
              Zeste de Savoir, le site qui en a dans le citron !
                17 septembre 2010 à 10:52:38

                Bonjour,

                Et bien je dirai que je galère un peut. Je m'entraîne sur Tkinter pour bien voir comment il fonctionne et j'aurai quelques questions + un problème (d'ordre mécanique => codage) :D .

                Quelle sont les différences entre les méthodes:
                • pack()
                • grid()
                • place()


                Le code présenté ci-dessous, découpe mon Canvas sous forme de cases. La taille d'un bloc équivaut à de 20x20 pixels. J'aimerai placer des images .gif de 10x10 pixels dans chacune de ces cases en les centrant.

                Si les coordonnées de ma souris ce trouvent dans l'une des cases dans mon Canvas, alors on blit le gif en le centrant dans cette case.
                Le problème c'est que je n'y arrive pas. Si je clic sur une case, mon image se blit. Si je déplace ma souris de quelque pixels et que je re-clic dessus, mon images se blite en décalage sur la même case.
                Si quelqu'un aurait une solution (pas forcément du code, juste une idée) qu'il me le fasse savoir.
                Je vous remercie d'avance.

                Mon code:

                ################################
                ## Les Modules Importés:(2)   ##
                #
                from tkinter import *
                import math
                
                #-*-*- <Les Classes> || Début de <JeuTk> -*-*-#
                
                class JeuTk(object):
                    def __init__(self):
                        self.l = []
                
                        self.tailleBloc = 20 #"Épaisseur" d'un bloc 20x20 pixels 
                        self.largBloc = 10
                
                        self.largF = self.largBloc * self.tailleBloc #largF = largeurFenetre
                        
                        for i in range(self.largBloc): #On créer 10 listes dans une liste
                            self.l.append([0] * self.largBloc)
                        
                        
                        #Création d'une fenetre
                        self.fenetre = Tk()
                
                        #Canvas
                        self.can = Canvas(self.fenetre, bg = "dark grey", height = self.largF, width = self.largF)
                        self.can.bind("<Button-1>", self.pointeur) #Clic Gauche
                        self.can.bind("<Button-3>", self.pointeur) #Clic Droit
                        self.can.pack(side = LEFT)
                
                        #Boutton
                        bou = Button(self.fenetre, text = "Quitter", command = self.fenetre.destroy)
                        bou.pack()
                
                        #Label: On affiche la grille
                        texte = Label(self.fenetre, text = self.l)
                        texte.pack()
                
                        #Photo
                        self.photo = PhotoImage(file = "1.gif")
                            
                
                    def pointeur(self, event):
                        #On fait en sorte que se soit une grille. Que des entiers
                        #Grâce au print, on peut voir que je clic sur des cases qui sont des entiers
                        #Si je clic en haut à gauche, on me renvoie (0;0). Plus à droite=> (1;0)...
                        print(math.ceil(event.x / self.tailleBloc), math.ceil(event.y / self.tailleBloc))
                        item = self.can.create_image(math.ceil(event.x), math.ceil(event.y), image = self.photo)
                        
                            
                        
                        
                if __name__ == "__main__":
                    p = JeuTk()
                    p.fenetre.mainloop()
                



                P.S: Pour une image gif de 10x10 pixels tapez: chiffre 7 dans Google image. Il se trouve dans la première page.
                Lien direct:
                • Partager sur Facebook
                • Partager sur Twitter
                  17 septembre 2010 à 11:05:42

                  Ton code donne ça comme résultat chez moi :
                  Image utilisateur
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Zeste de Savoir, le site qui en a dans le citron !
                    17 septembre 2010 à 11:12:30

                    Chez moi aussi. Le problème c'est que je ne veux pas qu'une image en chevauche une autre et qu'une seule image aille dans une seule et unique case.
                    Je n'ai aucune idée sur la représentation de l'algorithme.
                    • Partager sur Facebook
                    • Partager sur Twitter
                      17 septembre 2010 à 11:25:34

                      Je ne connais pas assez tkinter pour t'aider sur ce coup...
                      • Partager sur Facebook
                      • Partager sur Twitter
                      Zeste de Savoir, le site qui en a dans le citron !
                        17 septembre 2010 à 14:05:22

                        Image utilisateur

                        C'est pas grave, finalement j'ai réussit à générer les cases à cliquer pour le démineur. Je n'ai plus qu'a les resserrer (C'est trop espacer).
                        Il me manque beaucoup de choses à faire, comme les remplacer lors d'un clic, puis implémenter tout ça sur mon vrai démineur.
                        Je vous tient au courant. :)

                        EDIT: Voici les algo que j'ai utilisé:
                        Le premier place un chiffre dans une case.
                        Le deuxième génère une grille


                        def pointeur(self, event):
                                #On fait en sorte que se soit une grille. Que des entiers
                                #Grâce au print, on peut voir que je clic sur des cases qui sont des entiers
                                #Si je clic en haut à gauche, on me renvoie (0;0). Plus à droite=> (1;0)...
                                print(math.ceil(event.x / self.tailleBloc), math.ceil(event.y / self.tailleBloc))
                                
                                #Ne pas oublier '+1' pour pouvoir cliquer en 10;10 par exemple
                                for i in range(self.largBloc + 1):
                                    for j in range(self.largBloc + 1):
                                        if math.ceil(event.x / self.tailleBloc) == i and  math.ceil(event.y / self.tailleBloc)==j:
                                            
                                            #Pour centrer l'image: i*tailleBloc - largBloc
                                            item = self.can.create_image(i * self.tailleBloc - self.largBloc , j * self.tailleBloc - self.largBloc, \
                                                                         image = self.photo2)
                                
                                
                            def genereGrille(self):
                                for i in range(self.largBloc):
                                    for j in range(self.largBloc):
                                        item = self.can.create_image(i * self.tailleBloc + self.largBloc, j * self.tailleBloc + self.largBloc, \
                                                                     image = self.photo)
                        


                        EDIT N°2: Mon code en entier: (Pour ceux qui voudront tester)

                        ################################
                        ## Les Modules Importés:(2)   ##
                        #
                        from tkinter import *
                        import math
                        
                        #-*-*- <Les Classes> || Début de <JeuTk> -*-*-#
                        
                        class JeuTk(object):
                            def __init__(self):
                                self.l = []
                        
                                self.tailleBloc = 20
                                self.largBloc = 10
                        
                                self.largF = self.largBloc * self.tailleBloc #largF = largeurFenetre
                                
                                for i in range(self.largBloc): #On créer 5 listes dans une liste
                                    self.l.append([0] * self.largBloc)
                                
                                
                                #Création d'une fenetre
                                self.fenetre = Tk()
                        
                                #Canvas
                                self.can = Canvas(self.fenetre, bg = "dark grey", height = self.largF, width = self.largF)
                                self.can.bind("<Button-1>", self.pointeur) #Clic Gauche
                                self.can.bind("<Button-3>", self.pointeur) #Clic Droit
                                self.can.pack(side = LEFT)
                        
                                #Boutton
                                bou = Button(self.fenetre, text = "Quitter", command = self.fenetre.destroy)
                                bou.pack()
                        
                                #Boutton genererGrille
                                bou2 = Button(self.fenetre, text = "Nouveau", command = self.genereGrille)
                                bou2.pack()
                        
                                #Label: On affiche la grille
                                #texte = Label(self.fenetre, text = self.l)
                                #texte.pack()
                        
                                #Photo
                                self.photo = PhotoImage(file = "c.gif")
                                self.photo2 = PhotoImage(file = "1.gif")
                                    
                        
                            def pointeur(self, event):
                                #On fait en sorte que se soit une grille. Que des entiers
                                #Grâce au print, on peut voir que je clic sur des cases qui sont des entiers
                                #Si je clic en haut à gauche, on me renvoie (0;0). Plus à droite=> (1;0)...
                                print(math.ceil(event.x / self.tailleBloc), math.ceil(event.y / self.tailleBloc))
                                
                                #Ne pas oublier '+1' pour pouvoir cliquer en 10;10 par exemple
                                for i in range(self.largBloc + 1):
                                    for j in range(self.largBloc + 1):
                                        if math.ceil(event.x / self.tailleBloc) == i and  math.ceil(event.y / self.tailleBloc)==j:
                                            
                                            #Pour centrer l'image: i*tailleBloc - largBloc
                                            item = self.can.create_image(i * self.tailleBloc - self.largBloc , j * self.tailleBloc - self.largBloc, \
                                                                         image = self.photo2)
                                
                                
                            def genereGrille(self):
                                for i in range(self.largBloc):
                                    for j in range(self.largBloc):
                                        item = self.can.create_image(i * self.tailleBloc + self.largBloc, j * self.tailleBloc + self.largBloc, \
                                                                     image = self.photo)
                                        
                                        
                                
                                
                        if __name__ == "__main__":
                            p = JeuTk()
                            p.fenetre.mainloop()
                        
                        • Partager sur Facebook
                        • Partager sur Twitter
                          18 septembre 2010 à 15:52:12

                          Bonjour,

                          j'ai essayé de créer l'interface graphique de mon démineur, mais impossible de le faire fonctionner correctement.
                          En effet, il me dit que je suis en index out of range, alors que non, je ne le suis pas !

                          Explication de mon code:
                          J'ai crée une fenêtre avec un Canvas. J'ai découpé mon Canvas comme dans l'exemple du poste du haut (cf EDIT N°2).
                          C'est à dire sous forme de blocs. (Copier/coller le code de mon édit n°2, vous verrez de quoi je parle ;) )
                          En somme, c'est le même système.

                          Exécuter le code ci-dessous, cliquez sur commencer/jouer puis sur afficher.
                          Vous verrez déjà une erreur dans la console.
                          Ensuite cliquez dans le Canvas... et c'est le drame. Index out of range.

                          Quelqu'un aurait il une idée, parce que là je suis à sec :-° .
                          Merci d'avance.

                          Mon code:
                          ################################
                          ## Les Modules Importés:(2)   ##
                          #
                          from tkinter import *
                          import random
                          import math
                          
                                                                                         
                          #-*-*- <Les Classes> || Début de <Jeu> -*-*-#
                          
                          class Jeu(object):
                              """Permet de gérer la partie."""
                              def __init__(self):
                                  """
                                  Instancie un objet du type <Plateau>.
                                  Déclare les variables nécessaires.
                                  - a_dePlateau   (type:-Instance-)
                                  - partieEnCours (type:-Booleen-)
                                  
                                  Appel de la fonction:
                                  - jouer()
                          
                                  """
                                  #Variables nécessaires pour le déroulement de la partie
                                  self.a_dePlateau = Plateau()
                                  self.partieEnCours = True
                                  
                                  #Création des fenêtres
                                  self.fenetre = Tk()
                                  self.fenetreRegle = Tk()
                                  
                                  #Canvas
                                  self.can = Canvas(self.fenetre, bg = "dark grey", height = self.a_dePlateau.largF, \
                                                    width = self.a_dePlateau.largF)
                                  self.can.bind("<Button-1>", self.a_dePlateau.creuser)      #Creuse
                                  self.can.bind("<Button-3>", self.a_dePlateau.poserDrapeau) #Pose un drapeau
                                  self.can.pack(side = LEFT)
                          
                                  #Boutton Quitter
                                  bouQuitter = Button(self.fenetre, text = "Quitter", command = self.fenetre.destroy)
                                  bouQuitter.pack(side = BOTTOM)
                                  #Boutton Jouer
                                  bouJouer = Button(self.fenetre, text = "Jouer/recommencer", command = self.jouer)
                                  bouJouer.pack(side = BOTTOM)
                                  #Boutton Regle
                                  bouRegle = Button(self.fenetre, text = "Règles", command = self.regle)
                                  bouRegle.pack(side = BOTTOM)
                          
                                  #Boutton Rafraîchir grille
                                  bouRaf = Button(self.fenetre, text = "Rafraîchir", command = self.afficher)
                                  bouRaf.pack()
                          
                                  #Images -Chargement
                                  self.p_case = PhotoImage(file = "case.gif")
                                  self.p_croix = PhotoImage(file = "croix.gif")
                                  self.p_1 = PhotoImage(file = "1.gif")
                                  self.p_2 = PhotoImage(file = "2.gif")
                                  self.p_3 = PhotoImage(file = "3.gif")
                                  self.p_4 = PhotoImage(file = "4.gif")
                                  self.p_5 = PhotoImage(file = "5.gif")
                                  self.p_6 = PhotoImage(file = "6.gif")
                                  self.p_7 = PhotoImage(file = "7.gif")
                                  self.p_8 = PhotoImage(file = "8.gif")
                          
                          
                              def jouer(self):
                                  """Toutes les fonctions qui doivent être
                                     appellées pour jouer sont mises ici.
                                  """
                                  if self.partieEnCours == True and self.a_dePlateau.nombreMines > 0:
                                      self.a_dePlateau.genererGrille() 
                                      self.a_dePlateau.cacherGrille()
                          
                             
                              def gagner(self):
                                  """Le joueur a t-il gagner?"""
                                  if self.a_dePlateau.nombreMines <= 0:
                                      #Si /mapp/ et /mappCachee/ sont identiques
                                      #... alors c'est gagné !
                          
                                      for i in self.a_dePlateau.mappCachee:
                                          if not '*' in i:
                                              print("\n\nBravos vous avez gagné!!!!")
                                          
                                              return False
                                      
                          
                              def afficher(self):
                                  """Affiche le plateau de jeu en console."""
                                  #Affichage graphique
                                  for i in range(self.a_dePlateau.largBloc-1):
                                      for j in range(self.a_dePlateau.largBloc-1):
                                          
                                          if self.a_dePlateau.mappCachee[i-1][j-1] == '*':
                                              item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                       image = self.p_case)
                                              
                                          elif self.a_dePlateau.mappCachee[i][j] == '0':
                                              #A définir
                                              pass
                          
                                          elif self.a_dePlateau.mappCachee[i][j] == '1':
                                              item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                       image = self.p_1)
                          
                                          elif self.a_dePlateau.mappCachee[i][j] == '2':
                                              item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                       image = self.p_2)
                          
                                          elif self.a_dePlateau.mappCachee[i][j] == '3':
                                              item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                       image = self.p_3)
                          
                                          elif self.a_dePlateau.mappCachee[i][j] == '4':
                                              item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                       image = self.p_4)
                          
                                          elif self.a_dePlateau.mappCachee[i][j] == '5':
                                              item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                       image = self.p_5)
                          
                                          elif self.a_dePlateau.mappCachee[i][j] == '6':
                                              item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                       image = self.p_6)
                          
                                          elif self.a_dePlateau.mappCachee[i][j] == '7':
                                              item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                       image = self.p_7)
                          
                                          elif self.a_dePlateau.mappCachee[i][j] == '8':
                                              item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                       image = self.p_8)
                          
                                          elif self.a_dePlateau.mappCachee[i][j] == '@':
                                              item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                       image = self.p_croix)
                              
                              def regle(self):
                                  a = "\
                          Le but du jeu du démineur est de trouver toutes les mines présentes sur le\nterrain.\nLe terrain est chiffré, et chaque chiffre indique le nombre de bombes\n\
                          présentes dans les huit cases qui l'entoure:\nPour choisir une case, il vous faut rentrer la <ligne> puis la <colonne>sous\nforme de chiffres, un par un. Il vous sera donc demandé dans un premier\
                          temps la <ligne>, puis dans un deuxième temps la <colonne> allant de 0 à ", self.a_dePlateau.largBloc -1, ".\nTout chiffre superieur ou inférieur à ce nombre, ne sera pas accepté.\n\n\
                          0: Zéro bombe\n1: Une bombe\n2: Deux bombes\n ...\n9: C'est une case bombe\n\nC = Creuser; D = poser un drapeau\n\tBon Jeu et bonne chance."
                                  #Label
                                  texteRegle = Label(self.fenetreRegle, text = a)
                                  texteRegle.pack()
                          
                                  #Boutton Quiter
                                  bouQuitter = Button(self.fenetreRegle, text = "Quitter", command = self.fenetreRegle.QUIT)
                                  bouQuitter.pack(side = BOTTOM)
                          
                                  self.fenetreRegle.mainloop()
                                  
                                  
                          #-*-*- Fin de <Jeu> || Début de <Plateau> -*-*-#
                          
                          class Plateau(object):
                              """Permet de tenir à jour le plateau du jeu 'démineur'."""
                              def __init__(self):
                                  """
                                  Déclare les variables nécessaires.
                                  - mapp          (type:-Liste-)
                                  - longueur      (type:-Int-) (Nombre de cases: longueur²)
                                  - nombreMines   (type:-Int-)
                                  - mappCachee    (type:-Liste-)
                                  - nombreDrapeau (type:-Int-)
                          
                                  """
                                  self.mapp = []
                              
                                  self.mappCachee = []
                                  self.nombreMines = 0
                                  
                                  #Variables pour l'interface graphique
                                  self.tailleBloc = 20
                                  self.largBloc = 10   #Longueur de la grille: 10²
                                  self.largF = self.largBloc * self.tailleBloc 
                          
                                  
                                  
                              def genererGrille(self):
                                  """Génère une grille de démineur.
                                     Appel *placerBombe()*
                                     Appel *cacherGrille()*
                                     
                                  """
                                  #On construit un tableau de '0' de /longueur/²
                                  for i in range(self.largBloc):
                                      self.mapp.append([0] * self.largBloc)
                                      
                          
                                  #Appel de la fonction: placerBombe() en mettant à jour: /mapp/
                                  self.mapp = self.placerBombe()
                                  self.mapp = self.placerBombe()
                                  
                                      
                              def placerBombe(self):
                                  """Génère des nombres aléatoires
                                     pour placer une bombe et appel *chiffrerMap()*.
                                  """
                                  #On incrémente /nombreMines/ à chaque instance
                                  self.nombreMines += 1
                                  
                                  #On pose une bombe 'B' aléatoirement dans la /mapp/ suivant la longueur de celle-ci ->(self.largBloc)
                                  #Le numÃéro '9' (type:int) représente une bombe
                                  self.col, self.ligne, self.bombe = random.randrange(0, self.largBloc), random.randrange(0, self.largBloc), 9
                                  
                                  #On place la bombe aux coordonnées trouvées aléatoirement
                                  self.mapp[self.col][self.ligne] = self.bombe
                                  #Appel de la fonction chiffrerMap
                                  self.mapp = self.chiffrerMap(self.col, self.ligne)
                          
                                  return self.mapp
                          
                          
                              def chiffrerMap(self, col, ligne):
                                  """Permet de chiffrer ma /mapp/ pour
                                     savoir où se trouvent les bombes.
                                  """ 
                                  #Implémentation de l'algorithme pour chiffrer ma map
                                  #[[0, 0, 0, 0, 0],
                                  # [0, 0, 0, 0, 0],
                                  # [0, 0, B, 0, 0],
                                  # [0, 0, 0, 0, 0],
                                  # [0, 0, 0, 0, 0]]
                          
                                  #On parcours notre mapp à l'aide d'une double boucle
                                  #On ajoute dans une liste à part les 8 cases entourant la case actuelle
                                  #On regarde combien il y a de 'B'ombes dans cette /newL/.
                                  #La case actuelle prendra la valeur du nombre d'occurences de '9' dans ma /newL/
                                  
                                  for i in range(self.largBloc):      
                                      for j in range(self.largBloc):      
                                          newL = []
                                          
                                          for ii in range(max(0, i-1), min(i+2, self.largBloc)):         
                                              for jj in range(max(0, j-1), min(j+2, self.largBloc)):       
                                                  newL.append(self.mapp[ii][jj])
                                                  
                                          if self.mapp[i][j] != 9: #Le numéro '9' (type:int) représente une bombe
                                              self.mapp[i][j] = newL.count(9)                  
                                  newL = []
                                  return self.mapp
                          
                          
                              def cacherGrille(self):
                                  """Cache la /mapp/ de jeu en créant une mapp-like
                                     avec des '*' pour valeur.
                                  """
                                  #On construit un tableau de '0' de /largBloc/²
                                  for i in range(self.largBloc):
                                      self.mappCachee.append(['*'] * self.largBloc)
                          
                              
                              def poserDrapeau(self, event):
                                  """Permet de poser un drapeau sur une case donnée.
                                     Si: La case est cachée:
                                            - On place le drapeaux '@'
                          
                                     Sinon si: La cases contient déjà  un drapeau:
                                                  - On enlève le drapeau '@' et on la met en cachée '*'
                          
                                     Sinon: La case à déjà  été découverte:
                                               - Ne rien faire 'pass'                  
                                  """
                                  #On créer une variable /var/ qui prend pour valeur une
                                  #...céllule rentrée par l'utilisateur dans la fonction *action*
                                  #Sans oublier d'incrémenter ou de décrémenter /nombreMines/
                                  
                                  var = self.mappCachee[math.ceil(event.x / self.tailleBloc)][math.ceil(event.y / self.tailleBloc)]    
                                  
                                  if var == '*':
                                      var = '@'
                                      self.nombreMines -= 1
                                      
                                  elif var == '@':
                                      var = '*'
                                      self.nombreMines += 1
                                      
                                  else:
                                      pass
                          
                                  #On change le '*' de /mappCachee/ par la valeur de /var/ (type:string)
                                  self.mappCachee[math.ceil(event.x / self.tailleBloc)][math.ceil(event.y / self.tailleBloc)] = str(var)
                          
                                  return True
                          
                          
                              def creuser(self, event):
                                  """Permet de dévoiler une case dans
                                     la variable /mappCachee/
                                  """
                                  #Je créer une variable /var/
                                  #Qui prend comme valeur les coordonées de ma souris dans /mapp[event.x][event.y]/
                                  #On divise par /tailleBloc/ pour obtenir un nombre entier en /larBloc/ pour la longueur et /largBloc/ pour la hauteur
                                  #- si la case contient une bombe:
                                  #  - STOP
                                  #- si la case est déjà creusée:
                                  #  - Game over puis on stop la fonction
                                  #- sinon on retire le masque de la case str() pour pouvoir l'afficher
                                  #- Si la case vaut '0'
                                  #  - On regarde autour de cette case s'il y a d'autres '0'
                                  #  - Appel récursif de la fonction
                                  
                                  var = self.mapp[math.ceil(event.x / self.tailleBloc)][math.ceil(event.y / self.tailleBloc)]    
                                  
                                  if var == 9:
                                      self.mappCachee[math.ceil(event.x / self.tailleBloc)][math.ceil(event.y / self.tailleBloc)] = str(var)
                                      partieEnCours = False 
                                      return
                                  
                                  if self.mappCachee[math.ceil(event.x / self.tailleBloc)][math.ceil(event.y / self.tailleBloc)] == str(var):
                                      return
                                  
                                  else:
                                      self.mappCachee[math.ceil(event.x / self.tailleBloc)][math.ceil(event.y / self.tailleBloc)] = str(var)
                                      
                                      if var == 0: 
                                          #On regarde autour de cette case s'il y a d'autres '0'
                                          for ii in range(max(0, math.ceil(event.x / self.tailleBloc)-1), min(math.ceil(event.x / self.tailleBloc)+2, self.largBloc)):         
                                              for jj in range(max(0, math.ceil(event.y / self.tailleBloc)-1), min(math.ceil(event.y / self.tailleBloc)+2, self.largBloc)):
                                                  if self.mapp[ii][jj] == 0:
                                                      self.creuser2(ii, jj)
                                  return True
                          
                          
                              def creuser2(self, l, c):
                                  """Pour l'appelle récursif:
                                     l = ligne
                                     c = colonne
                                  """
                                  var = self.mapp[l][c]    
                                  
                                  if var == 9:
                                      self.mappCachee[l][c] = str(var)
                                      partieEnCours = False 
                                      return
                                  
                                  if self.mappCachee[l][c] == str(var):
                                      return
                                  
                                  else:
                                      self.mappCachee[l][c] = str(var)
                                      
                                      if var == 0: 
                                          #On regarde autour de cette case s'il y a d'autres '0'
                                          for ii in range(max(0, l-1), min(l+2, self.largBloc)):         
                                              for jj in range(max(0, c-1), min(c+2, self.largBloc)):
                                                  if self.mapp[ii][jj] == 0:
                                                      self.creuser2(ii, jj)
                                      
                          
                          #Sans oublier ca :-)
                          if __name__ == '__main__':
                              p = Jeu()
                              p.fenetre.mainloop()
                          
                          • Partager sur Facebook
                          • Partager sur Twitter
                            26 septembre 2010 à 20:01:46

                            Bonjour,

                            j'ai résolu il y a de ça quelques jours le problème du: index is out of range mais un autre problème est survenu.

                            Lorsque je clic sur le bouton <rafraîchir>, un appel de la fonction afficher se fait.
                            Cette fonction parcourt ma liste mappCachee.
                            Si il y a un '*' alors on affiche telle image à telle endroit.
                            Si il y a un 1 alors on affiche telle image à telle endroit
                            Si il y a un 2 ...

                            Mon programme ne plante pas, mais reste figé après avoir blité les images, comme si ma mainloop ne fonctionnait pas.

                            Est-ce que quelqu'un aurait une idée sur ce problème ?
                            Je vous donne mon code en vous remerciant d'avance.

                            Mon code:
                            class Jeu(object):
                                """Permet de gérer la partie."""
                                def __init__(self):
                                    """
                                    Instancie un objet du type <Plateau>.
                                    Déclare les variables nécessaires.
                                    - a_dePlateau   (type:-Instance-)
                                    - partieEnCours (type:-Booleen-)
                                    
                                    Créer les événements:
                                    - Boutons
                                    - Canvas
                                    - Gestion des clics
                            
                                    """
                                    #Variables nécessaires pour le déroulement de la partie
                                    self.a_dePlateau = Plateau()
                                    self.partieEnCours = True
                                    
                                    #Création des fenêtres
                                    self.fenetre = Tk()
                                    self.fenetreRegle = Tk()
                                    
                                    #Canvas
                                    self.can = Canvas(self.fenetre, bg = "dark grey", height = self.a_dePlateau.largF, \
                                                      width = self.a_dePlateau.largF)
                                    self.can.bind("<Button-1>", self.a_dePlateau.creuser)      #Creuse
                                    self.can.bind("<Button-3>", self.a_dePlateau.poserDrapeau) #Pose un drapeau
                                    self.can.pack(side = LEFT)
                            
                                    #Boutton Quitter
                                    bouQuitter = Button(self.fenetre, text = "Quitter", command = self.fenetre.destroy)
                                    bouQuitter.pack(side = BOTTOM)
                                    #Boutton Jouer
                                    bouJouer = Button(self.fenetre, text = "Générer une Grille", command = self.jouer)
                                    bouJouer.pack(side = BOTTOM)
                                    #Boutton Regle
                                    bouRegle = Button(self.fenetre, text = "Règles", command = self.regle)
                                    bouRegle.pack(side = BOTTOM)
                            
                                    #Boutton Rafraîchir grille
                                    bouRaf = Button(self.fenetre, text = "Rafraîchir", command = self.afficher)
                                    bouRaf.pack()
                            
                                    #Images -Chargement
                                    self.p_case = PhotoImage(file = "case.gif")
                                    self.p_croix = PhotoImage(file = "croix.gif")
                                    self.p_1 = PhotoImage(file = "1.gif")
                                    self.p_2 = PhotoImage(file = "2.gif")
                                    self.p_3 = PhotoImage(file = "3.gif")
                                    self.p_4 = PhotoImage(file = "4.gif")
                                    self.p_5 = PhotoImage(file = "5.gif")
                                    self.p_6 = PhotoImage(file = "6.gif")
                                    self.p_7 = PhotoImage(file = "7.gif")
                                    self.p_8 = PhotoImage(file = "8.gif")
                            
                                    
                                def jouer(self):
                                    """Toutes les fonctions qui doivent être
                                       appellées pour jouer sont mises ici.
                                    """
                                    self.a_dePlateau.genererGrille() 
                                    self.a_dePlateau.cacherGrille()
                            
                               
                                def gagner(self):
                                    """Le joueur a t-il gagner?"""
                                    if self.a_dePlateau.nombreMines <= 0:
                                        #Si /mapp/ et /mappCachee/ sont identiques
                                        #... alors c'est gagné !
                            
                                        for i in self.a_dePlateau.mappCachee:
                                            if not '*' in i:
                                                print("\n\nBravos vous avez gagné!!!!")
                                            
                                                return False
                                        
                            
                                def afficher(self):
                                    """Affichage graphique avec Tkinter"""
                                    #Affichage graphique
                                    for i in range(self.a_dePlateau.largBloc):
                                        for j in range(self.a_dePlateau.largBloc):
                                            if self.a_dePlateau.mappCachee[i][j] == '*':
                                                item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                         image = self.p_case)
                                                
                                            elif self.a_dePlateau.mappCachee[i][j] == '0':
                                                #A définir
                                                pass
                            
                                            elif self.a_dePlateau.mappCachee[i][j] == '1':
                                                item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                         image = self.p_1)
                            
                                            elif self.a_dePlateau.mappCachee[i][j] == '2':
                                                item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                         image = self.p_2)
                            
                                            elif self.a_dePlateau.mappCachee[i][j] == '3':
                                                item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                         image = self.p_3)
                            
                                            elif self.a_dePlateau.mappCachee[i][j] == '4':
                                                item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                         image = self.p_4)
                            
                                            elif self.a_dePlateau.mappCachee[i][j] == '5':
                                                item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                         image = self.p_5)
                            
                                            elif self.a_dePlateau.mappCachee[i][j] == '6':
                                                item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                         image = self.p_6)
                            
                                            elif self.a_dePlateau.mappCachee[i][j] == '7':
                                                item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                         image = self.p_7)
                            
                                            elif self.a_dePlateau.mappCachee[i][j] == '8':
                                                item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                         image = self.p_8)
                            
                                            elif self.a_dePlateau.mappCachee[i][j] == '@':
                                                item = self.can.create_image(i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc, \
                                                                         image = self.p_croix)
                            
                                    
                                
                                def regle(self):
                                    a = "\
                            Le but du jeu du démineur est de trouver toutes les mines présentes sur le\nterrain.\nLe terrain est chiffré, et chaque chiffre indique le nombre de bombes\n\
                            présentes dans les huit cases qui l'entoure:\nPour choisir une case, il vous faut rentrer la <ligne> puis la <colonne>sous\nforme de chiffres, un par un. Il vous sera donc demandé dans un premier\
                            temps la <ligne>, puis dans un deuxième temps la <colonne> allant de 0 à ", self.a_dePlateau.largBloc -1, ".\nTout chiffre superieur ou inférieur à ce nombre, ne sera pas accepté.\n\n\
                            0: Zéro bombe\n1: Une bombe\n2: Deux bombes\n ...\n9: C'est une case bombe\n\nC = Creuser; D = poser un drapeau\n\tBon Jeu et bonne chance."
                                    #Label
                                    texteRegle = Label(self.fenetreRegle, text = a)
                                    texteRegle.pack()
                            
                                    #Boutton Quiter
                                    bouQuitter = Button(self.fenetreRegle, text = "Quitter", command = self.fenetreRegle.QUIT)
                                    bouQuitter.pack(side = BOTTOM)
                            
                                    self.fenetreRegle.mainloop()
                                    
                                    
                            #-*-*- Fin de <Jeu> || Début de <Plateau> -*-*-#
                            
                            class Plateau(object):
                                """Permet de tenir à jour le plateau du jeu 'démineur'."""
                                def __init__(self):
                                    """
                                    Déclare les variables nécessaires.
                                    - mapp          (type:-Liste-)
                                    - longueur      (type:-Int-) (Nombre de cases: longueur²)
                                    - nombreMines   (type:-Int-)
                                    - mappCachee    (type:-Liste-)
                                    - nombreDrapeau (type:-Int-)
                            
                                    """
                                    self.mapp = []
                                
                                    self.mappCachee = []
                                    self.nombreMines = 0
                                    
                                    #Variables pour l'interface graphique
                                    self.tailleBloc = 20
                                    self.largBloc = 10   #Longueur de la grille: 10²
                                    self.largF = self.largBloc * self.tailleBloc 
                            
                                    
                                def genererGrille(self):
                                    """Génère une grille de démineur.
                                       Appel *placerBombe()*
                                       Appel *cacherGrille()*
                                       
                                    """
                                    #On construit un tableau de '0' de /longueur/²
                                    for i in range(self.largBloc):
                                        self.mapp.append([0] * self.largBloc)
                                        
                            
                                    #Appel de la fonction: placerBombe() en mettant à jour: /mapp/
                                    self.mapp = self.placerBombe()
                                    self.mapp = self.placerBombe()
                                    
                                        
                                def placerBombe(self):
                                    """Génère des nombres aléatoires
                                       pour placer une bombe et appel *chiffrerMap()*.
                                    """
                                    #On incrémente /nombreMines/ à chaque instance
                                    self.nombreMines += 1
                                    
                                    #On pose une bombe 'B' aléatoirement dans la /mapp/ suivant la longueur de celle-ci ->(self.largBloc)
                                    #Le numÃéro '9' (type:int) représente une bombe
                                    self.col, self.ligne, self.bombe = random.randrange(0, self.largBloc), random.randrange(0, self.largBloc), 9
                                    
                                    #On place la bombe aux coordonnées trouvées aléatoirement
                                    self.mapp[self.col][self.ligne] = self.bombe
                                    #Appel de la fonction chiffrerMap
                                    self.mapp = self.chiffrerMap(self.col, self.ligne)
                            
                                    return self.mapp
                            
                            
                                def chiffrerMap(self, col, ligne):
                                    """Permet de chiffrer ma /mapp/ pour
                                       savoir où se trouvent les bombes.
                                    """ 
                                    #Implémentation de l'algorithme pour chiffrer ma map
                                    #[[0, 0, 0, 0, 0],
                                    # [0, 0, 0, 0, 0],
                                    # [0, 0, B, 0, 0],
                                    # [0, 0, 0, 0, 0],
                                    # [0, 0, 0, 0, 0]]
                            
                                    #On parcours notre mapp à l'aide d'une double boucle
                                    #On ajoute dans une liste à part les 8 cases entourant la case actuelle
                                    #On regarde combien il y a de 'B'ombes dans cette /newL/.
                                    #La case actuelle prendra la valeur du nombre d'occurences de '9' dans ma /newL/
                                    
                                    for i in range(self.largBloc):      
                                        for j in range(self.largBloc):      
                                            newL = []
                                            
                                            for ii in range(max(0, i-1), min(i+2, self.largBloc)):         
                                                for jj in range(max(0, j-1), min(j+2, self.largBloc)):       
                                                    newL.append(self.mapp[ii][jj])
                                                    
                                            if self.mapp[i][j] != 9: #Le numéro '9' (type:int) représente une bombe
                                                self.mapp[i][j] = newL.count(9)                  
                                    newL = []
                                    return self.mapp
                            
                            
                                def cacherGrille(self):
                                    """Cache la /mapp/ de jeu en créant une mapp-like
                                       avec des '*' pour valeur.
                                    """
                                    #On construit un tableau de '0' de /largBloc/²
                                    for i in range(self.largBloc):
                                        self.mappCachee.append(['*'] * self.largBloc)
                            
                                
                                def poserDrapeau(self, event):
                                    """Permet de poser un drapeau sur une case donnée.
                                       Si: La case est cachée:
                                              - On place le drapeaux '@'
                            
                                       Sinon si: La cases contient déjà  un drapeau:
                                                    - On enlève le drapeau '@' et on la met en cachée '*'
                            
                                       Sinon: La case à déjà  été découverte:
                                                 - Ne rien faire 'pass'                  
                                    """
                                    #On créer une variable /var/ qui prend pour valeur une
                                    #...céllule rentrée par l'utilisateur dans la fonction *action*
                                    #Sans oublier d'incrémenter ou de décrémenter /nombreMines/
                                    
                                    var = self.mappCachee[math.ceil(event.x / self.tailleBloc)][math.ceil(event.y / self.tailleBloc)]    
                                    
                                    if var == '*':
                                        var = '@'
                                        self.nombreMines -= 1
                                        
                                    elif var == '@':
                                        var = '*'
                                        self.nombreMines += 1
                                        
                                    else:
                                        pass
                            
                                    #On change le '*' de /mappCachee/ par la valeur de /var/ (type:string)
                                    self.mappCachee[math.ceil(event.x / self.tailleBloc)][math.ceil(event.y / self.tailleBloc)] = str(var)
                            
                            
                                def creuser(self, event):
                                    """Permet de dévoiler une case dans
                                       la variable /mappCachee/
                                    """
                                    #Je créer une variable /var/
                                    #Qui prend comme valeur les coordonées de ma souris dans /mapp[event.x][event.y]/
                                    #On divise par /tailleBloc/ pour obtenir un nombre entier en /larBloc/ pour la longueur et /largBloc/ pour la hauteur
                                    #- si la case contient une bombe:
                                    #  - STOP
                                    #- si la case est déjà creusée:
                                    #  - Game over puis on stop la fonction
                                    #- sinon on retire le masque de la case str() pour pouvoir l'afficher
                                    #- Si la case vaut '0'
                                    #  - On regarde autour de cette case s'il y a d'autres '0'
                                    #  - Appel récursif de la fonction
                                    
                                    var = self.mapp[math.ceil(event.x / self.tailleBloc)][math.ceil(event.y / self.tailleBloc)]
                                   
                                    
                                    if var == 9:
                                        self.mappCachee[math.ceil(event.x / self.tailleBloc)][math.ceil(event.y / self.tailleBloc)] = str(var)
                                        partieEnCours = False 
                                        return
                                    
                                    if self.mappCachee[math.ceil(event.x / self.tailleBloc)][math.ceil(event.y / self.tailleBloc)] == str(var):
                                        return
                                    
                                    else:
                                        self.mappCachee[math.ceil(event.x / self.tailleBloc)][math.ceil(event.y / self.tailleBloc)] = str(var)
                                        
                                        if var == 0: 
                                            #On regarde autour de cette case s'il y a d'autres '0'
                                            for ii in range(max(0, math.ceil(event.x / self.tailleBloc)-1), min(math.ceil(event.x / self.tailleBloc)+2, self.largBloc)):         
                                                for jj in range(max(0, math.ceil(event.y / self.tailleBloc)-1), min(math.ceil(event.y / self.tailleBloc)+2, self.largBloc)):
                                                    if self.mapp[ii][jj] == 0:
                                                        self.creuser2(ii, jj)
                                    #return True
                            
                            
                                def creuser2(self, l, c):
                                    """Pour l'appelle récursif:
                                       l = ligne
                                       c = colonne
                                    """
                                    var = self.mapp[l][c]    
                                    
                                    if var == 9:
                                        self.mappCachee[l][c] = str(var)
                                        partieEnCours = False 
                                        return
                                    
                                    if self.mappCachee[l][c] == str(var):
                                        return
                                    
                                    else:
                                        self.mappCachee[l][c] = str(var)
                                        
                                        if var == 0: 
                                            #On regarde autour de cette case s'il y a d'autres '0'
                                            for ii in range(max(0, l-1), min(l+2, self.largBloc)):         
                                                for jj in range(max(0, c-1), min(c+2, self.largBloc)):
                                                    if self.mapp[ii][jj] == 0:
                                                        self.creuser2(ii, jj)
                                        
                            
                            
                            if __name__ == '__main__':
                                p = Jeu()
                                p.fenetre.mainloop()
                            


                            Les principales fonctions sont:
                            • afficher
                            • __init__ (dans la classe <Jeu>)

                            • Partager sur Facebook
                            • Partager sur Twitter
                              27 septembre 2010 à 1:15:24

                              cool, j'la'avais pas vu celui-là ...
                              donnez en argument la path vers un dossier contenant des images ...
                              exemple:
                              jos@unit:~/Bureau/mines$ python mines.py /media/mes_images

                              le lien est sur cette page.

                              Image utilisateur

                              la fin de jeu n'est pas du tout travaillé :(
                              • Partager sur Facebook
                              • Partager sur Twitter

                              Python c'est bon, mangez-en. 

                                29 septembre 2010 à 0:29:32

                                Bonjour à tous,
                                Je ne savais pas trop quoi faire en ce moment et j'ai trouvé cette idée de démineur plutôt sympa.
                                Il s'agit d'un démineur assez complet:
                                • Affichage du temps
                                • Affichage du nombre de drapeaux restants
                                • Gestion des scores
                                • 3 tailles différentes

                                Le tout réalisé avec tkinter.

                                Image utilisateur
                                Image utilisateur

                                Et voici le code:
                                api.py
                                #!/usr/bin/env python
                                # -*- coding: utf-8 -*-
                                from random import sample
                                
                                class Case:
                                    """classe représentant une case"""
                                    def __init__(self, index):
                                        self.index = index
                                        self.type = Api.CASE_COVER
                                        self.hasFlag = False
                                        self.hasMine = False
                                        self.number = 0
                                        self.tkItem = None
                                
                                    def reset(self):
                                        """réinitialise la case"""
                                        self.type = Api.CASE_COVER
                                        self.hasFlag = False
                                        self.hasMine = False
                                        self.number = 0
                                        
                                    @property
                                    def hasNumber(self):
                                        return self.number != 0
                                
                                 
                                
                                class Api:
                                    """la classe principale"""
                                    #les différents type de case
                                    CASE_COVER, CASE_VISIBLE, CASE_FLAG, CASE_MINE, CASE_EXPLOSE, CASE_FLAG_FALSE = range(6)
                                    def __init__(self):
                                        self.isStarted = False
                                        self.CbCaseChange = lambda x: None
                                        self.cbGameOver = lambda x: None
                                        self.cbWin = lambda: None
                                        self.cbFlagChange = lambda x: None
                                        self.cbStart = lambda : None
                                
                                    def setCb(self, caseChange, flagChange, gameOver, win, start):
                                        """configuration des callbacks"""
                                        self.cbCaseChange = caseChange
                                        self.cbFlagChange = flagChange
                                        self.cbGameOver = gameOver
                                        self.cbWin = win
                                        self.cbStart = start
                                
                                    def setConfig(self, size, nbrMines):
                                        self.size = size
                                        self.rows, self.cols = size
                                        self.nbrMines = nbrMines
                                        self.create()
                                
                                    def create(self):
                                        """créé la list représentant les cases"""
                                        self.nbrCases = self.rows * self.cols
                                        self.cases = [Case(i) for i in range(self.nbrCases)]
                                        self.new()
                                
                                    def getCases(self):
                                        return self.cases
                                
                                    def new(self):
                                        """réinitialise la map"""
                                        self.isStarted = False
                                        #le nombre de reapeau restant
                                        self.flagRemain = self.nbrMines
                                        #réinitialise les cases
                                        for case in self.cases:
                                            case.reset()
                                        #place les mines
                                        self.placeMine()
                                        #nombre de case restante
                                        self.caseRemain = self.nbrCases
                                        self.cbFlagChange(self.flagRemain)
                                
                                    def placeMine(self):
                                        """place les mines sur la map"""
                                        for case in sample(self.cases, self.nbrMines):
                                            case.hasMine = True
                                
                                    def demine(self, case):
                                        """démine la case passée en argument"""
                                        #si c'est la première case déminée
                                        if self.caseRemain == self.nbrCases:
                                            #on démarre la partie
                                            self.isStarted = True
                                            self.cbStart()
                                        #si la partie n'est pas démarée, on s'arrête là
                                        if not self.isStarted:
                                            return
                                        #si la case est encore couverte
                                        if case.type == self.CASE_COVER:
                                            #si la case est minée
                                            if case.hasMine:
                                                #c'est perdu
                                                self.setGameOver(case)
                                                self.isStarted = False
                                                self.cbGameOver()
                                                return
                                
                                            #le nombre de mines autour de la case
                                            numMine = self.getMineArround(case)
                                            #la case est déminée
                                            case.type = self.CASE_VISIBLE
                                            #1 case de moins
                                            self.caseRemain -= 1
                                            #si le nombre de cases restantes est égale au nombre de mines
                                            if self.caseRemain == self.nbrMines:
                                                #c'est gagnée
                                                self.isStarted = False
                                                self.cbWin()
                                            
                                            #si il y a des mines autour
                                            if numMine:
                                                case.number = numMine
                                            #sinon on démine les cases environnantes
                                            else:
                                                for c in self.getAroundCase(case):
                                                    self.demine(c)
                                
                                            #appéle le callback 'caseChange' pour mettre à jour le coté graphique
                                            self.cbCaseChange(case)
                                
                                    def getAroundCase(self, case):
                                        """retourne les cases environnantes (c'est un peu tordu, doit y avoir mieux!!)"""
                                        i = case.index
                                        c = self.cols
                                        return [self.cases[t] for r in (-c, 0, c) for t in (i+r-1, i+r, i+r+1) if t/c == (i+r)/c and 0<=t<len(self.cases)]
                                
                                    def getMineArround(self, case):
                                        """retourne le nombre de mines autour de la case"""
                                        return len([0 for c in self.getAroundCase(case) if c.hasMine])
                                
                                    def setGameOver(self, caseExplose):
                                        """permet d'afficher la position des mines et les drapeaux mal placés"""
                                        #c'est la case qui a explosée
                                        caseExplose.type = self.CASE_EXPLOSE
                                        self.cbCaseChange(caseExplose)
                                
                                        for case in self.cases:
                                            #si la case a une mine
                                            if case.hasMine:
                                                #si elle n'a pas de drapeau
                                                if case.type != self.CASE_FLAG:
                                                    #si ce n'est pas la case qui a explosée
                                                    if case != caseExplose:
                                                        #affiche la mine
                                                        case.type = self.CASE_MINE
                                                        self.cbCaseChange(case)
                                
                                            #si la case n'a pas de mine et un drapeau
                                            elif case.type == self.CASE_FLAG:
                                                #affiche un drapeau mal placé
                                                case.type = self.CASE_FLAG_FALSE
                                                self.cbCaseChange(case)
                                
                                    def switchFlag(self, case):
                                        """ajoute/retire un drapeau sur la case"""
                                        #si la partie n'est pas commencé
                                        if not self.isStarted:
                                            return
                                
                                        switch = {self.CASE_FLAG: self.CASE_COVER, self.CASE_COVER: self.CASE_FLAG}
                                        #si la case à un drapeau ou est recouverte
                                        if switch.has_key(case.type):
                                            case.type = switch[case.type]
                                            #ajoute ou retire un drapeau
                                            self.flagRemain += {self.CASE_COVER: 1, self.CASE_FLAG: -1}[case.type]
                                            #met à jour la case (graphique)
                                            self.cbCaseChange(case)
                                            #met à jour le nombre de drapeaux restant
                                            self.cbFlagChange(self.flagRemain)
                                


                                demineur.py
                                #!/usr/bin/env python
                                # -*- coding: utf-8 -*-
                                
                                import Tkinter as tk
                                from api import Api
                                import os
                                import sys
                                import pickle
                                import tkFont
                                
                                #la couleur de fond
                                BG = "#062369"
                                
                                class ResourceHandler:
                                    """classe permettant une gestion plus aisée des images"""
                                    def __init__(self, path="img"):
                                        self.path = path
                                        self.imgs = {}
                                        self.load()
                                
                                    def load(self):
                                        """charge les images dand le dict self.imgs"""
                                        for img in os.listdir(self.path):
                                            path = os.path.join(self.path, img)
                                            name = os.path.splitext(img)[0]
                                            
                                            img = tk.PhotoImage ( file=path)
                                            self.imgs[name] = img
                                
                                    def get(self, imgName):
                                        """retourne une image en fonction de son nom"""
                                        return self.imgs[imgName]
                                
                                    def getBtn(self, btnName):
                                        """retourne les 3 images d'un boutons (normal, over, down)"""
                                        capName = btnName.capitalize()
                                        btn = self.get("btn%s"%capName)
                                        btnDown = self.get("btn%sDown"%capName)
                                        btnOver = self.get("btn%sOver"%capName)
                                
                                        return btn, btnDown, btnOver
                                
                                    def getCases(self):
                                        """retorune les images des cases"""
                                        l = ("cover", "empty", "flag", "mine", "over", "explose", "flagfalse")
                                        return dict([(name, self.get("case%s"%name.capitalize())) for name in l])
                                
                                    def getBd(self, img, clr="blue"):
                                        """retourne les images des bordures (rouge ou bleue)"""
                                        clr = clr.capitalize()
                                        img = img.capitalize()
                                        return self.get("bg%s%s"%(img, clr))
                                
                                
                                class MyButton(tk.Label):
                                    """La classe des boutons personnalisés"""
                                    def __init__(self, parent, btns, command=lambda x: None, data=None):
                                        tk.Label.__init__(self, parent, image=btns[0], bg=BG, bd=0)
                                        self.btns = btns
                                        self.command = command
                                        self.data = data
                                        self.bind ( "<Button-1>", self.onClick)
                                        self.bind ( "<ButtonRelease-1>", self.onRelease)
                                        self.bind("<Enter>", self.onEnter)
                                        self.bind("<Leave>", self.onLeave)
                                
                                    def onClick(self, e):
                                        self.config(image=self.btns[1])
                                        self.command(self.data)
                                
                                    def onRelease(self, e):
                                        self.config(image=self.btns[2])
                                
                                    def onEnter(self, e):
                                        self.config(image=self.btns[2])
                                
                                    def onLeave(self, e):
                                        self.config(image=self.btns[0])
                                
                                
                                class TkCase(tk.Label):
                                    """la classe représentant une case"""
                                    def __init__(self, parent, imgs, case, api):
                                        tk.Label.__init__(self, parent, bd=0, padx=0, pady=0, fg="#0b2664")
                                        self.imgs = imgs
                                        self.api = api
                                        self.setImg("cover")
                                        self.case = case
                                        self.bind("<Enter>", self.onCaseEnter)
                                        self.bind("<Leave>", self.onCaseLeave)
                                        self.bind("<Button-1>", self.onDemine)
                                        self.bind("<Button-3>", self.onFlag)
                                
                                    def onCaseEnter(self, e):
                                        """lorsque le pointeur entre dans la case"""
                                        #si la case est encore recouverte
                                        if self.case.type == Api.CASE_COVER:
                                            self.setImg("over")
                                
                                    def onCaseLeave(self, e):
                                        """lorsque le pointeur quitte la case"""
                                        #si la case est encore recouverte
                                        if self.case.type == Api.CASE_COVER:
                                            self.setImg("cover")
                                
                                    def onDemine(self, e):
                                        """lorsque l'utilisateur fait un click gauche sur la case"""
                                        #on démine
                                        self.api.demine(self.case)
                                
                                    def onFlag(self, e):
                                        """lorsque l'utilisateur fait un click droit sur la case"""
                                        #on switch le drapeau
                                        self.api.switchFlag(self.case)
                                        
                                    def setImg(self, img):
                                        """change l'image de la case"""
                                        self.config(image=self.imgs[img])
                                
                                    def setNumber(self, num):
                                        """affiche un numero dans la case"""
                                        self.config(compound=tk.CENTER, text=str(num))
                                
                                    def reset(self):
                                        """recouvre la case"""
                                        self.config(text="")
                                        self.setImg("cover")
                                
                                
                                class TkMap(tk.Frame):
                                    """la classe réprésentant la map"""
                                    def __init__(self, parent, config):
                                        tk.Frame.__init__(self, parent)
                                        self.parent = parent
                                        self.res = ResourceHandler()
                                        #initialisation de l'api
                                        self.api = Api()
                                        #configure les callbacks
                                        self.api.setCb(self.setCase, parent.onFlagChange, parent.onGameOver,
                                            parent.onWin, parent.onStart)
                                        self.size = None
                                        #la couleur de la bordure
                                        self.clr = "blue"
                                        self.setConfig(config)
                                
                                    def setConfig(self, config):
                                        #détruit tous les widgets
                                        for w in self.winfo_children():
                                            w.destroy()
                                        #met à jour les donnée
                                        self.size, self.nbrMines = config
                                        self.rows, self.cols = self.size
                                        #configure l'api
                                        self.api.setConfig(self.size, self.nbrMines)
                                        #créé la bordure bleu
                                        self.createBorder()
                                        #la frame contenant les cases
                                        self.frameMap = tk.Frame(self)
                                        #création des cases
                                        self.createCases()
                                        self.frameMap.grid(row=1, column=1, columnspan=self.cols, rowspan=self.rows)
                                
                                    def new(self):
                                        """rédémarre une partie (avec la même configuration)"""
                                        #réinitialise l'api
                                        self.api.new()
                                        #réinitialise les cases
                                        for case in self.api.getCases():
                                            case.tkItem.reset()
                                
                                    def setClr(self, clr):
                                        """change la couleur de la bordure"""
                                        if clr != self.clr:
                                            self.clr = clr
                                            for name, tkBd in self.listTkBd:
                                                tkBd.config(image=self.res.getBd(name, clr))
                                
                                    def createBorder(self):
                                        """créé la bordure"""
                                        row, col = self.size
                                        #les fragment de la bordure sont stockés, permettant de changer sa couleur
                                        #les fragment sont stockés dans le sens horaire, permettant de faire 
                                        #une animation lors d'une victoire
                                        listBg = [("topLeft", (0, 0), None)]
                                        for i in range(col):
                                            listBg+=[("top", (0, i+1), tk.N)]
                                        listBg += [("topRight", (0, col+1), None)]
                                        for i in range(row):
                                            listBg += [("right", (i+1, col+1), tk.E)]
                                        listBg += [("bottomRight", (row+1, col+1), None)]
                                        li = []
                                        for i in range(col):
                                            li += [("bottom", (row+1, i+1), tk.S)]
                                        listBg += (reversed(li))
                                        listBg += [("bottomLeft", (row+1, 0), None)]
                                        li = []
                                        for i in range(row):
                                            li += [("left", (i+1, 0), tk.W)]
                                        listBg+=(reversed(li))
                                
                                        self.listTkBd = []
                                        for name, pos, sticky in listBg:
                                            row, col = pos
                                            lbl = tk.Label(self, image=self.res.getBd(name), bd=0)
                                            lbl.grid(row=row, column=col, sticky=sticky)
                                            self.listTkBd.append((name, lbl))
                                
                                    def anim(self, index=0, clr="red"):
                                        """anime la bordure"""
                                        name, lbl = self.listTkBd[index]
                                        lbl.config(image=self.res.getBd(name, clr))
                                
                                        if index+1 < len(self.listTkBd):
                                            self.timerId = self.after(10, lambda i=index: self.anim(i+1, clr))
                                        elif clr == "red":
                                            self.timerId = self.after(10, lambda : self.anim(0, "blue"))
                                        #lorsque l'animation est terminée
                                        else:
                                            #affiche la page de score (si besoin)
                                            self.parent.showScore()
                                        
                                    def createCases(self):
                                        """création des cases"""
                                        for case in self.api.getCases():
                                            #calcul les coordonnées de la cases
                                            row, column = divmod(case.index, self.cols)
                                            #instancie la case
                                            tkCase = TkCase(self.frameMap, self.res.getCases(), case, self.api)
                                            case.tkItem = tkCase
                                            tkCase.grid(row=row, column=column)
                                
                                    def setCase(self, case):
                                        """met à jour l'image de la case"""
                                        tkCase = case.tkItem
                                        #si la case est déminée
                                        if case.type == Api.CASE_VISIBLE:
                                            tkCase.setImg("empty")
                                            #si elle a un nombre (de mines autour)
                                            if case.hasNumber:
                                                tkCase.setNumber(case.number)
                                        #si la case n'est pas déminée
                                        else:
                                            imgName = {Api.CASE_COVER: "cover", Api.CASE_FLAG: "flag", Api.CASE_MINE: "mine",
                                                Api.CASE_EXPLOSE: "explose", Api.CASE_FLAG_FALSE: "flagfalse"}[case.type]
                                
                                            tkCase.setImg(imgName)
                                
                                
                                class TkMenu(tk.Frame):
                                    """classe réprésentant le menu"""
                                    def __init__(self, parent):
                                        tk.Frame.__init__(self, parent)
                                        self.res = ResourceHandler()
                                        self.clr = "blue"
                                        self.showBorder()
                                
                                    def showBorder(self):
                                        """affiche la bordure du menu"""
                                        listBg = [(("menuTop"), (0, 0), (1, 3), None), (("menuLeft"), (1, 0), (7, 1), tk.W),
                                            (("menuCenter"), (4, 1), (1, 1), tk.W), (("menuBottom"), (8, 0), (1, 3), None),
                                            (("menuRight"), (1, 2), (7, 1), tk.W)]
                                
                                        self.listTkBd = []
                                        for name, pos, span, sticky in listBg:
                                            row, column = pos
                                            rowspan, columnspan = span
                                            lbl = tk.Label(self, image=self.res.getBd(name), bd=0)
                                            lbl.grid(row=row, column=column, rowspan=rowspan, columnspan=columnspan, sticky=sticky)
                                            self.listTkBd.append((name, lbl))
                                
                                    def setBtns(self, info):
                                        """affiche et configure les boutons"""
                                        for i, btn in enumerate(info):
                                            i += {True: 2, False: 1}[i > 2]
                                            name, command, data = btn
                                            MyButton(self, btns=self.res.getBtn(name), command=command, data=data).grid(row=i, column=1, sticky=tk.N)
                                
                                    def setClr(self, clr):
                                        """change la couleur de la bordure"""
                                        if clr != self.clr:
                                            self.clr = clr
                                            for name, tkBd in self.listTkBd:
                                                tkBd.config(image=self.res.getBd(name, clr))
                                
                                
                                class TkInfo(tk.Frame):
                                    """classe qui affiche le temps et le nombre de drapeaux restants"""
                                    def __init__(self, parent):
                                        tk.Frame.__init__(self, parent, bg=BG, relief=tk.SUNKEN, bd=2, padx=5, pady=5)
                                        self.res = ResourceHandler()
                                        self.show()
                                
                                    def show(self):
                                        """création des widget"""
                                        font = tkFont.Font(size=18)
                                        tk.Label(self, image=self.res.get("clock"), bd=0, bg=BG).pack(side=tk.LEFT)
                                        self.varTime = tk.StringVar(value="00:00")
                                        tk.Label(self, textvariable=self.varTime, bd=0, bg=BG, fg="white", width=5, font=font).pack(side=tk.LEFT)
                                        tk.Label(self, width=5, bg=BG).pack(side=tk.LEFT)
                                        tk.Label(self, image=self.res.get("flag"), bd=0, bg=BG).pack(side=tk.LEFT)
                                        self.varFlag = tk.StringVar()
                                        tk.Label(self, textvariable=self.varFlag, bd=0, bg=BG, fg="white", width=3, font=font).pack(side=tk.LEFT)
                                
                                    def setFlag(self, val):
                                        """change le nombre de drapeaux restants"""
                                        self.varFlag.set(str(val))
                                
                                    def setTime(self, time):
                                        """change le temps"""
                                        timeStr = "%02i:%02i"%divmod(time, 60)
                                        self.varTime.set(timeStr)
                                
                                
                                class TkScore(tk.Frame):
                                    """classe qui affiche les scores"""
                                    def __init__(self, parent, cfgs, cfgId):
                                        tk.Frame.__init__(self, parent, bg=BG)
                                        self.parent = parent
                                        self.cfgs = cfgs
                                        self.res = ResourceHandler()
                                        self.font = tkFont.Font(size=12)
                                        self.numScore = 10
                                        self.placeEntry = -1
                                        self.create()
                                        #charge les scores
                                        with open("score") as f:
                                            self.allScores = pickle.load(f)
                                        self.setConfig(cfgId)
                                        
                                    def create(self):
                                        """créé la frame qui affiche la taille de la map et le nombre de mines"""
                                        self.frameScore = tk.Frame(self, bg=BG, relief=tk.SUNKEN, bd=2, padx=3, pady=3)
                                        frameInfo = tk.Frame(self, bg=BG, relief=tk.SUNKEN, bd=2, padx=3, pady=3)
                                        self.varEntry = tk.StringVar()
                                        tk.Label(frameInfo, image=self.res.get("size"), bd=0, bg=BG).pack(side=tk.LEFT)
                                        self.varSize = tk.StringVar()
                                        tk.Label(frameInfo, textvariable=self.varSize, font=self.font, fg="white", bd=0, bg=BG).pack(side=tk.LEFT)
                                        tk.Label(frameInfo, width=5, bg=BG).pack(side=tk.LEFT)
                                        tk.Label(frameInfo, image=self.res.get("mine"), bd=0, bg=BG).pack(side=tk.LEFT)
                                        self.varMine = tk.StringVar()
                                        tk.Label(frameInfo, textvariable=self.varMine, font=self.font, fg="white", bd=0, bg=BG).pack(side=tk.LEFT)
                                        frameBtn = tk.Frame(self,bg=BG)
                                        MyButton(frameBtn, self.res.getBtn("clear"), self.onClear).pack(padx=10, side=tk.LEFT)
                                        MyButton(frameBtn, self.res.getBtn("valid"), self.onValid).pack(padx=10, side=tk.LEFT)
                                        frameInfo.grid(pady=5)
                                        frameBtn.grid(row=2)
                                        self.bind_all("<KeyPress-Return>", self.onValid)
                                
                                    def write(self):
                                        """écrit les scores dans le fichier"""
                                        with open("score", "w") as f:
                                            pickle.dump(self.allScores, f)
                                
                                    def setConfig(self, cfgId):
                                        """change la configuration"""
                                        self.cfg = self.cfgs[cfgId]
                                        self.cfgId = cfgId
                                        self.actualScores = self.allScores[self.cfgId]
                                        size, numMines = self.cfg
                                        self.varSize.set("%sx%s"%size)
                                        self.varMine.set(str(numMines))
                                
                                    def showScore(self):
                                        """affiche les scores"""
                                        self.parent.pack_propagate(0)
                                        #efface les scores
                                        for w in self.frameScore.winfo_children():
                                            w.destroy()
                                        #cache les widget de la frame principale
                                        for w in self.parent.winfo_children():
                                            w.pack_forget()
                                        
                                        #si il y a au moins un score
                                        if self.actualScores:
                                            for i, info in enumerate(self.actualScores):
                                                name, time = info
                                                timeStr = "%02i:%02i"%divmod(time, 60)
                                                #la place
                                                tk.Label(self.frameScore, text="%i-"%(i+1), bg=BG, fg="white",
                                                    font=self.font).grid(row=i, column=0, sticky=tk.E)
                                                #si l'utilisateur peut rentrer son nom
                                                if self.placeEntry == i:
                                                    entry = tk.Entry(self.frameScore, textvariable=self.varEntry,
                                                        insertbackground="white", width=15, bg=BG, fg="white", font=self.font)
                                                    entry.grid(row=i, column=1, sticky=tk.W, ipadx=15)
                                                    entry.focus_force()
                                                #sinon on affiche le nom
                                                else:
                                                    tk.Label(self.frameScore, text=name, bg=BG, fg="white",
                                                        font=self.font).grid(row=i, column=1, sticky=tk.W, ipadx=15)
                                                #affiche le temps
                                                tk.Label(self.frameScore, text=timeStr, bg=BG, fg="white",
                                                    font=self.font).grid(row=i, column=2, sticky=tk.W, ipadx=15)
                                        #si il n'y a pas de score
                                        else:
                                            #un label vide
                                            tk.Label(self.frameScore, bg=BG, width=20).grid()
                                        
                                        self.frameScore.grid(row=1)
                                        self.pack()
                                
                                    def isBest(self, time):
                                        """retourne True si le temps rentre dans la liste, sinon False"""
                                        if len(self.actualScores) < self.numScore:
                                            return True
                                
                                        if time < self.actualScores[-1][1]:
                                            return True
                                
                                        return False
                                
                                    def addScore(self, time):
                                        """permet d'ajouter un nouveau score"""
                                        #si il y a au moins un score
                                        if self.actualScores:
                                            #récupère la place du nouveau score
                                            for i, info in enumerate(self.actualScores):
                                                if time < info[1]:
                                                    self.placeEntry = i
                                                    self.actualScores.insert(i, ["", time])
                                                    break
                                            #si c'est la dernière plave
                                            else:
                                                #on l'joute à la liste
                                                self.actualScores.append(["", time])
                                                self.placeEntry = i + 1
                                            #si le nombre de scores est supérieur au nombre max de scores
                                            if len(self.actualScores) > self.numScore:
                                                        self.actualScores.pop()
                                        #si c'est le premier score
                                        else:
                                            self.placeEntry = 0
                                            self.actualScores.append(["", time])
                                
                                        #affiche les scores (avec une Entry)
                                        self.showScore()
                                
                                    def onValid(self, e):
                                        """le bouton 'valider' (ou la touche Entrée) est cliquer"""
                                        #si il y a un nouveau score
                                        if self.placeEntry != -1:
                                            #récupère le nom,  et sauvegarde les scores
                                            name = self.varEntry.get()
                                            self.actualScores[self.placeEntry][0] = name
                                            self.write()
                                        #efface la frame des scores
                                        self.placeEntry = -1
                                        self.varEntry.set("")
                                        self.parent.pack_propagate(1)
                                        self.pack_forget()
                                        self.parent.packWidget()
                                
                                    def onClear(self, e):
                                        """le bouton 'clear' est cliqué"""
                                        #détruit les labels des scores
                                        for w in self.frameScore.winfo_children():
                                            w.destroy()
                                        tk.Label(self.frameScore, bg=BG, width=20).grid()
                                        #met à jour le fichier
                                        self.actualScores = self.allScores[self.cfgId] = []
                                        self.write()
                                
                                
                                class Demineur(tk.Tk):
                                    """la classe principale du démineur"""
                                    #ids de la taille de la map
                                    SMALL_ID, MIDDLE_ID, BIG_ID = range(3)
                                    def __init__(self):
                                        tk.Tk.__init__(self)
                                        #la couleur d'arrière plan
                                        self.config(bg=BG)
                                        #les 3 tailles possibles ((ligne, colonne), nombre de mines)
                                        self.cfgs = {self.SMALL_ID: ((10, 10), 15), self.MIDDLE_ID: ((16, 16), 40), self.BIG_ID: ((24, 24), 120)}
                                        #la config de départ
                                        self.cfgId = self.MIDDLE_ID
                                        self.cfg = self.cfgs[self.MIDDLE_ID]
                                        self.time = 0
                                        #l'id du timer, permettant d'arrêter temps
                                        self.timerId = None
                                        #Les scores
                                        self.tkScore = TkScore(self, self.cfgs, self.cfgId)
                                        #le temps et le nombre de drapeaux
                                        self.tkInfo = TkInfo(self)
                                        #le menu gauche
                                        self.tkMenu = TkMenu(self)
                                        self.createMenuBtns()
                                        #la map
                                        self.tkMap = TkMap(self, self.cfg)
                                        #configure les scores
                                        self.tkScore.setConfig(self.cfgId)
                                        self.packWidget()
                                
                                    def packWidget(self):
                                        """affiche les widgets"""
                                        self.tkInfo.pack()
                                        self.tkMenu.pack(side=tk.LEFT)
                                        self.tkMap.pack(side=tk.LEFT)
                                
                                    def createMenuBtns(self):
                                        """création et initialisation des boutons du menus"""
                                        BtnsInfo = (("quit", self.onQuit, None), ("refresh", self.onRefresh, None),
                                            ("score", self.onScore, None), ("small", self.onResize, self.SMALL_ID),
                                            ("middle", self.onResize, self.MIDDLE_ID), ("big", self.onResize, self.BIG_ID))
                                        self.tkMenu.setBtns(BtnsInfo)
                                
                                    def setClr(self, clr):
                                        """change la couleur des bordures"""
                                        self.tkMap.setClr(clr)
                                        self.tkMenu.setClr(clr)
                                
                                    def tick(self):
                                        """permet de modifier le temps"""
                                        self.time += 1
                                        self.tkInfo.setTime(self.time)
                                        self.timerId = self.after(1000, self.tick)
                                
                                    def onQuit(self, e):
                                        """le bouton 'quit' est cliqué"""
                                        sys.exit(0)
                                
                                    def onRefresh(self, e):
                                        """le bouton 'refresh' est cliqué"""
                                        self.resetTimer()
                                        self.setClr("blue")
                                        self.tkMap.new()
                                
                                    def onScore(self, e):
                                        """le bouton 'score' est cliqué"""
                                        self.tkScore.showScore()
                                        self.tkScore.pack()
                                        
                                    def onFlagChange(self, num):
                                        """le nombre de drapeau a changé"""
                                        self.tkInfo.setFlag(num)
                                
                                    def onResize(self, cfgId):
                                        """la taille de la map a changée"""
                                        if cfgId != self.cfgId:
                                            self.setClr("blue")
                                            self.resetTimer()
                                            self.cfgId = cfgId
                                            self.cfg = self.cfgs[cfgId]
                                            self.tkScore.setConfig(cfgId)
                                            self.tkMap.setConfig(self.cfg)
                                
                                    def onGameOver(self):
                                        """la partie est perdu"""
                                        self.after_cancel(self.timerId)
                                        self.setClr("red")
                                
                                    def onWin(self):
                                        """la partie est gagnée"""
                                        self.after_cancel(self.timerId)
                                        self.tkMap.anim()
                                
                                    def showScore(self):
                                        """affiche les scores si besoin"""
                                        if self.tkScore.isBest(self.time):
                                            self.tkScore.addScore(self.time)
                                
                                    def resetTimer(self):
                                        """remet le temps à zero"""
                                        self.time = 0
                                        self.tkInfo.setTime(0)
                                        if self.timerId:
                                            self.after_cancel(self.timerId)
                                
                                    def onStart(self):
                                        """la patie commence, affiche le temps"""
                                        self.timerId = self.after(1000, self.tick)
                                
                                        
                                demineur = Demineur()
                                demineur.mainloop()
                                


                                Et voici le zip contenant les fichiers et les images: demineur.zip
                                J'ai programmé avec python 2.6. ça ne fonctionne pas avec python 3, mais ça doit pouvoir s'arranger facilement.
                                J'ai testé sur Ubuntu, ça à l'air de fonctionner correctement.

                                un petit:
                                python demineur.py

                                pour lancer le programme.
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  29 septembre 2010 à 7:20:57

                                  nyko77,
                                  d'habitude je trouve les rendus Tk plutôt môches, mais là ...
                                  respect pour le design ... :waw:
                                  • Partager sur Facebook
                                  • Partager sur Twitter

                                  Python c'est bon, mangez-en. 

                                    29 septembre 2010 à 8:28:14

                                    Citation : josmiley

                                    nyko77,
                                    d'habitude je trouve les rendus Tk plutôt môches, mais là ...
                                    respect pour le design ... :waw:



                                    +1

                                    Très jolie rendu, c'est incroyable ce que l'on peut faire avec Tkinter ... quand on s'y connaît ;) .
                                    Ton démineur n'est pas mal non plus Josmiley. J'adore particulièrement le backGround. Pourquoi ne pas charger un backGround différent à chaque partie gagnée ou perdue ? :)

                                    Je vais paraître ridicule avec mon petit démineur fait avec Tkinter (Mon rendu est... nul ! ... et le mot 'nul' est faible :D )

                                    Question pour nyko77:

                                    CASE_COVER, CASE_VISIBLE, CASE_FLAG, CASE_MINE, CASE_EXPLOSE, CASE_FLAG_FALSE = range(6)
                                    

                                    => Ici se sont bien des variables globales, on est d'accord ?

                                    self.CbCaseChange = lambda x: None
                                    

                                    => Je ne comprends pas ce que tu cherches à faire ici, peux-tu m'expliquer ?

                                    import tkFont
                                    

                                    => Simpas comme classe, je ne connaissais pas.

                                    class MyButton(tk.Label):
                                        """La classe des boutons personnalisés"""
                                        def __init__(self, parent, btns, command=lambda x: None, data=None):
                                    

                                    => Pareil, je n'ai pas tout compris.


                                    Ton rendu m'a convaincu d'apprendre (parfaitement ? ;du moins sur le bout des doigts) Tkinter.
                                    Je ne m'attendais pas à un tel rendu.

                                    Bonne journée,
                                    Realmagma.
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      29 septembre 2010 à 10:56:20

                                      Des participants. Super !

                                      Félicitations pour vos contributions, en particulier nyko77 pour le très beau rendu avec tkinter.

                                      J'ai toujours pas eu le temps de faire mon interface Pygame, je voulais m'amuser avec et créer de jolies animations pour avoir un truc un peu sympa, mais la charge de boulot que j'ai actuellement ne me permet malheureusement pas de m'y coller (surtout que je perds du temps à jouer au démineur en console au taff... :lol: ).

                                      Bravo, en tout cas.
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                      Zeste de Savoir, le site qui en a dans le citron !
                                        29 septembre 2010 à 21:16:57

                                        Citation : realmagma


                                        CASE_COVER, CASE_VISIBLE, CASE_FLAG, CASE_MINE, CASE_EXPLOSE, CASE_FLAG_FALSE = range(6)
                                        


                                        => Ici se sont bien des variables globales, on est d'accord ?



                                        En faite pas tout à fait. Ce sont plutôt des attributs de classe. Ils ne sont pas accessibles partout dans mon programme. Si je veux y accéder depuis le classe API, je peux utiliser self.CASE_COVER ou API.CASE_COVER, en dehors de la classe uniquement avec API.CASE_COVER. L'avantage de les mettre en dehors du __init__ est que je peux y accéder sans instancier la classe.

                                        Citation : realmagma


                                        class MyButton(tk.Label):
                                            """La classe des boutons personnalisés"""
                                            def __init__(self, parent, btns, command=lambda x: None, data=None):
                                        


                                        => Pareil, je n'ai pas tout compris.



                                        L'argument command attend une fonction, ou une méthode (c'est la fonction appelé lorsque l'on clique sur le bouton). si un jour (je ne sais pour quelle raison), je souhaite créer un bouton qui n'appèle pas de fonction, et que j'ai simplement mis command=None, j'aurais un beau message d'erreur lors du clique sur le bouton, du type:

                                        TypeError: 'NoneType' object is not callable


                                        lambda sert à créer simplement de petites fonctions:

                                        lambda x: None
                                        

                                        est équivalent à:
                                        def maFonction(x):
                                            return None
                                        


                                        C'est le même principe pour mes attributs de callbacks.


                                        Citation : josmiley


                                        nyko77,
                                        d'habitude je trouve les rendus Tk plutôt môches, mais là ...
                                        respect pour le design ... :waw:



                                        En faite j'ai passé plus de temps à utiliser (et comprendre) gimp, qu'à programmer le démineur.
                                        Je trouve également l'aspect de tkinter un peu vieillot. Je m'en sert d'habitude uniquement pour me faire une interface rapidement, pour tester mes programmes.
                                        wxpython ou pyqt sont quand même plus recommandés pour faire des application digne de ce nom.
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          30 septembre 2010 à 15:50:57

                                          [HS] Je vais essayer de faire ce projet! Merci Nohar! [hs]
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            2 octobre 2010 à 17:32:49

                                            Bonjour! C'est exactement le mini projet qu'il me fallait pour bien comprendre la POO ! J'y suis pas encore mais j'ai reussi à faire la phase 1 :ange: Avant de continuer j'aimerais avoir votre analyse de mon code et des remarques , améliorations etc (si vous avez le temps et l'envie)..... Merci beaucoup!


                                            #!/usr/bin/env python
                                            # -*- coding: cp1252 -*-
                                            
                                            
                                            #Exercice du SDZ : Démineur phase 1 by FIVETAG
                                            import random
                                            #Pour avoir un terrain aléatoire
                                            
                                            #Defintion des variables globales qui vont représenter les différentes cases
                                            global MINE , DEMINE , TERRE , EXPLOSE
                                            MINE='x'
                                            TERRE='o'
                                            DEMINE='+'
                                            EXPLOSE='@'
                                            
                                            def terrain_alea(longeur,maxMines):
                                                '''fonction qui sert a faire un terrain de maniére aléatoire avec longeur et un nombre maximum de mines'''
                                                chaine=""
                                                for x in range(longeur): 
                                                    m=0
                                                    if random.randint(0,3)==1 and m<=maxMines: 
                                                        chaine+=MINE
                                                        m+=1
                                                    else:
                                                        chaine+=TERRE
                                                return chaine
                                            
                                            
                                            
                                            
                                            #CODE
                                            class Plateau :
                                                '''Plateau de jeu'''
                                                def __init__(self,terrain,hauteur):
                                                    self.cases=[] #cases du terrain
                                                    self.terrain=terrain #terrain ce présentant sous une chaine de caractére
                                                    self.hauteur=hauteur #hauteur et largeur du terrain  
                                                    x,y=0,0 #coordonnées successives des différentes cases
                                                    for c in terrain :
                                                        self.cases.append(Case(str(c),(x,y)))
                                                        #c= etat de la case , x= coordonnée en abscisse , y = coordonnées en ordonnée
                                                        x+=1 #et un de plus en abscisse
                                                        if(x%(hauteur)==0):
                                                            # on incremente l'ordonnée y de 1 et on remet l'abscisse x à 0 si le nombre de cases alignées a atteint la hauteur (j'aurait du mettre la cote)
                                                            x=0
                                                            y+=1
                                                   
                                                def __iter__(self):
                                                    '''methode speciale,  a=Plateau(),
                                                    cette methode me permet de faire :
                                                    "for x in a :
                                                        ..."
                                                    ici elle devra retourner chaque elements de self.plateau'''
                                                    for case in self.cases:
                                                            yield case #retourne chaque case c'est un generator
                                                            
                                                def reset(self):
                                                    self.__init__(self.terrain,self.hauteur) #:B 
                                            
                                                     
                                                     
                                            #Question : si j'enléve object et les paranthéses ça change quoi?
                                            class Case(object):
                                                '''Une case du jeu'''
                                                def __init__(self,etat,coords):
                                                    '''etat : miné , déminé , découvert ou pas , coords: coordonnées de la case'''
                                                    self.etat=etat 
                                                    self.coords=coords
                                                    self.x=coords[0] #abscisse
                                                    self.y=coords[1] #ordonnée
                                                def setEtat(self,newEtat): #c'est un mutateur (j'ai bien appris mon cours!)
                                                    self.etat=newEtat
                                                    
                                                def __getitem__(self, key):
                                                    '''methode speciale, , a=Plateau(),
                                                    cette methode permet de faire par exemple :
                                                    "x=a[0]"
                                                    ici elle devra retourner l'element de self.plateau demande'''
                                                    return self.coords[key]  #retourne la case demande 
                                            
                                                def __repr__(self):
                                                    '''lorsque qu'on retourne l'objet , l'etat est affiché'''
                                                    return self.etat
                                            
                                            
                                            
                                            
                                            
                                            
                                            #INTERFACE
                                            class Interface :
                                                '''Interface rudimentaire du démineur'''
                                                def __init__ (self,plateau):
                                                    print "-"*25+"DEMINEUR"+"-"*25+"\n"+"-"*60+"\n\
                                            Menu Principal  : %c:mine  , %c:terre , %c:terre déminée\n"%(EXPLOSE,TERRE,DEMINE)+"-"*60+"\n"
                                                    self.plateau=plateau
                                            
                                                def getPlateau(self): 
                                                    '''c'est un ascessseur qui permet d'affichezr le plateau et de l'actualiser!'''
                                                    chaine=""
                                                    nc=0
                                                    for c in self.plateau :
                                                        if (nc==int(c[1])): #je met tout dans une chaine comme ça ça m'affichera un tableau , c[1] c'est la coordonnée en Y et c[0] en x
                                                            nc+=1
                                                            chaine+="\n"+" "*30 #donc a chaque fois que l'ordonnée change on saute une ligne! 
                                                        if str(c)==MINE:  #pour ne pas afficher les mines au joueur ! On affiche alors de la terre pour qu'il se fasse piégé *vv*
                                                            chaine+=TERRE 
                                                        else:
                                                            chaine+=str(c) #bon sion on affiche ce qu'il y a donc logiquement de la terre!
                                                    chaine+="\n" #enfin je rajoute un saut de ligne pour que ça soit un peut aéré!
                                                    print chaine   
                                                        
                                                        
                                                def aide(self):
                                                    '''Permet d'afficher l'aide au joueur'''
                                                    print "AIDE : Le but est de dévoiler toutes les cases sans mines  \n"
                                            
                                                def creuser(self,reponse=False):
                                                    '''La méthode qui nous permet de faire l'action principale : creuser !'''
                                                    if reponse: #reponse permet si elle est vraie (True) donner la solution de la partie 
                                                        for c in self.plateau: #on parcours toutes les cases du plateau courant
                                                            if  str(c)==MINE : #si la case est une mine on la met a l'état explosé (oui sinon dans getPlateau les mines ne peuvent pas être affiché .. ça serait peut être mieux de faire la langochat au niveau de getPlateau?       
                                                                c.setEtat(EXPLOSE)
                                                            else :
                                                                c.setEtat(DEMINE) #Ca c'est facultatif mais c'est pour suivre ma logique : si j'afffiche les cases explosés alors il faut montrer celle qui ne le sont pas (parce que la terre par definition peut cacher des mines)
                                                    else:
                                                        coords=raw_input("Veuillez rentrez la valeur de l'abscisse et de l'ordonnée de la case à creuser sous la forme : X*Y \n")
                                                        coordsDe=coords.split('*') #On décompose la chaine rentré dans une liste avec le séparateur * donc :
                                                        x=int(coordsDe[0]) #l'absciesse c'est le premier element de la liste , on n'oublie pas de la mettre en entier
                                                        y=int(coordsDe[1]) #l'ordonnée est le second et dernier élement de la liste , on n'oublie pas encor de le mettre en entier
                                                        for c in self.plateau:  #on parcours les cases du plateau
                                                            if c[0]==x and c[1]==y and str(c)==MINE or str(c)==EXPLOSE : #si la valeur d'abscissse correspond à la valeur d'abscisse d'une instance de Case (idem pour y) et si l'etat est miné (ou explosé au cas ou si on creuse une autre fois la mine) 
                                                                chaine= "vous etes tombez sur une mine  :(" #on affiche un bien triste message
                                                                c.setEtat(EXPLOSE) #et on met l'etat explosé a notre case
                                                                break #et on sort de cette boucle (element trouvé!
                                                            elif c[0]==x and c[1]==y:
                                                                chaine= "pas de mine en vue!"
                                                                c.setEtat(DEMINE) #ben là on a de la chance , pas de mine donc on met l'état deminé
                                                                break
                                                            else :
                                                                chaine="La case demandée n'existe pas :B" #et sinon le joueur est mauvais en math dans ce cas on affiche ceci
                                                        print chaine #et on affiche la reponse 
                                                    
                                            
                                            #PRG PRINCIPAL
                                                        
                                            
                                            
                                            #Initialisation du pateau de jeu et de l'interface  par instanciation de classes
                                            jeu=Plateau(terrain_alea(100,5),10)
                                            interface=Interface(jeu)
                                            interface.getPlateau()
                                            
                                            
                                            #On fait une boucle infini qui attend a chaque fois la réponse de l'utilisateur 
                                            while(1):
                                                attente=raw_input("(a)ide \n(c)reuser\n(l)angochat\n(r)ecommencer\n(*q)uitter\n ")
                                                
                                            #en fonction de la reponse on execute une action
                                                if attente=='a':
                                                    interface.aide()
                                                    interface.getPlateau()
                                                elif attente=='c':
                                                    interface.creuser()
                                                    interface.getPlateau()
                                                elif attente=='l':
                                                    interface.creuser(True) #True pour le parametre reponse du module creuser
                                                    interface.getPlateau()
                                                elif attente=='r':
                                                    jeu.reset()
                                                    interface.getPlateau()
                                                else :
                                                    break;  #Byebye 
                                            
                                            
                                            
                                            #Je débute en POO , et j'aimerais voir les améliorations possibles , les critiques et les erreurs relatives  mon code pour que je m'améliore par la suite , je trouve difficile mais j'en vois l'utilité de séparé le code de l'interface \
                                            #et ce qui me titille c'est que par exemple le module creuser est dans l'INTERFACE mais devrait il pas être dans la partie CODE , merci de votre aide!
                                            




                                            EDIT : Conseil de Fred ajoutés
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                            Anonyme
                                              2 octobre 2010 à 17:45:04

                                              ligne 125 : Il manque un ":" après le else

                                              Ensuite les "-", c'est moche

                                              print "-"*50 # c'est plus beau
                                              


                                              Je sais pas si j'ai bien compris le code, mais il est où le démineur?
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                2 octobre 2010 à 17:58:48

                                                Le démineur ? ... Test mon code sur ta machine ...
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                Anonyme
                                                  2 octobre 2010 à 18:21:14

                                                  le démineur c'est le "+" il me semble, mais le problème c'est que tu rentres les coordonnées et que tu n'obliges pas le déplacement de 1 en 1.

                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    2 octobre 2010 à 19:31:36

                                                    Ah je ne voyez pas les règles de la même façon ( dans la règle du démineur il n'est pas obligatoire de ce dép lasser de 1 en 1 on peut se "téléporter" et le démineur n'apparait pas sur la carte enfin ces "pas" aparaissent )
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      3 octobre 2010 à 12:03:17

                                                      Bonjour,

                                                      j'ai continué mon petit démineur en reprenant tes images Nyko77 (ne m'en veux pas, elles sont super bien faites :p )
                                                      Je rencontre un problème, d'ordre technique qui est le suivant:

                                                      Dans ma classe <JeuTk>, lorsque je clic-gauche ou clic-droit, j'appelle deux fonctions où l'une est associée au clic-G et l'autre au clic-D.
                                                      J'aimerai qu'elles appellent une seule et même fonction qui, pourrait savoir si tel ou tel bouton à été pressé. (Clic-G ? Clic-D ?)

                                                      Auriez-vous une solution à me proposer?
                                                      Merci d'avance

                                                      P.S: Je fais ça pour éviter de rafraîchir à chaque fois que je clic sur une case.

                                                      EDIT: Ma question est: Comment cette fonction (qui est appelée grâce au clicG ou clicD) peut savoir si c'est soit le clic-G ou soit le clic-D qui a été pressé?

                                                      Un bout de mon code:
                                                      self.can.bind("<Button-1>", self.a_dePlateau.creuser)      #Creuser
                                                      self.can.bind("<Button-3>", self.a_dePlateau.poserDrapeau) #Pose un drapeau
                                                      


                                                      Je préférerai ceci:
                                                      self.can.bind("<Button-1>", self.afficher)      
                                                      self.can.bind("<Button-3>", self.afficher) 
                                                      
                                                      def afficher(self):
                                                          Si c'est un clic-G:
                                                              #Exécuter ce bout de code
                                                          Sinon si c'est un clic-D:
                                                              #Exécuter ce bout de code
                                                      


                                                      Image utilisateur
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        3 octobre 2010 à 13:09:16

                                                        Il faut utiliser la commande lambda de cette manière:
                                                        #constante à définir quelque part
                                                        CLICK_G, CLICK_D = range(2)
                                                        
                                                        self.can.bind("<Button-1>", lambda: self.afficher(CLICK_G))      
                                                        self.can.bind("<Button-3>", lambda: self.afficher(CLICK_D)) 
                                                        
                                                        def afficher(self, click):
                                                            if click == CLICK_G:
                                                                #Exécuter ce bout de code
                                                            elif click == CLICK_D:
                                                                #Exécuter ce bout de code
                                                        


                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          3 octobre 2010 à 17:29:14

                                                          Merci pour ta réponse Nyko77, mais elle ne me convient pas. :D
                                                          Pourquoi ? Tout simplement parce que je souhaite faire quelque chose comme ceci:

                                                          def afficher(self, event):
                                                                  """Affichage graphique avec Tkinter
                                                                     Appel de la méthode *etatDuJeu*
                                                          
                                                                  """
                                                                  
                                                                  if event == CLICK_G:
                                                                      self.a_dePlateau.creuser(event)
                                                                  elif event == CLICK_D:
                                                                      self.a_dePlateau.poserDrapeau(event)
                                                          


                                                          Je récupère les coordonnées de ma souris (event.x; event.y)dans ces deux méthodes.

                                                          def poserDrapeau(self, event):
                                                              var = self.mappCachee[math.ceil(event.x / self.tailleBloc)-1][math.ceil(event.y / self.tailleBloc)-1]
                                                          


                                                          Auriez-vous une autre solution ?
                                                          Merci d'avance.

                                                          Realmagma


                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                            3 octobre 2010 à 20:00:42

                                                            En effet, autant pour moi. Voilà ce que tu cherches:

                                                            #constante à définir quelque part
                                                            CLICK_G, CLICK_D = range(2)
                                                            
                                                            self.can.bind("<Button-1>", lambda event: self.afficher(event, CLICK_G))      
                                                            self.can.bind("<Button-3>", lambda event: self.afficher(event, CLICK_D)) 
                                                            
                                                            def afficher(self, event, click):
                                                                if click == CLICK_G:
                                                                    self.a_dePlateau.creuser(event)
                                                                elif click == CLICK_D:
                                                                    self.a_dePlateau.poserDrapeau(event)
                                                            
                                                            • Partager sur Facebook
                                                            • Partager sur Twitter
                                                              4 octobre 2010 à 13:14:48

                                                              Hum, pourquoi me suis-je obstiné à mettre une étoile devant le: event
                                                              J'avais fait quelque chose comme:

                                                              self.can.bind("<Button-1>", lambda event: self.afficher(event, CLICK_G))      
                                                              self.can.bind("<Button-3>", lambda event: self.afficher(event, CLICK_D)) 
                                                              
                                                              def afficher(self, *event, click): 
                                                                  if click == CLICK_G:
                                                                      self.a_dePlateau.creuser(event)
                                                                  elif click == CLICK_D:
                                                                      self.a_dePlateau.poserDrapeau(event)
                                                              


                                                              En tout cas merci, ça marche.
                                                              Voici mon code complet, bien entendu l'ergonomie est plutôt moche par rapport à Nyko77 et Josmiley; mais ont s'y fait vite.
                                                              Il me reste plus qu'a trouver comment mettre une image sur les boutons et à afficher "gagner" ou "perdu".


                                                              ################################
                                                              ## Les Modules Importés:(2)   ##
                                                              #
                                                              from tkinter import *
                                                              import random
                                                              import math
                                                              
                                                                                                                             
                                                              #-*-*- <Les Classes> || Début de <Jeu> -*-*-#
                                                              CLICK_G, CLICK_D = range(2)
                                                              class Jeu(object):
                                                                  """Permet de gérer la partie."""
                                                                  def __init__(self):
                                                                      """
                                                                      Instancie un objet du type <Plateau>.
                                                                      Déclare les variables nécessaires.
                                                                      - a_dePlateau   (type:-Instance-)
                                                                      - partieEnCours (type:-Booleen-)
                                                                      
                                                                      Créer les événements:
                                                                      - Boutons
                                                                      - Canvas
                                                                      - Gestion des clics
                                                              
                                                                      """
                                                                      #Variables nécessaires pour le déroulement de la partie
                                                                      self.a_dePlateau = Plateau()
                                                                      #self.partieEnCours = True
                                                                      
                                                                      #Création des fenêtres
                                                                      self.fenetre = Tk()
                                                                      
                                                                      #Canvas
                                                                      self.can = Canvas(self.fenetre, bg = "#004899", height = self.a_dePlateau.largF, \
                                                                                        width = self.a_dePlateau.largF, relief = GROOVE, bd = 3)
                                                                      self.can.bind("<Button-1>", lambda event: self.afficher(event, CLICK_G)) 
                                                                      self.can.bind("<Button-3>", lambda event: self.afficher(event, CLICK_D)) 
                                                                      self.can.pack(side = LEFT)
                                                                      
                                                                      #Boutton Quitter
                                                                      bouQuitter = Button(self.fenetre, text = "Quitter", command = self.fenetre.destroy)
                                                                      bouQuitter.pack(side = BOTTOM)
                                                                      #Boutton Jouer
                                                                      bouJouer = Button(self.fenetre, text = "Grille (10 Mines)", command = self.jouer)
                                                                      bouJouer.pack(side = BOTTOM)
                                                              
                                                                      #Boutton Jouer
                                                                      bouJouer_25 = Button(self.fenetre, text = "Grille (20 Mines)", command = self.partie_20Mines)
                                                                      bouJouer_25.pack(side = BOTTOM)
                                                                      #Boutton Regle
                                                                      bouRegle = Button(self.fenetre, text = "Règles", command = self.regle)
                                                                      bouRegle.pack(side = BOTTOM)
                                                              
                                                              
                                                                      #Images -Chargement
                                                                      self.p_case = PhotoImage(file = "caseCover.gif")
                                                                      self.p_vide = PhotoImage(file = "caseEmpty.gif")
                                                                      self.p_croix = PhotoImage(file = "caseFlag.gif")
                                                                      self.p_1 = PhotoImage(file = "numero_1.gif")
                                                                      self.p_2 = PhotoImage(file = "numero_2.gif")
                                                                      self.p_3 = PhotoImage(file = "numero_3.gif")
                                                                      self.p_4 = PhotoImage(file = "numero_4.gif")
                                                                      self.p_5 = PhotoImage(file = "numero_5.gif")
                                                                      self.p_6 = PhotoImage(file = "numero_6.gif")
                                                                      self.p_7 = PhotoImage(file = "numero_7.gif")
                                                                      self.p_8 = PhotoImage(file = "numero_8.gif")
                                                              
                                                                      
                                                                  def jouer(self):
                                                                      """Toutes les fonctions qui doivent être
                                                                         appellées pour jouer sont mises ici.
                                                                      """
                                                                      self.can.delete(ALL)
                                                                      self.a_dePlateau.mappCachee = []
                                                                      self.a_dePlateau.mapp = []
                                                                      self.a_dePlateau.nombreMines = 0
                                                                      
                                                                      self.a_dePlateau.genererGrille() 
                                                                      self.a_dePlateau.cacherGrille()
                                                                      
                                                              
                                                              
                                                                  def partie_20Mines(self):
                                                                      """Permet de jouer une partie avec 20 mines"""
                                                                      self.a_dePlateau.placementMines = 20
                                                                      self.jouer()
                                                              
                                                                      
                                                                  def etatDuJeu(self):
                                                                      """Le joueur a t-il gagner ?
                                                                          Appel de la fméthode *initialisation*
                                                              
                                                                      """
                                                                      if self.a_dePlateau.perdu == False:
                                                                          if self.a_dePlateau.nombreMines <= 0:
                                                                              #Si /mapp/ et /mappCachee/ sont identiques alors c'est gagné !
                                                                              
                                                                              if self.a_dePlateau.mappCachee == self.a_dePlateau.mapp:
                                                                                  print("Gagne")
                                                                                  self.initialisation()   
                                                                              elif self.a_dePlateau.mappCachee != self.a_dePlateau.mapp or self.a_dePlateau.perdu == True:
                                                                                  print("Perdu")
                                                                                  self.initialisation()         
                                                                      else:
                                                                          print("Perdu")
                                                                          self.initialisation()
                                                                            
                                                              
                                                                  def initialisation(self):
                                                                      """Initialise les données du jeu.
                                                                         Cette méthode est appelée dans *etatDuJeu*
                                                              
                                                                      """
                                                                      self.can.delete(ALL)
                                                                      self.a_dePlateau.mappCachee = []
                                                                      self.a_dePlateau.mapp = []
                                                                      self.a_dePlateau.nombreMines = 0
                                                                      self.a_dePlateau.perdu = False
                                                                      self.jouer()
                                                                      
                                                                  def afficher(self, event, clic):
                                                                      """Affichage graphique avec Tkinter
                                                                         Appel de la méthode *etatDuJeu*
                                                              
                                                                      """
                                                                      if clic == CLICK_G:
                                                                          self.a_dePlateau.creuser(event)
                                                                      elif clic == CLICK_D:
                                                                          self.a_dePlateau.poserDrapeau(event)
                                                                      
                                                                               
                                                                      for i in range(self.a_dePlateau.largBloc):
                                                                          for j in range(self.a_dePlateau.largBloc):
                                                                              
                                                                              if self.a_dePlateau.mappCachee[i][j] == 10:
                                                                                      
                                                                                  item = self.can.create_image((i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                               (j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                           image = self.p_case)
                                                                                  
                                                                              elif self.a_dePlateau.mappCachee[i][j] == 0:
                                                                                  item = self.can.create_image((i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                               (j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                           image = self.p_vide)
                                                              
                                                                              elif self.a_dePlateau.mappCachee[i][j] == 1:
                                                                                  item = self.can.create_image((i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                               (j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                           image = self.p_1)
                                                              
                                                                              elif self.a_dePlateau.mappCachee[i][j] == 2:
                                                                                  item = self.can.create_image((i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                               (j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                           image = self.p_2)
                                                              
                                                                              elif self.a_dePlateau.mappCachee[i][j] == 3:
                                                                                  item = self.can.create_image((i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                               (j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                           image = self.p_3)
                                                              
                                                                              elif self.a_dePlateau.mappCachee[i][j] == 4:
                                                                                  item = self.can.create_image((i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                               (j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                           image = self.p_4)
                                                              
                                                                              elif self.a_dePlateau.mappCachee[i][j] == 5:
                                                                                  item = self.can.create_image((i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                               (j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                           image = self.p_5)
                                                              
                                                                              elif self.a_dePlateau.mappCachee[i][j] == 6:
                                                                                  item = self.can.create_image((i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                               (j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                           image = self.p_6)
                                                              
                                                                              elif self.a_dePlateau.mappCachee[i][j] == 7:
                                                                                  item = self.can.create_image((i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                               (j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                           image = self.p_7)
                                                              
                                                                              elif self.a_dePlateau.mappCachee[i][j] == 8:
                                                                                  item = self.can.create_image((i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                               (j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                           image = self.p_8)
                                                              
                                                                              elif self.a_dePlateau.mappCachee[i][j] == 9:
                                                                                  item = self.can.create_image((i * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                               (j * self.a_dePlateau.tailleBloc + self.a_dePlateau.largBloc), \
                                                                                                           image = self.p_croix)
                                                                              self.etatDuJeu()
                                                                                      
                                                                  
                                                                  def regle(self):
                                                                      a = """
                                                              Le but du jeu du démineur est de trouver toutes les mines présentes sur le terrain.
                                                              Composé de cases, il vous suffit de cliquer dessus pour dévoiler cette même case.
                                                              Le terrain est chiffré, et chaque chiffre indique le nombre de bombes présentes dans les huit cases qui l'entoure:\n\n
                                                              Action:
                                                              <Clic-Gauche> = Dévoiler une case
                                                              <Clic-Droit>  = Poser un drapeau
                                                              0123456789 = nombre de bombes dans les huit cases adjacentes
                                                                          """
                                                                      #Fenêtre
                                                                      fenetreRegle = Tk()
                                                                      
                                                                      #Label
                                                                      texteRegle = Label(fenetreRegle, text = a)
                                                                      texteRegle.pack()
                                                              
                                                                      fenetreRegle.mainloop()
                                                                      
                                                                      
                                                              #-*-*- Fin de <Jeu> || Début de <Plateau> -*-*-#
                                                              
                                                              class Plateau(object):
                                                                  """Permet de tenir à jour le plateau du jeu 'démineur'."""
                                                                  def __init__(self):
                                                                      """
                                                                      Déclare les variables nécessaires.
                                                                      - mapp          (type:-Liste-)
                                                                      - longueur      (type:-Int-) (Nombre de cases: longueur²)
                                                                      - nombreMines   (type:-Int-)
                                                                      - mappCachee    (type:-Liste-)
                                                                      - nombreDrapeau (type:-Int-)
                                                              
                                                                      """
                                                                      self.mapp = []
                                                                  
                                                                      self.mappCachee = []
                                                                      self.nombreMines = 0
                                                                      self.placementMines = 10 #Combien de mines doit on placer dans une partie
                                                                      
                                                                      #Variables pour l'interface graphique
                                                                      self.tailleBloc = 30 
                                                                      self.largBloc = 10   #Longueur de la grille: 10²
                                                                      self.largF = self.largBloc * self.tailleBloc
                                                              
                                                                      self.perdu = False
                                                              
                                                                      
                                                                  def genererGrille(self):
                                                                      """Génère une grille de démineur.
                                                                         Appel *placerBombe()*
                                                                         Appel *cacherGrille()*
                                                                         
                                                                      """
                                                                      #On construit un tableau de 0 de /longueur/²
                                                                      for i in range(self.largBloc):
                                                                          self.mapp.append([0] * self.largBloc)
                                                                          
                                                                      for i in range(self.placementMines):
                                                                          #Appel de la fonction: placerBombe() en mettant à jour: /mapp/
                                                                          self.mapp = self.placerBombe()
                                                                      
                                                                          
                                                                  def placerBombe(self):
                                                                      """Génère des nombres aléatoires
                                                                         pour placer une bombe et appel *chiffrerMap()*.
                                                                      """
                                                                      #On incrémente /nombreMines/ à chaque instance
                                                                      self.nombreMines += 1
                                                                      
                                                                      #On pose une bombe 9 aléatoirement dans la /mapp/ suivant la longueur de celle-ci ->(self.largBloc)
                                                                      #Le numéro 9 (type:int) représente une bombe
                                                                      self.col, self.ligne, self.bombe = random.randrange(0, self.largBloc), random.randrange(0, self.largBloc), 9
                                                                      
                                                                      #On place la bombe aux coordonnées trouvées aléatoirement
                                                                      self.mapp[self.col][self.ligne] = self.bombe
                                                                      #Appel de la fonction chiffrerMap
                                                                      self.mapp = self.chiffrerMap(self.col, self.ligne)
                                                              
                                                                      return self.mapp
                                                              
                                                              
                                                                  def chiffrerMap(self, col, ligne):
                                                                      """Permet de chiffrer ma /mapp/ pour
                                                                         savoir où se trouvent les bombes.
                                                                      """ 
                                                                      #Implémentation de l'algorithme pour chiffrer ma map
                                                                      #[[0, 0, 0, 0, 0],
                                                                      # [0, 0, 0, 0, 0],
                                                                      # [0, 0, 9, 0, 0],
                                                                      # [0, 0, 0, 0, 0],
                                                                      # [0, 0, 0, 0, 0]]
                                                              
                                                                      #On parcours notre mapp à l'aide d'une double boucle
                                                                      #On ajoute dans une liste à part les 8 cases entourant la case actuelle
                                                                      #On regarde combien il y a de 9 dans cette /newL/.
                                                                      #La case actuelle prendra la valeur du nombre d'occurences de 9 dans ma /newL/
                                                                      
                                                                      for i in range(self.largBloc):      
                                                                          for j in range(self.largBloc):      
                                                                              newL = []
                                                                              
                                                                              for ii in range(max(0, i-1), min(i+2, self.largBloc)):         
                                                                                  for jj in range(max(0, j-1), min(j+2, self.largBloc)):       
                                                                                      newL.append(self.mapp[ii][jj])
                                                                                      
                                                                              if self.mapp[i][j] != 9: #Le numéro 9 (type:int) représente une bombe
                                                                                  self.mapp[i][j] = newL.count(9)                  
                                                                      newL = []
                                                                      return self.mapp
                                                              
                                                              
                                                                  def cacherGrille(self):
                                                                      """Cache la /mapp/ de jeu en créant une mapp-like
                                                                         avec des 10 pour valeur (représente '*').
                                                                      """
                                                                      #On construit un tableau de 10 (*) de /largBloc/²
                                                                      for i in range(self.largBloc):
                                                                          self.mappCachee.append([10] * self.largBloc)
                                                              
                                                                  
                                                                  def poserDrapeau(self, event):
                                                                      """Permet de poser un drapeau sur une case donnée.
                                                                         Si: La case est cachée:
                                                                                - On place le drapeaux '@'
                                                              
                                                                         Sinon si: La cases contient déjà  un drapeau:
                                                                                      - On enlève le drapeau '@' et on la met en cachée 10 ('*')
                                                              
                                                                         Sinon: La case à déjà  été découverte:
                                                                                   - Ne rien faire 'pass'                  
                                                                      """
                                                                      #On créer une variable /var/ qui prend pour valeur une
                                                                      #...céllule rentrée par l'utilisateur dans la fonction *action*
                                                                      #Sans oublier d'incrémenter ou de décrémenter /nombreMines/
                                                                      
                                                                      var = self.mappCachee[math.ceil(event.x / self.tailleBloc)-1][math.ceil(event.y / self.tailleBloc)-1]    
                                                                      
                                                                      if var == 10: 
                                                                          var = 9
                                                                          self.nombreMines -= 1
                                                                          
                                                                      elif var == 9:
                                                                          var = 10
                                                                          self.nombreMines += 1
                                                                          
                                                                      else:
                                                                          pass
                                                              
                                                                      #On change le '*' de /mappCachee/ par la valeur de /var/ (type:string)
                                                                      self.mappCachee[math.ceil(event.x / self.tailleBloc)-1][math.ceil(event.y / self.tailleBloc)-1] = var #####
                                                              
                                                              
                                                                  def creuser(self, event):
                                                                      """Permet de dévoiler une case dans
                                                                         la variable /mappCachee/
                                                                      """
                                                                      #Je créer une variable /var/
                                                                      #Qui prend comme valeur les coordonées de ma souris dans /mapp[event.x][event.y]/
                                                                      #On divise par /tailleBloc/ pour obtenir un nombre entier en /larBloc/ pour la longueur et /largBloc/ pour la hauteur
                                                                      #- si la case contient une bombe:
                                                                      #  - STOP
                                                                      #- si la case est déjà creusée:
                                                                      #  - Game over puis on stop la fonction
                                                                      #- sinon on retire le masque de la case str() pour pouvoir l'afficher
                                                                      #- Si la case vaut 0
                                                                      #  - On regarde autour de cette case s'il y a d'autres 0
                                                                      #  - Appel récursif de la fonction
                                                                      #
                                                                      #-1 car sinon lors du clic index is out of range -> [math.ceil(event.x / self.tailleBloc)-1][math.ceil(event.y / self.tailleBloc)-1]
                                                                      
                                                                      var = self.mapp[math.ceil(event.x / self.tailleBloc)-1][math.ceil(event.y / self.tailleBloc)-1]
                                                                      
                                                                      if var == 9:
                                                                          self.mappCachee[math.ceil(event.x / self.tailleBloc)-1][math.ceil(event.y / self.tailleBloc)-1] = var
                                                                          self.perdu = True 
                                                                          return
                                                                      
                                                                      if self.mappCachee[math.ceil(event.x / self.tailleBloc)-1][math.ceil(event.y / self.tailleBloc)-1] == var:
                                                                          return
                                                                      
                                                                      else:
                                                                          self.mappCachee[math.ceil(event.x / self.tailleBloc)-1][math.ceil(event.y / self.tailleBloc)-1] = var
                                                                          
                                                                          if var == 0: 
                                                                              #On regarde autour de cette case s'il y a d'autres 0
                                                                              for ii in range(max(0, math.ceil(event.x / self.tailleBloc)-1), min(math.ceil(event.x / self.tailleBloc)+2, self.largBloc)):         
                                                                                  for jj in range(max(0, math.ceil(event.y / self.tailleBloc)-1), min(math.ceil(event.y / self.tailleBloc)+2, self.largBloc)):
                                                                                      if self.mapp[ii][jj] == 0:
                                                                                          self.creuser2(ii, jj)
                                                                                      
                                                              
                                                                  def creuser2(self, l, c):
                                                                      """Pour l'appelle récursif:
                                                                         l = ligne
                                                                         c = colonne
                                                                      """
                                                                      var = self.mapp[l][c]    
                                                                      
                                                                      if var == 9:
                                                                          self.mappCachee[l][c] = var
                                                                          self.perdu = True
                                                                          return
                                                                      
                                                                      if self.mappCachee[l][c] == var:
                                                                          return
                                                                      
                                                                      else:
                                                                          self.mappCachee[l][c] = var
                                                                          
                                                                          if var == 0: 
                                                                              #On regarde autour de cette case s'il y a d'autres 0
                                                                              for ii in range(max(0, l-1), min(l+2, self.largBloc)):         
                                                                                  for jj in range(max(0, c-1), min(c+2, self.largBloc)):
                                                                                      if self.mapp[ii][jj] == 0:
                                                                                          self.creuser2(ii, jj)
                                                              
                                                                          
                                                              
                                                              
                                                              if __name__ == '__main__':
                                                                  p = Jeu()
                                                                  p.fenetre.mainloop()
                                                              


                                                              Image utilisateur
                                                              • Partager sur Facebook
                                                              • Partager sur Twitter

                                                              [Exercice][Débutant - Intermediaire] Démineur

                                                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                              • Editeur
                                                              • Markdown