Partage
  • Partager sur Facebook
  • Partager sur Twitter

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

mini-projet

    9 septembre 2010 à 10:03:22

    Bonjour, voici aussi ma version: Phase 1:

    J'ai supprimé ma classe <Affichage> car elle m'énervait :colere: .

    Ce que ne peut pas faire mon démineur:

    • Poser des drapeaux
    • Dire si une partie est perdue ou gagnée (Pourquoi ça ne veut pas fonctionner?)
    • Afficher tous les zéro contigües d'un coups


    Ce qu'il sait faire:

    • Afficher la grille des réponses et la grille cachée (Fait exprès)
    • Générer une grille
    • Chiffrer une grille
    • Creuser


    J'ai tout codé dans un seul fichier, mais je compte bien faire un fichier par <classe> pour le moment puis un fichier pour deux <classes> par la suite.

    Classe <Jeu>:
    ################################
    ## Les Modules Importés:(1)   ##
    #
    import random
    
    
                                                                   
    #-*-*- <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()
    
            """
            self.a_dePlateau = Plateau()
            self.partieEnCours = True
            #Appel de la fonction lors de l'instantation de <Jeu>
            self.jouer() 
    
    
        def jouer(self):
            """Toutes les fonctions qui doivent être
               appellées pour jouer sont mises ici.
            """
            self.regle()
            
            while True:
                self.a_dePlateau.genererGrille() 
                self.a_dePlateau.cacherGrille()
            
                while(self.partieEnCours is True or self.a_dePlateau.nombreMines > 0):
                    self.partieEnCours = self.a_dePlateau.creuser()
                    self.afficher()
    
        
        def gagner(self):
            """Le joueur a t-il gagner?"""
            if self.a_dePlateau.nom.nombreMines <= 0:
                
                return False
    
    
        def regle(self):
            """Les règles du jeu"""
            print("""Le but du jeu du démineur est de trouver toutes les mines présentes sur le
    terrain.
    Le terrain est chiffré, et chaque chiffre indique le nombre de bombes
    présentes dans les huit cases qui l'entoure:
    Pour choisir une case, il vous faut rentrer la <ligne> puis la <colonne>
    sous forme 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 zéro à
    quatre.
    Tout chiffre superieur ou inférieur à ce nombre, ne sera pas accepté.
    
    
    0: Zéro bombe
    1: Une bombe
    ...
    9: C'est une case bombe
    
                   Bon Jeu et bonne chance.""")
            input("\n\nAppuyez sur une touche pour commencer:>")
    
    
        def afficher(self):
            """Affiche le plateau de jeu en console."""
            #Affiche le plateau chiffré(Pour debugger). Comptage du nombre de mines restantes.
            for i in self.a_dePlateau.mapp: print(i, end="" + '\n')   
            print("Nombres de mines restantes:", self.a_dePlateau.nombreMines)
    
            #Plateau de jeu de la version jouable.
            for i in self.a_dePlateau.mappCachee: print(i, end="" + '\n')
    



    Classe <Plateau>:
    #-*-*- 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-)
    
            """
            self.mapp = []
            self.longueur = 5    #Longueur de la grille: 5²
            self.nombreMines = 0
            self.mappCachee = []
    
            
        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.longueur):
                self.mapp.append([0] * self.longueur)
    
            #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.longueur)
            #Le numéro '9' (type:int) représente une bombe
            self.col, self.ligne, self.bombe = random.randrange(0, self.longueur), random.randrange(0, self.longueur), 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.longueur):      
                for j in range(self.longueur):      
                    newL = []
                    
                    for ii in range(max(0, i-1), min(i+2, self.longueur)):         
                        for jj in range(max(0, j-1), min(j+2, self.longueur)):       
                            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 /longueur/²
            for i in range(self.longueur):
                self.mappCachee.append(['*'] * self.longueur)
    
    
        def creuser(self):
            """Permet de creuser une case
               dans /mappCachee/
            """
            #On commence par créer une boucle infinie
            #On convertit la varibale en (type:int)
            #...pour savoir si je ne suis pas en index out of range
            #...lors de la saisit de la variable.
            #Si tout est bon je créer une variable /var/
            #Qui prend comme valuer le chiffre dans /mapp[ligne][colonne]/
            #...en le convertissant en str() pour pouvoir l'afficher
            
            while True:
                
                ligne = input("Ligne N°: ")
                if len(ligne) == 1:
                    ligne = int(ligne)
                    if not ligne in range(self.longueur):
                        continue
                
                colonne = input("Colonne N°: ")
                if len(colonne) == 1:
                    colonne = int(colonne)
                    if not colonne in range(self.longueur):
                        continue
                    else:
                        break
                    
            var = self.mapp[ligne][colonne]    
            
            if var == 9:
                partieEnCours = False
            else:
                partieEnCours = True
    
            self.mappCachee[ligne][colonne] = str(var)
            return partieEnCours
    
            
                
    
    #Sans oublié ca :-)
    if __name__ == '__main__':
        p = Jeu()
        p.jouer()
    



    Mes deux classes regroupées:
    ################################
    ## Les Modules Importés:(1)   ##
    #
    import random
    
    
                                                                   
    #-*-*- <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()
    
            """
            self.a_dePlateau = Plateau()
            self.partieEnCours = True
            #Appel de la fonction lors de l'instantation de <Jeu>
            self.jouer() 
    
    
        def jouer(self):
            """Toutes les fonctions qui doivent être
               appellées pour jouer sont mises ici.
            """
            self.regle()
            
            while True:
                self.a_dePlateau.genererGrille() 
                self.a_dePlateau.cacherGrille()
            
                while(self.partieEnCours is True or self.a_dePlateau.nombreMines > 0):
                    self.partieEnCours = self.a_dePlateau.creuser()
                    self.afficher()
    
        
        def gagner(self):
            """Le joueur a t-il gagner?"""
            if self.a_dePlateau.nom.nombreMines <= 0:
                
                return False
    
    
        def regle(self):
            """Les règles du jeu"""
            print("""Le but du jeu du démineur est de trouver toutes les mines présentes sur le
    terrain.
    Le terrain est chiffré, et chaque chiffre indique le nombre de bombes
    présentes dans les huit cases qui l'entoure:
    Pour choisir une case, il vous faut rentrer la <ligne> puis la <colonne>
    sous forme 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 zéro à
    quatre.
    Tout chiffre superieur ou inférieur à ce nombre, ne sera pas accepté.
    
    
    0: Zéro bombe
    1: Une bombe
    ...
    9: C'est une case bombe
    
                   Bon Jeu et bonne chance.""")
            input("\n\nAppuyez sur une touche pour commencer:>")
    
    
        def afficher(self):
            """Affiche le plateau de jeu en console."""
            #Affiche le plateau chiffré(Pour debugger). Comptage du nombre de mines restantes.
            for i in self.a_dePlateau.mapp: print(i, end="" + '\n')   
            print("Nombres de mines restantes:", self.a_dePlateau.nombreMines)
    
            #Plateau de jeu de la version jouable.
            for i in self.a_dePlateau.mappCachee: print(i, end="" + '\n')
    
    #-*-*- 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-)
    
            """
            self.mapp = []
            self.longueur = 5    #Longueur de la grille: 5²
            self.nombreMines = 0
            self.mappCachee = []
    
            
        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.longueur):
                self.mapp.append([0] * self.longueur)
    
            #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.longueur)
            #Le numéro '9' (type:int) représente une bombe
            self.col, self.ligne, self.bombe = random.randrange(0, self.longueur), random.randrange(0, self.longueur), 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.longueur):      
                for j in range(self.longueur):      
                    newL = []
                    
                    for ii in range(max(0, i-1), min(i+2, self.longueur)):         
                        for jj in range(max(0, j-1), min(j+2, self.longueur)):       
                            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 /longueur/²
            for i in range(self.longueur):
                self.mappCachee.append(['*'] * self.longueur)
    
    
        def creuser(self):
            """Permet de creuser une case
               dans /mappCachee/
            """
            #On commence par créer une boucle infinie
            #On convertit la varibale en (type:int)
            #...pour savoir si je ne suis pas en index out of range
            #...lors de la saisit de la variable.
            #Si tout est bon je créer une variable /var/
            #Qui prend comme valuer le chiffre dans /mapp[ligne][colonne]/
            #...en le convertissant en str() pour pouvoir l'afficher
            
            while True:
                
                ligne = input("Ligne N°: ")
                if len(ligne) == 1:
                    ligne = int(ligne)
                    if not ligne in range(self.longueur):
                        continue
                
                colonne = input("Colonne N°: ")
                if len(colonne) == 1:
                    colonne = int(colonne)
                    if not colonne in range(self.longueur):
                        continue
                    else:
                        break
                    
            var = self.mapp[ligne][colonne]    
            
            if var == 9:
                partieEnCours = False
            else:
                partieEnCours = True
    
            self.mappCachee[ligne][colonne] = str(var)
            return partieEnCours
    
            
                
    
    #Sans oublié ca :-)
    if __name__ == '__main__':
        p = Jeu()
        p.jouer()
    



    P.S: Tu as été plus rapide que moi, je vais regarder ton code pour voir ce que tu as fait. :)
    • Partager sur Facebook
    • Partager sur Twitter
      9 septembre 2010 à 10:48:27

      Je n'ai pas le temps de regarder vos codes dans la journée (je le prendrai ce soir, quand je serai rentré du taff), mais j'en profite pour poster le mien "phases 1 et 2" (sans l'interface).


      #!/usr/bin/env python
      #-*- coding: utf-8 -*-
      
      from __future__ import print_function
      from random import randint
      
      ###############################################################################
      # Constantes globales
      
      MINE = '*'    # Dessin d'une mine
      FLAG = '!'    # Drapeau
      NOFLAG = '.'  # Case cachée normale
      NOTHING = ' ' # Case vide
      
      class Cell(object):
          """
          Classe modélisant une case du champ de mines.
      
          """
          def __init__(self):
              """
              Initialisation des attributs.
      
              """
              self.mine = False  # La case contient-elle une mine ?
              self.flag = False  # Y-a t'il un drapeau posé sur cette case ?
              self.show = False  # La case est-elle visible ?
              self.value = 0     # Combien de cases adjacentes contiennent une mine ?
      
          def __str__(self):
              """
              Retourne un caractère symbolisant l'état de la case.
      
              """
              if self.show:
                  return str(self.value) if self.value else NOTHING
              else:
                  return FLAG if self.flag else NOFLAG
      
      class Field(object):
          """
          Classe modélisant un champ de mines.
      
          """
          def __init__(self, rows, cols, n_mines):
              """
              Initialisation du champ de mines.
      
              rows: nombre de lignes
              cols: nombre de colonnes
              n_mines: nombre de mines
      
              """        
              if rows < 1 or cols < 1:
                  raise ValueError('rows et cols doivent être positifs')
              if n_mines > rows * cols:
                  raise ValueError('trop de mines')
              self.rows = rows
              self.cols = cols
              self.n_mines = n_mines
              self.hidden = rows * cols  # nombre de cases cachées
              self.flagged = 0           # nombre de cases portant un drapeau
              self.gameover = False
              self.cells = []
              self._init_cells()         # initialisation des cases
              # remplissage aléatoire du champ de mines
              for _ in xrange(n_mines):
                  idx = randint(0, rows * cols -1)
                  while self.cells[idx].mine:
                      idx = randint(0, rows * cols -1)
                  row = idx // cols
                  col = idx - row * cols
                  self.cells[idx].mine = True
                  self._count_mines(row, col)
              
          def _init_cells(self):
              """
              Initialisation des cases.
              Cette fonction pourra être surchargée si une classe fille désire 
              utiliser une autre classe pour les cases. (voir interface)
      
              """
              self.cells = [Cell() for _ in xrange(self.rows * self.cols)]
      
          def _count_mines(self, row, col):
              """
              Incrémente les compteurs de mines autour de la case (row, col)
              row: numéro de ligne de la case.
              col: numéro de colonne de la case.
      
              """
              for r in xrange(max(row-1, 0), min(row+2, self.rows)):
                  for c in xrange(max(col-1, 0), min(col+2, self.cols)):
                      self.cells[r * self.cols + c].value += 1
          
          @property
          def won(self):
              """
              Propriété (s'utilise comme un attribut 'won' en lecture seule).
              Retourne True si la partie est gagnée, False sinon.
      
              """
              return self.n_mines == self.hidden
      
          def flag_cell(self, row, col):
              """
              Pose un drapeau sur la case à la position (row, col) et incrémente le
              compteur de drapeaux posés.
              Effectue l'inverse si un drapeau est déjà présent sur cette case.
              Ne fait rien si la case n'est pas masquée.
              
              row: numéro de ligne de la case.
              col: numéro de colonne de la case.
      
              """
              cell = self.cells[row * self.cols + col]
              if not cell.show:
                  cell.flag = not cell.flag 
                  if cell.flag:
                      self.flagged += 1
                  else:
                      self.flagged -= 1
          
          def play_cell(self, row, col):
              """
              Joue ("creuse") la case à la position (row, col).
              row: numéro de ligne de la case.
              col: numéro de colonne de la case.
      
              """
              cell = self.cells[row * self.cols + col]
              # si la case porte un drapeau ou si elle est déjà découverte,
              # ne rien faire
              if cell.show or cell.flag:
                  return
              # si la case porte une mine, la partie est terminée.
              if cell.mine:
                  self.gameover = True
              # sinon...
              else:
                  # on découvre la case
                  cell.show = True
                  self.hidden -= 1
                  # si la case est nulle, on creuse aussi son voisinage
                  if cell.value == 0:
                      for r in xrange(max(row-1, 0), min(row+2, self.rows)):
                          for c in xrange(max(col-1, 0), min(col+2, self.cols)):
                              self.play_cell(r, c)
                  # enfin, on regarde si la partie est gagnée
                  self.gameover = self.won
      
          def __str__(self):
              """
              Retourne une représentation du champ de mines sous forme de string,
              pour l'affichage.
      
              """
              str_grid = '+' + '-' * self.cols + '+'
              for idx, cell in enumerate(self.cells):
                  ch_line = idx % self.cols
                  if ch_line == 0:
                      str_grid += '\n|'
                  if self.gameover and cell.mine:
                      str_grid += MINE
                  else:
                      str_grid += str(cell)
                  if ch_line == self.cols-1:
                      str_grid += '|'
              str_grid += '\n+' + '-' * self.cols + '+'
              return str_grid
      
      class Game(object):
          """
          Classe gérant l'exécution du jeu.
      
          """
          def __init__(self, rows, cols, n_bombs):
              """
              Initialisation du jeu.
      
              """
              self.field = Field(rows, cols, n_bombs)
              self.flag = False   # mode 'creusage' ou 'drapeau'
      
          def run(self):
              """
              Exécution du jeu.
      
              """
              prompt = "[c : creuser, d : drapeau, q : quitter]\n{0} > "
              while not self.field.gameover:
                  print(self.field)
                  entree = raw_input(
                          prompt.format('drapeau' if self.flag else 'creuser'))
                  self.parse_input(entree.strip().lower())
              print(self.field)
              if self.field.won:
                  print('Gagné !')
              else:
                  print('BOOM ! Perdu')
      
          def parse_input(self, in_str):
              """
              Traite la saisie de l'utilisateur.
      
              """
              if in_str == 'q':
                  raise SystemExit
              if in_str == 'c':
                  self.flag = False
                  return
              if in_str == 'd':
                  self.flag = True
                  return
              try:
                  row, col = [int(num) for num in in_str.split()]
                  if self.flag:
                      self.field.flag_cell(row, col)
                  else:
                      self.field.play_cell(row, col)
              except (ValueError, TypeError):
                  print('Entrée invalide : 2 nombres attendus')
              except IndexError:
                  print('Entrée invalide : [0 <= ligne < {0}] [0 <= colonne < {1}]\
                          '.format(self.field.rows, self.field.cols))
      
      if __name__ == '__main__':
          g = Game(5, 5, 3)
          g.run()
      



      En parlant d'interface, je galère à gérer la souris dans ncurses (oui je voulais l'ajouter, clic gauche pour creuser et droit pour poser un drapeau, même dans la console :p ). J'arrive bien à reconnaitre un clic mais je n'ai pas trouvé (ou compris) comment récupérer la position de la souris et en tenir compte.
      Si des pros de la programmation curses en Python passent par ici, un petit complément d'explication serait le bienvenu (je n'ai pas trouvé mon bonheur sur le web, juste une floppée d'exemples qui ne répondent pas à mes questions). :)

      @realmagma : une partie est perdue si tu creuses sur une mine, ou gagnée si toutes les cases qui restent cachées contiennent encore des mines (donc que le nombre de cases cachées est égal au nombre de mines) et qu'aucune n'a explosé jusqu'à présent...
      Je regarderai ton code ce soir.
      • Partager sur Facebook
      • Partager sur Twitter
      Zeste de Savoir, le site qui en a dans le citron !
        9 septembre 2010 à 10:55:53

        Pour curses, j'ai trouvé ceci:

        fenetre.move(y,x) :place le curseur à la position précisée.
        Tu pourrai de ce fait, incrémenter/décrémenter (x;y) lorsque tu bouges la souris.

        Source: ici ;)

        EDIT: J'ai aussi trouvé ceci:

        curses.getmouse()¶
        After getch() returns KEY_MOUSE to signal a mouse event, this method should be call to retrieve the queued mouse event, represented as a 5-tuple (id, x, y, z, bstate). id is an ID value used to distinguish multiple devices, and x, y, z are the event’s coordinates. (z is currently unused.). bstate is an integer value whose bits will be set to indicate the type of event, and will be the bitwise OR of one or more of the following constants, where n is the button number from 1 to 4: BUTTONn_PRESSED, BUTTONn_RELEASED, BUTTONn_CLICKED, BUTTONn_DOUBLE_CLICKED, BUTTONn_TRIPLE_CLICKED, BUTTON_SHIFT, BUTTON_CTRL, BUTTON_ALT.

        curses.getsyx()¶
        Returns the current coordinates of the virtual screen cursor in y and x. If leaveok is currently true, then -1,-1 is returned.


        Source: ici (Je sais que tu es déjà aller voir, mais si ça peut servir à d'autres. :)
        • Partager sur Facebook
        • Partager sur Twitter
          9 septembre 2010 à 10:59:32

          Oui mais... non.
          Déjà testé, il n'y a pas moyen de détecter les mouvements de la souris. Uniquement les clics et les modificateurs (et quand bien même ce serait possible, niveau performances ça serait assez galère, il faudrait tout redessiner chaque fois que la souris bouge...).

          Edit :
          Le truc c'est que les coordonnées (x,y) de l'événement souris ne me parlent pas.
          Est-ce la position de la souris ou la position du curseur virtuel ?
          Les tests que j'ai effectués tendent à me faire penser que c'est la position du curseur virtuel (qui n'est PAS piloté/pilotable par la souris, ou du moins que je n'ai pas réussi à piloter)...
          Il est là le problème. Il me manque un chaînon pour faire le lien. :p
          • Partager sur Facebook
          • Partager sur Twitter
          Zeste de Savoir, le site qui en a dans le citron !
            9 septembre 2010 à 16:20:20

            Voici ma nouvelle version de la phase 1:

            Mes deux classes en un seul fichier:
            ################################
            ## Les Modules Importés:(2)   ##
            #
            import random
            import os
            
                                                                           
            #-*-*- <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()
            
                    """
                    self.a_dePlateau = Plateau()
                    self.partieEnCours = True
                    #Appel de la fonction lors de l'instantation de <Jeu>
                    self.jouer() 
            
            
                def jouer(self):
                    """Toutes les fonctions qui doivent être
                       appellées pour jouer sont mises ici.
                    """
                    self.regle()
                    
                    while self.partieEnCours == True:
                        self.a_dePlateau.genererGrille() 
                        self.a_dePlateau.cacherGrille()
                    
                        while(self.partieEnCours is True and self.a_dePlateau.nombreMines > 0):
                                self.partieEnCours = self.a_dePlateau.creuser()
                                self.afficher()
                                
                                cestGagne = self.gagner() #Création d'une variable
                                if cestGagne == False:
                                    break
                                
                    #L'utilisateur veut t'il rejouer ?        
                    rejouer = input("\nVoulez vous rejouer. <O> = oui et <N> = Non\n>")
                    if rejouer.upper() == 'O':
                        self.partieEnCours = True 
                    else:
                        self.partieEnCours = False
            
                
                def gagner(self):
                    """Le joueur a t-il gagner?"""
                    if self.a_dePlateau.nombreMines <= 0 or self.a_dePlateau.mapp == self.a_dePlateau.mappCachee:
                        Print("\n\nBravos vous avez gagné!!!!")
                        return False
                    
            
                def regle(self):
                    """Les règles du jeu"""
                    print("""Le but du jeu du démineur est de trouver toutes les mines présentes sur le
            terrain.
            Le terrain est chiffré, et chaque chiffre indique le nombre de bombes
            présentes dans les huit cases qui l'entoure:
            Pour choisir une case, il vous faut rentrer la <ligne> puis la <colonne>
            sous forme 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 zéro à
            quatre.
            Tout chiffre superieur ou inférieur à ce nombre, ne sera pas accepté.
            
            
            0: Zéro bombe
            1: Une bombe
            ...
            9: C'est une case bombe
                           Bon Jeu et bonne chance.""")
                    
                    input("\n\nAppuyez sur une touche pour commencer:>")
                    os.system("CLS")
            
            
                def afficher(self):
                    """Affiche le plateau de jeu en console."""
                    #Affiche le plateau chiffré(Pour debugger). Comptage du nombre de mines restantes.
                    for i in self.a_dePlateau.mapp: print(i, end="" + '\n')   
                    print("Nombres de mines restantes:", self.a_dePlateau.nombreMines)
            
                    #Plateau de jeu de la version jouable.
                    for i in self.a_dePlateau.mappCachee: print(i, end="" + '\n')
            
            #-*-*- 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-)
            
                    """
                    self.mapp = []
                    self.longueur = 5    #Longueur de la grille: 5²
                    self.nombreMines = 0
                    self.mappCachee = []
            
                    
                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.longueur):
                        self.mapp.append([0] * self.longueur)
            
                    #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.longueur)
                    #Le numéro '9' (type:int) représente une bombe
                    self.col, self.ligne, self.bombe = random.randrange(0, self.longueur), random.randrange(0, self.longueur), 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.longueur):      
                        for j in range(self.longueur):      
                            newL = []
                            
                            for ii in range(max(0, i-1), min(i+2, self.longueur)):         
                                for jj in range(max(0, j-1), min(j+2, self.longueur)):       
                                    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 /longueur/²
                    for i in range(self.longueur):
                        self.mappCachee.append(['*'] * self.longueur)
            
            
                def creuser(self):
                    """Permet de creuser une case
                       dans /mappCachee/
                    """
                    #On commence par créer une boucle infinie
                    #On convertit la varibale en (type:int)
                    #...pour savoir si je ne suis pas en index out of range
                    #...lors de la saisit de la variable.
                    #Si tout est bon je créer une variable /var/
                    #Qui prend comme valuer le chiffre dans /mapp[ligne][colonne]/
                    #...en le convertissant en str() pour pouvoir l'afficher
                    
                    while True:
                        
                        ligne = input("\n\nLigne N°: ")
                        if len(ligne) == 1:
                            ligne = int(ligne)
                            if not ligne in range(self.longueur):
                                continue
                        
                        colonne = input("Colonne N°: ")
                        if len(colonne) == 1:
                            colonne = int(colonne)
                            if not colonne in range(self.longueur):
                                continue
                            else:
                                break
                            
                    var = self.mapp[ligne][colonne]    
                    
                    if var == 9:
                        partieEnCours = False
                    else:
                        partieEnCours = True
            
                    self.mappCachee[ligne][colonne] = str(var)
                    return partieEnCours
            
                    
                        
            
            #Sans oublié ca :-)
            if __name__ == '__main__':
                p = Jeu()
                p.jouer()
            


            Voilà qui est déjà mieux ^^

            EDIT: Ma Phase N°2:

            Bonjour à Tous,

            Je vous présente mon démineur en console de la phases N°2:

            Ce que mon démineur peut faire:
            • Demander à l'utilisateur d'entrer des coordonnées
            • Demander s'il veut poser un drapeau ou creuser


            Ce qui ne marche pas très bien: (copier/coller mon code) (Python 3)
            • La deuxième implémentation de la méthode creuser de la phase N°2
            • La méthode verificationMap


            J'aurai besoin d'aide pour le premier, et quelques explications pour le deuxième s'il vous plaît.
            Je vous poste mon code en un seul fichier: 2 Classes


            Je vous remercie d'avance.


            ################################
            ## Les Modules Importés:(2)   ##
            #
            import random
            import os
            
                                                                           
            #-*-*- <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()
            
                    """
                    self.a_dePlateau = Plateau()
                    self.partieEnCours = True
                    #Appel de la fonction lors de l'instantation de <Jeu>
                    self.jouer() 
            
            
                def jouer(self):
                    """Toutes les fonctions qui doivent être
                       appellées pour jouer sont mises ici.
                    """
                    self.regle()
                    
                    while self.partieEnCours == True:
                        self.a_dePlateau.genererGrille() 
                        self.a_dePlateau.cacherGrille()
                    
                        while(self.partieEnCours is True and self.a_dePlateau.nombreMines > 0):
                                self.partieEnCours = self.a_dePlateau.action()
                                self.afficher()
            
                                #Création d'une variable pour savoir si on a gagné
                                cestGagne = self.gagner() 
                                if cestGagne == False:
                                    break
                                
                    #L'utilisateur veut t'il rejouer ?        
                    rejouer = input("\nVoulez vous rejouer. <O> = oui et <N> = Non\n>")
                    if rejouer.upper() == 'O':
                        self.partieEnCours = True 
                    else:
                        self.partieEnCours = False
            
               
                def gagner(self):
                    """Le joueur a t-il gagner?"""
                    if self.a_dePlateau.nombreMines <= 0:
                        #Appel de la fonction *verificationMap*
                        #Si /mapp/ et /mappCachee/ sont identiques
                        #... alors c'est gagné !
            
                        verifier = self.verificationMap()
                        if verifier == True:
                            print("\n\nBravos vous avez gagné!!!!")
                            
                            return False
                        
            
                def afficher(self):
                    """Affiche le plateau de jeu en console."""
                    #Affiche le plateau chiffré(Pour debugger). Comptage du nombre de mines restantes.
                    for i in self.a_dePlateau.mapp: print(i, end="" + '\n')   
                    print("Nombres de mines restantes:", self.a_dePlateau.nombreMines)
            
                    #Plateau de jeu de la version jouable.
                    for i in self.a_dePlateau.mappCachee: print(i, end="" + '\n')
            
            
                def verificationMap(self):
                    """Verifie si /mapp/ et /mappCachee/
                       sont identiques pur confirmer si
                       l'utilisateur à gagné
                    """
                    #On parcours /mappCachee/ et on remplace
                    #... tous les '@' par des '9'
                    #On met toutes les valeurs de cette liste en (type:int).
                    #On regarde si les /mapp/ et /mappCachee/ sont identiques
                    #Si oui, on retourne 'True'
            
                    for i in self.a_dePlateau.mappCachee:
                        for j in i:
                            j.replace('@', '9')
                            #Conertir les valeurs de mappCachee en (type:Int)
                            #Si elles sont identiques, 'retourn True'
                            #Sinon 'return False'
                    
            
                def regle(self):
                    """Les règles du jeu"""
                    print("""Le but du jeu du démineur est de trouver toutes les mines présentes sur le
            terrain.
            Le terrain est chiffré, et chaque chiffre indique le nombre de bombes
            présentes dans les huit cases qui l'entoure:
            Pour choisir une case, il vous faut rentrer la <ligne> puis la <colonne>
            sous forme 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 zéro à
            quatre.
            Tout chiffre superieur ou inférieur à ce nombre, ne sera pas accepté.
            
            
            0: Zéro bombe
            1: Une bombe
            ...
            9: C'est une case bombe
                           Bon Jeu et bonne chance.""")
                    
                    input("\n\nAppuyez sur une touche pour commencer:>")
                    os.system("CLS")
                    
            #-*-*- 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.longueur = 5    #Longueur de la grille: 5²
                    self.mappCachee = []
                    self.nombreMines = 0
            
                    
                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.longueur):
                        self.mapp.append([0] * self.longueur)
            
                    #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.longueur)
                    #Le numéro '9' (type:int) représente une bombe
                    self.col, self.ligne, self.bombe = random.randrange(0, self.longueur), random.randrange(0, self.longueur), 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.longueur):      
                        for j in range(self.longueur):      
                            newL = []
                            
                            for ii in range(max(0, i-1), min(i+2, self.longueur)):         
                                for jj in range(max(0, j-1), min(j+2, self.longueur)):       
                                    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 /longueur/²
                    for i in range(self.longueur):
                        self.mappCachee.append(['*'] * self.longueur)
            
            
                def action(self):
                    """Permet de choisir entre *creuser* ou
                       *poserDrapeau.
                       Permet de choisir une case pour l'une ou l'autre des méthodes.
                    """
                    #On commence par créer une boucle infinie
                    #On convertit la varibale en (type:int)
                    #...pour savoir si je ne suis pas en index out of range
                    #...lors de la saisit de la variable.
                    #On demande si l'utilisateur veut *creuser* ou *poserDrapeau*
                    #On recupère le tout dans /partieEncours/ qui sera retournée
                    #...en fin de fonction pour savoir si on arrête le jeu ou pas
                    
                    while True:
                        
                        ligne = input("\n\nLigne N°: ")
                        if len(ligne) == 1:
                            
                            try:
                                ligne = int(ligne)
                            except ValueError:
                                print("\n*Il faut rentrer un nombre, recommencez du début*")
                                continue
                            
                            if not ligne in range(self.longueur):
                                continue
                        
                        colonne = input("Colonne N°: ")
                        if len(colonne) == 1:
            
                            try:
                                colonne = int(colonne)
                            except ValueError:
                                print("\n*Il faut rentrer un nombre, recommencez du début*")
                                continue
                            
                            if not colonne in range(self.longueur):
                                continue
                            else:
                                break
            
                    while True:
                        choix = input("\nC = Creuser; D = Poser un drapeau: Que faire: >")
                        if choix.upper() == "C":
                            #Appel de la méthode *creuser*
                            partieEnCours = self.creuser(ligne, colonne)
                            break
                        
                        elif choix.upper() == "D":
                            #Appel de la méthode *poserDrapeau*
                            partieEnCours = self.poserDrapeau(ligne, colonne)
                            break
                        
                        else:
                            #Si non le choix est incorrecte, ré-entre dans la boucle
                            continue
            
                    return partieEnCours
            
                
                def poserDrapeau(self, ligne, colonne):
                    """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écouvert:
                                 - 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[ligne][colonne]    
                    
                    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[ligne][colonne] = str(var)
            
                    return True
            
            
                def creuser(self, ligne, colonne):
                    """Permet de dévoiler une case dans
                       la variable /mappCachee/
                    """
                    #Je créer une variable /var/
                    #Qui prend comme valeur le chiffre dans /mapp[ligne][colonne]/
                    #...en le convertissant en str() pour pouvoir l'afficher
                    
                    var = self.mapp[ligne][colonne]    
                    
                    if var == 9:
                        partieEnCours = False
                    else:
                        partieEnCours = True
            
                    #On change le '*' de /mappCachee/ par la valeur de /var/
                    self.mappCachee[ligne][colonne] = str(var)
            
                    if var == 0:
                        #On regarde autour de cette case s'il y a d'autres '0'
                        for ii in range(max(0, ligne-1), min(ligne+2, self.longueur)):         
                            for jj in range(max(0, colonne-1), min(colonne+2, self.longueur)):
            
                                #Si il l'une des 8 cases vaut '0' alors on l'a dévoile
                                if self.mapp[ii][jj] == 0:
                                    self.mappCachee[ii][jj] = str(self.mapp[ii][jj])
            
                    return partieEnCours
                        
            
            #Sans oublié ca :-)
            if __name__ == '__main__':
                p = Jeu()
                p.jouer()
            
            • Partager sur Facebook
            • Partager sur Twitter
              10 septembre 2010 à 10:49:57

              OK j'ai regardé vos codes.

              @Sparrow:
              On a utilisé le même genre de structure (un tableau d'objets "Cases", qui décrivent tout l'état d'une case donnée).
              Juste pour ta classe Case, les accesseurs et mutateurs sont peut-être superflus en l'état, puisque tu n'as pas "manglé" les noms d'attributs (rajouté deux underscores devant pour les rendre "pseudo-privés"), et qu'il est plus simple en Python d'y accéder directement dans ce cas. Mais ça reste valide.
              Pour la méthode compter_bombes de la classe Plateau... je trouve que ça fait beaucoup de if . :lol:
              Sinon, du reste, pas grand chose à redire. Beau boulot.

              @realmagma:
              Pour ta méthode creuser, essaye de l'implémenter "telle que tu penses".
              Là tu commences par une boucle infinie... si c'est comme ça que tu penses, j'aimerais pas voir ta tête quand tu oublies de faire un break . :D
              En fait, elle fait plus que simplement "creuser", ta méthode, elle récupère aussi l'entrée de l'utilisateur : du coup, l'interface utilisateur n'est pas séparée du modèle, ce qui va te poser problème dans la suite quand tu voudras faire une interface.
              Si tu regardes le code de Sparrow et le mien, tu verras que toutes les interactions avec l'utilisateur sont cantonnées dans une seule classe (ce serait ta classe Jeu), la méthode creuser prend en argument le numéro de ligne et le numéro de colonne de la case à creuser...
              Dans mon code, j'ai commenté cette méthode un peu plus que les autres, pour montrer le mécanisme que j'utilise. Jettes-y un oeil. ;)

              Je vois pas mal d'endroits où tu fais compliqué pour faire simple:
              si j'ai une fonction verifie_machin(truc) , qui retourne True ou False , je n'ai pas besoin de faire quelquechose du genre :
              maVarTemporaire = verifie_machin(truc)
              if maVarTemporaire == True:
                  # faire quelquechose parce que truc est bien verifie_machiné
              


              Mais plutôt :
              if verifie_machin(truc):
                  # agir en conséquence
              

              Ça allège ton code, le rend plus lisible, et plus facile à suivre. ;)

              Attention aussi à bien vérifier tous les cas avec tes méthodes.
              Regarde ta méthode "gagner" : quand est-ce qu'elle retourne True ?

              Enfin, pour "verifierMap"... à quoi sert-elle ?
              À première vue je dirais que tu as l'intention de vérifier si la partie est finie grâce à cette méthode, mais y'a-t-il vraiment besoin de faire une vérification complexe en comparant deux tableaux pour ça ?
              Regarde ma méthode Field.won() . ;)
              • Partager sur Facebook
              • Partager sur Twitter
              Zeste de Savoir, le site qui en a dans le citron !
              Anonyme
                10 septembre 2010 à 11:21:06

                Salut,

                merci Nohar pour avoir relevé ces points. Je ne connaissais pas le fait de "mangler" les noms d'attributs, alors, par habitude de Java, j'ai fait des get/set.
                En ce qui concerne la méthode compterBombes, j'avoue que c'est un peu brutal, mais pour le moment je ne vois pas comment changer ça :-°

                Je vais essayer de m'en occuper au plus vite, j'éditerais mon post précédent avec le code "corrigé" pour ces remarques, sans doute en plusieurs fois.

                Edit : voilà, j'ai fait juste des modifs sur les noms des attributs. En ce qui concerne le comptage des bombes, il faudrait faire une approche récursive ? Je vais essayer de voir vos codes pour tenter d'avoir une solution moins primitive ^^

                Bonne journée.
                • Partager sur Facebook
                • Partager sur Twitter
                  10 septembre 2010 à 11:39:58

                  Pour la méthode "compter", sachant que tu parcours un "sous-tableau" carré, tu peux y aller avec une petite double boucle.
                  Dans mon code, c'est un peu différent, je "chiffre" le tableau comme dirait realmagma, en même temps que je place mes bombes : chaque fois qu'une bombe est ajoutée, j'incrémente les compteurs autour d'elle, ce qui est théoriquement plus rapide.

                  Mais sinon, pour rester dans ton idée de compter les mines à la volée (au dernier moment avant d'afficher), ça pourrait donner un truc du genre :

                  # ligne, colonne sont les coordonnées de la case courante
                  # n_lignes, n_colonnes sont les dimensions du tableau
                  l_min = max(0, ligne-1)
                  l_max = min(ligne+2, n_lignes)
                  c_min = max(0, colonne-1)
                  c_max = min(colonne+2, n_colonnes)
                  bombes = 0
                  for lig in xrange(l_min, l_max):
                      for col in xrange(c_min, c_max):
                          if self.__plateau[lig][col].estUneBombe():
                              bombes += 1
                  
                  self.__plateau[ligne][colonne].setNbBombesAutour(bombes)
                  


                  C'est un peu moins efficace, comme algo, mais pour un démineur ça passe (et c'est lisible).
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Zeste de Savoir, le site qui en a dans le citron !
                    10 septembre 2010 à 11:52:55

                    Bonjour,

                    j'ai fait comme tu as dit, en séparant l'interface avec utilisateur que j'ai mis dans la classe <Jeu>

                    En regardant ton code, j'ai compris qu'il fallait un appel récursif pour dévoiler tous les zéro contigües.
                    Cependant, je tombe dans... un appel récursif infini que je n'arrive pas à résoudre, ne sachant quoi mettre comme condition pour l'arrêter.
                    J'ai aussi implémenter des

                    if mafonction():
                    


                    ...comme tu me l'as recommandé; et enfin, supprimé ma méthode *verifier()* qui ne servait à rien :lol:


                    Que mettre dans ma condition pour éviter un appel récursif ?

                    Mon nouveau code:
                    ################################
                    ## Les Modules Importés:(2)   ##
                    #
                    import random
                    import os
                    
                                                                                   
                    #-*-*- <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()
                    
                            """
                            self.a_dePlateau = Plateau()
                            self.partieEnCours = True
                            
                            #Appel de la fonction lors de l'instantation de <Jeu>
                            self.jouer() 
                    
                    
                        def jouer(self):
                            """Toutes les fonctions qui doivent être
                               appellées pour jouer sont mises ici.
                            """
                            self.regle()
                            
                            while self.partieEnCours == True:
                                self.a_dePlateau.genererGrille() 
                                self.a_dePlateau.cacherGrille()
                            
                                while(self.partieEnCours is True and self.a_dePlateau.nombreMines > 0):
                                        self.action()
                                        self.afficher()
                    
                                        if self.gagner() == False:
                                            break
                                        
                            #L'utilisateur veut t'il rejouer ?        
                            rejouer = input("\nVoulez vous rejouer. <O> = oui et <N> = Non\n>")
                            if rejouer.upper() == 'O':
                                self.partieEnCours = True 
                            else:
                                self.partieEnCours = False
                    
                       
                        def gagner(self):
                            """Le joueur a t-il gagner?"""
                            if self.a_dePlateau.nombreMines <= 0:
                                #Appel de la fonction *verificationMap*
                                #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."""
                            #Affiche le plateau chiffré(Pour debugger). Comptage du nombre de mines restantes.
                            for i in self.a_dePlateau.mapp: print(i, end="" + '\n')   
                            print("Nombres de mines restantes:", self.a_dePlateau.nombreMines)
                    
                            #Plateau de jeu de la version jouable.
                            for i in self.a_dePlateau.mappCachee: print(i, end="" + '\n')
                    
                    
                        def action(self):
                            """Permet de choisir entre *creuser* ou
                                *poserDrapeau.
                                Permet de choisir une case pour l'une ou l'autre des méthodes.
                            """
                            #On commence par créer une boucle infinie
                            #On convertit la varibale en (type:int)
                            #...pour savoir si je ne suis pas en index out of range
                            #...lors de la saisit de la variable.
                            #On demande si l'utilisateur veut *creuser* ou *poserDrapeau*
                            #On recupère le tout dans /partieEncours/ qui sera retournée
                            #...en fin de fonction pour savoir si on arrête le jeu ou pas
                            
                            while True:
                                
                                ligne = input("\n\nLigne N°: ")
                                if len(ligne) == 1:
                                    
                                    try:
                                        ligne = int(ligne)
                                    except ValueError:
                                        print("\n*Il faut rentrer un nombre, recommencez du début*")
                                        continue
                                    
                                    if not ligne in range(self.a_dePlateau.longueur):
                                        continue
                                
                                colonne = input("Colonne N°: ")
                                if len(colonne) == 1:
                    
                                    try:
                                        colonne = int(colonne)
                                    except ValueError:
                                        print("\n*Il faut rentrer un nombre, recommencez du début*")
                                        continue
                                    
                                    if not colonne in range(self.a_dePlateau.longueur):
                                        continue
                                    else:
                                        break
                    
                            while True:
                                choix = input("\nC = Creuser; D = Poser un drapeau: Que faire: >")
                                if choix.upper() == "C":
                                    #Appel de la méthode *creuser*
                                    self.partieEnCours = self.a_dePlateau.creuser(ligne, colonne)
                                    break
                                
                                elif choix.upper() == "D":
                                    #Appel de la méthode *poserDrapeau*
                                    self.partieEnCours = self.a_dePlateau.poserDrapeau(ligne, colonne)
                                    break
                                
                                else:
                                    #Si non le choix est incorrecte, ré-entre dans la boucle
                                    continue
                            
                    
                        def regle(self):
                            """Les règles du jeu"""
                            print("""Le but du jeu du démineur est de trouver toutes les mines présentes sur le
                    terrain.
                    Le terrain est chiffré, et chaque chiffre indique le nombre de bombes
                    présentes dans les huit cases qui l'entoure:
                    Pour choisir une case, il vous faut rentrer la <ligne> puis la <colonne>
                    sous forme 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 zéro à
                    quatre.
                    Tout chiffre superieur ou inférieur à ce nombre, ne sera pas accepté.
                    
                    
                    0: Zéro bombe
                    1: Une bombe
                    ...
                    9: C'est une case bombe
                                   Bon Jeu et bonne chance.""")
                            
                            input("\n\nAppuyez sur une touche pour commencer:>")
                            os.system("CLS")
                            
                    #-*-*- 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.longueur = 5    #Longueur de la grille: 5²
                            self.mappCachee = []
                            self.nombreMines = 0
                    
                            
                        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.longueur):
                                self.mapp.append([0] * self.longueur)
                    
                            #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.longueur)
                            #Le numéro '9' (type:int) représente une bombe
                            self.col, self.ligne, self.bombe = random.randrange(0, self.longueur), random.randrange(0, self.longueur), 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.longueur):      
                                for j in range(self.longueur):      
                                    newL = []
                                    
                                    for ii in range(max(0, i-1), min(i+2, self.longueur)):         
                                        for jj in range(max(0, j-1), min(j+2, self.longueur)):       
                                            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 /longueur/²
                            for i in range(self.longueur):
                                self.mappCachee.append(['*'] * self.longueur)
                    
                        
                        def poserDrapeau(self, ligne, colonne):
                            """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écouvert:
                                         - 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[ligne][colonne]    
                            
                            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[ligne][colonne] = str(var)
                    
                            return True
                    
                    
                        def creuser(self, ligne, colonne):
                            """Permet de dévoiler une case dans
                               la variable /mappCachee/
                            """
                            #Je créer une variable /var/
                            #Qui prend comme valeur le chiffre dans /mapp[ligne][colonne]/
                            #...en le convertissant en str() pour pouvoir l'afficher
                            
                            var = self.mapp[ligne][colonne]    
                            
                            if var == 9:
                                partieEnCours = False
                            else:
                                partieEnCours = True
                    
                            #On change le '*' de /mappCachee/ par la valeur de /var/
                            self.mappCachee[ligne][colonne] = str(var)
                    
                            if var == 0:
                                #On regarde autour de cette case s'il y a d'autres '0'
                                for ii in range(max(0, ligne-1), min(ligne+2, self.longueur)):         
                                    for jj in range(max(0, colonne-1), min(colonne+2, self.longueur)):
                                        self.creuser(ii, jj) #Appel récursif
                            else:
                                pass
                    
                            return partieEnCours
                                
                    
                    #Sans oublié ca :-)
                    if __name__ == '__main__':
                        p = Jeu()
                        p.jouer()
                    
                    • Partager sur Facebook
                    • Partager sur Twitter
                      10 septembre 2010 à 11:58:18

                      J'ai bien détaillé et documenté l'algo, pourtant... :-°
                      Regarde bien les étapes que je suis, les conditions d'arrêt sont celles pour lesquelles ont fait un return prématuré...
                      • Partager sur Facebook
                      • Partager sur Twitter
                      Zeste de Savoir, le site qui en a dans le citron !
                        10 septembre 2010 à 13:12:59

                        Je suis désolé mais ça ne marche pas :euh: .

                        var = celluleActuelle (de mapp)
                        Si var n'est pas une bombe et n'est pas égale à 0
                        - On a perdu dans le premier cas et on remplace la valeur dans le second cas
                        - On arrête la fonction grâce au 'return'
                        
                        Sinon c'est que 'var' vaut zéro
                        - Dans ce cas on regarde ce qui l'entoure et on dévoile les zéro
                        - Appel récursif


                        Pourquoi je tombe dans un appel récursif infini? J'ai bien regardé ton code, mais impossible de déterminer pourquoi. :(

                        Ma méthode creuser:


                        def creuser(self, ligne, colonne):
                                """Permet de dévoiler une case dans
                                   la variable /mappCachee/
                                """
                                #Je créer une variable /var/
                                #Qui prend comme valeur le chiffre dans /mapp[ligne][colonne]/
                                #...en le convertissant en str() pour pouvoir l'afficher
                                
                                var = self.mapp[ligne][colonne]    
                                
                                if var == 9 and var != 0:
                                    #On change le '*' de /mappCachee/ par la valeur de /var/
                                    self.mappCachee[ligne][colonne] = str(var)
                                    if var == 9:
                                        partieEnCours = False
                                    else:
                                        partieEnCours = True
                                    return
                                    
                                else:
                                    #On regarde autour de cette case s'il y a d'autres '0'
                                    for ii in range(max(0, ligne-1), min(ligne+2, self.longueur)):         
                                        for jj in range(max(0, colonne-1), min(colonne+2, self.longueur)):
                                            self.creuser(ii, jj) #Appel récursif
                        
                                return partieEnCours
                        


                        Suis-je bête ou tout simplement nul ? (Les deux à la fois?)... merde alors! :o
                        • Partager sur Facebook
                        • Partager sur Twitter
                          10 septembre 2010 à 13:22:16

                          creuser(case):
                            - si la case est déjà creusée:
                                - stop
                            - [sinon] si la case contient une bombe:
                                - gameover
                                - stop
                            - [sinon] retirer le masque de la case
                            - si la case est nulle:
                                - pour chaque case adjacente 'casadj':
                                    - creuser(casadj)
                          • Partager sur Facebook
                          • Partager sur Twitter
                          Zeste de Savoir, le site qui en a dans le citron !
                          Anonyme
                            10 septembre 2010 à 13:28:00

                            Salut,

                            Effectivement, en utilisant les fonctions min/max, ça devient un peu plus lisible. Après, question efficacité, ce n'est pas d'ailleurs plus rapide ces deux boucles plutôt que tous les branchements précédents ?

                            Bonne après-midi.
                            • Partager sur Facebook
                            • Partager sur Twitter
                              10 septembre 2010 à 13:33:09

                              Citation : Sparrow

                              Après, question efficacité, ce n'est pas d'ailleurs plus rapide ces deux boucles plutôt que tous les branchements précédents ?


                              C'est kif-kif, l'algo n'est pas fondamentalement changé, il est juste écrit de manière plus concise.

                              D'ailleurs, on peut remarquer que quand on écrit la double-boucle, on compte aussi la case qui courante, donc on traite une case de plus alors que ça sert à rien de la traiter (mais entre traiter 8 ou 9 cases, la différence est négligeable).

                              Edit : me suis gouré dans mes explications, j'ai pris la case "courante" pour la case "qui contient la mine", parce que j'ai confondu avec mon algo. :p
                              • Partager sur Facebook
                              • Partager sur Twitter
                              Zeste de Savoir, le site qui en a dans le citron !
                                10 septembre 2010 à 13:50:10

                                :ange: ça marche !!!

                                >_< j'en aurais eu des migraines pour trouver (grâce à ton aide très précieuse) cette algorithme récursif :ninja: .
                                En tout merci à toi. Il me reste un bug à corriger, une fois fait, je passe à Tkinter (si le temps me le permet).

                                Voici mon code en entier:
                                P.S: Encore merci :)

                                ################################
                                ## Les Modules Importés:(2)   ##
                                #
                                import random
                                import os
                                
                                                                                               
                                #-*-*- <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()
                                
                                        """
                                        self.a_dePlateau = Plateau()
                                        self.partieEnCours = True
                                        
                                        #Appel de la fonction lors de l'instantation de <Jeu>
                                        self.jouer() 
                                
                                
                                    def jouer(self):
                                        """Toutes les fonctions qui doivent être
                                           appellées pour jouer sont mises ici.
                                        """
                                        self.regle()
                                        
                                        while self.partieEnCours == True:
                                            self.a_dePlateau.genererGrille() 
                                            self.a_dePlateau.cacherGrille()
                                        
                                            while(self.partieEnCours is True and self.a_dePlateau.nombreMines > 0):
                                                    self.action()
                                                    self.afficher()
                                
                                                    if self.gagner() == False:
                                                        break
                                                    
                                        #L'utilisateur veut t'il rejouer ?        
                                        rejouer = input("\nVoulez vous rejouer. <O> = oui et <N> = Non\n>")
                                        if rejouer.upper() == 'O':
                                            self.partieEnCours = True 
                                        else:
                                            self.partieEnCours = False
                                
                                   
                                    def gagner(self):
                                        """Le joueur a t-il gagner?"""
                                        if self.a_dePlateau.nombreMines <= 0:
                                            #Appel de la fonction *verificationMap*
                                            #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."""
                                        #Affiche le plateau chiffré(Pour debugger). Comptage du nombre de mines restantes.
                                        for i in self.a_dePlateau.mapp: print(i, end="" + '\n')   
                                        print("Nombres de mines restantes:", self.a_dePlateau.nombreMines)
                                
                                        #Plateau de jeu de la version jouable.
                                        for i in self.a_dePlateau.mappCachee: print(i, end="" + '\n')
                                
                                
                                    def action(self):
                                        """Permet de choisir entre *creuser* ou
                                            *poserDrapeau.
                                            Permet de choisir une case pour l'une ou l'autre des méthodes.
                                        """
                                        #On commence par créer une boucle infinie
                                        #On convertit la varibale en (type:int)
                                        #...pour savoir si je ne suis pas en index out of range
                                        #...lors de la saisit de la variable.
                                        #On demande si l'utilisateur veut *creuser* ou *poserDrapeau*
                                        #On recupère le tout dans /partieEncours/ qui sera retournée
                                        #...en fin de fonction pour savoir si on arrête le jeu ou pas
                                        
                                        while True:
                                            
                                            ligne = input("\n\nLigne N°: ")
                                            if len(ligne) == 1:
                                                
                                                try:
                                                    ligne = int(ligne)
                                                except ValueError:
                                                    print("\n*Il faut rentrer un nombre, recommencez du début*")
                                                    continue
                                                
                                                if not ligne in range(self.a_dePlateau.longueur):
                                                    continue
                                            
                                            colonne = input("Colonne N°: ")
                                            if len(colonne) == 1:
                                
                                                try:
                                                    colonne = int(colonne)
                                                except ValueError:
                                                    print("\n*Il faut rentrer un nombre, recommencez du début*")
                                                    continue
                                                
                                                if not colonne in range(self.a_dePlateau.longueur):
                                                    continue
                                                else:
                                                    break
                                
                                        while True:
                                            choix = input("\nC = Creuser; D = Poser un drapeau: Que faire: >")
                                            if choix.upper() == "C":
                                                #Appel de la méthode *creuser*
                                                self.partieEnCours = self.a_dePlateau.creuser(ligne, colonne)
                                                break
                                            
                                            elif choix.upper() == "D":
                                                #Appel de la méthode *poserDrapeau*
                                                self.partieEnCours = self.a_dePlateau.poserDrapeau(ligne, colonne)
                                                break
                                            
                                            else:
                                                #Si non le choix est incorrecte, ré-entre dans la boucle
                                                continue
                                        
                                
                                    def regle(self):
                                        """Les règles du jeu"""
                                        print("""Le but du jeu du démineur est de trouver toutes les mines présentes sur le
                                terrain.
                                Le terrain est chiffré, et chaque chiffre indique le nombre de bombes
                                présentes dans les huit cases qui l'entoure:
                                Pour choisir une case, il vous faut rentrer la <ligne> puis la <colonne>
                                sous forme 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 zéro à
                                quatre.
                                Tout chiffre superieur ou inférieur à ce nombre, ne sera pas accepté.
                                
                                
                                0: Zéro bombe
                                1: Une bombe
                                ...
                                9: C'est une case bombe
                                               Bon Jeu et bonne chance.""")
                                        
                                        input("\n\nAppuyez sur une touche pour commencer:>")
                                        os.system("CLS")
                                        
                                #-*-*- 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.longueur = 5    #Longueur de la grille: 5²
                                        self.mappCachee = []
                                        self.nombreMines = 0
                                
                                        
                                    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.longueur):
                                            self.mapp.append([0] * self.longueur)
                                
                                        #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.longueur)
                                        #Le numéro '9' (type:int) représente une bombe
                                        self.col, self.ligne, self.bombe = random.randrange(0, self.longueur), random.randrange(0, self.longueur), 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.longueur):      
                                            for j in range(self.longueur):      
                                                newL = []
                                                
                                                for ii in range(max(0, i-1), min(i+2, self.longueur)):         
                                                    for jj in range(max(0, j-1), min(j+2, self.longueur)):       
                                                        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 /longueur/²
                                        for i in range(self.longueur):
                                            self.mappCachee.append(['*'] * self.longueur)
                                
                                    
                                    def poserDrapeau(self, ligne, colonne):
                                        """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écouvert:
                                                     - 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[ligne][colonne]    
                                        
                                        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[ligne][colonne] = str(var)
                                
                                        return True
                                
                                
                                    def creuser(self, ligne, colonne):
                                        """Permet de dévoiler une case dans
                                           la variable /mappCachee/
                                        """
                                        #Je créer une variable /var/
                                        #Qui prend comme valeur le chiffre dans /mapp[ligne][colonne]/
                                        #- si la case est déjà creusée:
                                        #  - STOP
                                        #- sinon si la case contient une bombe:
                                        #  - Game over puis on stop la fonction
                                        #- sinon on retire le masque de la case str() pour pouvoir l'afficher
                                        #- Si la case est nulle
                                        #  - On regarde autour de cette case s'il y a d'autres '0'
                                        #  - Appel récursif de la fonction
                                        
                                        var = self.mapp[ligne][colonne]    
                                       
                                        if self.mappCachee[ligne][colonne] == str(var):
                                            return
                                        
                                        elif var == 9:
                                            partieEnCours = False 
                                            return     
                                        else:
                                            self.mappCachee[ligne][colonne] = str(var)
                                            
                                        if var == 0: 
                                            #On regarde autour de cette case s'il y a d'autres '0'
                                            for ii in range(max(0, ligne-1), min(ligne+2, self.longueur)):         
                                                for jj in range(max(0, colonne-1), min(colonne+2, self.longueur)):
                                                    self.creuser(ii, jj) 
                                
                                        return True
                                            
                                
                                #Sans oublié ca :-)
                                if __name__ == '__main__':
                                    p = Jeu()
                                    p.jouer()
                                


                                P.P.S:
                                - As-tu trouvé comment faire avec Curse ?
                                - Ensuite, penses-tu utiliser Pygame ou Tkinter ?



                                • Partager sur Facebook
                                • Partager sur Twitter
                                  10 septembre 2010 à 13:55:03

                                  Pour curses, non, j'ai pas encore trouvé comment gérer la souris correctement, mais à vrai dire c'est complètement secondaire (le principe de curses, c'est que ce sont des interfaces pour la console, et en général dans une interface console, on utilise plutôt le clavier), j'en fais pas une affaire d'état pour l'instant. :p

                                  Et sinon, non, je ne vais finalement pas faire l'interface avec tkinter parce qu'après avoir regardé comment fonctionne ce module, il ne m'a pas du tout séduit (trop "primitif", et puis, je le confesse, j'aime pas programmer des GUI :p). En fait, si je crée une seconde interface (ce qui n'est pas gagné, parce qu'entre-temps j'ai eu une autre idée de projet de jeu, un peu plus complexe — et riche — qu'un démineur, et que j'aimerais l'explorer correctement avant de décider si j'en fais un autre mini-projet dans ce style ou bien un tuto), je la ferai probablement avec Pygame.
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                  Zeste de Savoir, le site qui en a dans le citron !
                                    10 septembre 2010 à 14:01:54

                                    Si j'aurai les compétences nécessaires, je l'aurai aussi fait sous Pygame. (C'est pour cela que j'attends ton tutoriel avec impatience ;) )

                                    Citation : Nohar

                                    si j'en fais un autre mini-projet dans ce style ou bien un tuto), je la ferai probablement avec Pygame.


                                    Et pourquoi pas les deux à la fois ? :p
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      10 septembre 2010 à 14:09:08

                                      Un démineur, pour Pygame, c'est un bon premier projet : les sprites sont statiques, c'est juste un plateau qui se met à jour, c'est aussi simple à coder (comme interface) qu'un morpion. Tu galèrerais probablement moins qu'avec tkinter.

                                      Et sinon, je pense qu'entre un mini-projet "animé" dans ce style-là ou un tuto, il y a une grosse différence d'approche. La première, c'est "essayez, faites des erreurs, et on améliore au fur et à mesure qu'on avance", la seconde, c'est "ok, pour faire ça, vous allez avoir besoin de voir telle, telle et telle notion qui ne s'invente pas, alors j'en profite pour vous expliquer avant de passer à la pratique". Le jeu auquel je pense est typiquement adapté à Pygame, et je crois qu'il nécessite de voir plusieurs notions importantes... donc on verra, mais je penche plus pour un tuto. ;)
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                      Zeste de Savoir, le site qui en a dans le citron !
                                        10 septembre 2010 à 14:47:23

                                        Ne me fait pas plus languir, quel est donc ce jeu ? ;)

                                        Citation : Nohar

                                        les sprites sont statiques, c'est juste un plateau qui se met à jour


                                        Justement c'est au niveau des Sprites que je coince, RanderPlain et cie, il y en a trop :-°. Et puis bon, la doc n'est pas super bien non-plus.
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          10 septembre 2010 à 14:52:09

                                          Citation : realmagma

                                          Ne me fait pas plus languir, quel est donc ce jeu ? ;)



                                          hmm, je préfère garder ça secret, mais pour indice, c'est un jeu de plate-formes, sans scrolling, très technique (il faut beaucoup plus de skill pour le finir que pour le coder...).

                                          Citation : realmagma


                                          Justement c'est au niveau des Sprites que je coince, RanderPlain et cie, il y en a trop :-°. Et puis bon, la doc n'est pas super bien non-plus.


                                          Justement, s'ils sont statiques, tu n'as pas besoin d'utiliser la classe Sprite, mais juste d'encapsuler une surface et des coordonnées. L'utilisation des classes Sprites est plus compliquée parce qu'elles intègrent plusieurs mécanismes qui permettent d'optimiser l'affichage ou la gestion de très nombreux sprites mobiles, ce qui n'est pas nécessaire ici parce qu'entre 2 clics, rien n'a besoin de bouger. ;)
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                          Zeste de Savoir, le site qui en a dans le citron !
                                            11 septembre 2010 à 3:04:07

                                            @Nohar:
                                            while self.cells[idx].mine:
                                                            idx = randint(0, rows * cols -1)
                                            


                                            il me semble que si quelqu'un de vraiment maladroit teste ton code, il risque une jolie boucle infinie.
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              11 septembre 2010 à 8:37:04

                                              Citation : Nohar

                                              Citation : realmagma


                                              Justement c'est au niveau des Sprites que je coince, RanderPlain et cie, il y en a trop :-°. Et puis bon, la doc n'est pas super bien non-plus.


                                              Justement, s'ils sont statiques, tu n'as pas besoin d'utiliser la classe Sprite, mais juste d'encapsuler une surface et des coordonnées. L'utilisation des classes Sprites est plus compliquée parce qu'elles intègrent plusieurs mécanismes qui permettent d'optimiser l'affichage ou la gestion de très nombreux sprites mobiles, ce qui n'est pas nécessaire ici parce qu'entre 2 clics, rien n'a besoin de bouger. ;)


                                              C'est bon, tu m'as convaincu, je le ferai donc sous Pygame (pas d'utilisation de la classes <Sprite>, bonne nouvelle :D )
                                              Par contre nous sommes bien d'accord sur le fait qu'il faut bien une classe <Affichage> à présent ;)

                                              Bonne journée.
                                              Realmagma.

                                              EDIT: Finalement ça attendra, j'ai un énorme bug au niveau de la méthode *creuser* qui me fait perdre dès que je creuse à un endroit où il y a un chiffre autre que '0'.
                                              Quand je creuse et je tombe sur un zéro, pratiquement toute la mappCachee se dévoile.
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                11 septembre 2010 à 9:00:55

                                                @psimod :
                                                Ah ouais, c'est pas faux, si l'utilisateur rentre n'importe quoi en créant le champ (genre 30 mines pour une grille 5×5). Il faut que je rajoute un comportement d'erreur ici. Merci de l'avoir remarqué.
                                                Edit : voilà, c'est corrigé.

                                                @realmagma :
                                                T'es pas forcément obligé de créer une classe Affichage... Perso, pour mon interface, j'ai grosso-modo dérivé ma classe Cell en CursesCell (en ajoutant une méthode "display"), ma classe Field en CursesField (de même) et j'ai créé une classe CursesGame qui orchestre l'affichage du tout (par délégation principalement) ainsi que les interactions avec l'utilisateur.
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                Zeste de Savoir, le site qui en a dans le citron !
                                                  11 septembre 2010 à 9:53:54

                                                  Je viens de régler le petit bug, je vais commencer Pygame :)

                                                  EDIT:
                                                  Quand tu dis 'dériver' tu veux dire 'hériter' ?
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    11 septembre 2010 à 13:44:27

                                                    Citation : realmagma


                                                    Quand tu dis 'dériver' tu veux dire 'hériter' ?



                                                    Oui.
                                                    On "dérive" une classe de base en une classe dérivée. La classe dérivée "hérite" des comportements de sa classe de base.
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                    Zeste de Savoir, le site qui en a dans le citron !
                                                      11 septembre 2010 à 13:48:44

                                                      Citation : NoHaR

                                                      Citation : realmagma


                                                      Quand tu dis 'dériver' tu veux dire 'hériter' ?



                                                      Oui.
                                                      On "dérive" une classe de base en une classe dérivée. La classe dérivée "hérite" des comportements de sa classe de base.



                                                      OK ça marche.
                                                      Après réflexion, je vais plutôt le faire sous Tkinter. Je dois apprendre comment le module marche, comment créer des fenêtres ETC.
                                                      De toute façon je n'ai pas les compétences requises pour le faire sous Pygame. Je le ferai une fois ton tutoriel fait et validé ;) .

                                                      Ton interface graphique avance ?
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        11 septembre 2010 à 13:52:31

                                                        Elle était déjà finie avant que le sujet soit créé (sinon j'aurais eu du mal à faire les screenshots :-° ).
                                                        J'attends juste que d'autres postent la leur avant de l'envoyer.
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                        Zeste de Savoir, le site qui en a dans le citron !
                                                          13 septembre 2010 à 14:49:11

                                                          Salut.
                                                          Finalement, j'ai décidé de poster aujourd'hui le code correspondant à la phase 3 de mon démineur afin de pouvoir recueillir vos critiques/avis/idées d'améliorations.

                                                          Voici la totalité du code :

                                                          core.py (identique à la phase 2)

                                                          #!/usr/bin/env python
                                                          #-*- coding: utf-8 -*-
                                                          
                                                          from __future__ import print_function
                                                          from random import randint
                                                          
                                                          ###############################################################################
                                                          # Constantes globales
                                                          
                                                          MINE = '*'    # Dessin d'une mine
                                                          FLAG = '!'    # Drapeau
                                                          NOFLAG = '.'  # Case cachée normale
                                                          NOTHING = ' ' # Case vide
                                                          
                                                          class Cell(object):
                                                              """
                                                              Classe modélisant une case du champ de mines.
                                                          
                                                              """
                                                              def __init__(self):
                                                                  """
                                                                  Initialisation des attributs.
                                                          
                                                                  """
                                                                  self.mine = False  # La case contient-elle une mine ?
                                                                  self.flag = False  # Y-a t'il un drapeau posé sur cette case ?
                                                                  self.show = False  # La case est-elle visible ?
                                                                  self.value = 0     # Combien de cases adjacentes contiennent une mine ?
                                                          
                                                              def __str__(self):
                                                                  """
                                                                  Retourne un caractère symbolisant l'état de la case.
                                                          
                                                                  """
                                                                  if self.show:
                                                                      return str(self.value) if self.value else NOTHING
                                                                  else:
                                                                      return FLAG if self.flag else NOFLAG
                                                          
                                                          class Field(object):
                                                              """
                                                              Classe modélisant un champ de mines.
                                                          
                                                              """
                                                              def __init__(self, rows, cols, n_mines):
                                                                  """
                                                                  Initialisation du champ de mines.
                                                          
                                                                  rows: nombre de lignes
                                                                  cols: nombre de colonnes
                                                                  n_mines: nombre de mines
                                                          
                                                                  """
                                                                  if rows < 1 or cols < 1:
                                                                      raise ValueError('rows et cols doivent être positifs')
                                                                  if n_mines > rows * cols:
                                                                      raise ValueError('trop de mines')
                                                                  self.rows = rows
                                                                  self.cols = cols
                                                                  self.n_mines = n_mines
                                                                  self.hidden = rows * cols  # nombre de cases cachées
                                                                  self.flagged = 0           # nombre de cases portant un drapeau
                                                                  self.gameover = False
                                                                  self.cells = []
                                                                  self._init_cells()         # initialisation des cases
                                                                  # remplissage aléatoire du champ de mines
                                                                  for _ in xrange(n_mines):
                                                                      idx = randint(0, rows * cols -1)
                                                                      while self.cells[idx].mine:
                                                                          idx = randint(0, rows * cols -1)
                                                                      row = idx // cols
                                                                      col = idx - row * cols
                                                                      self.cells[idx].mine = True
                                                                      self._count_mines(row, col)
                                                                  
                                                              def _init_cells(self):
                                                                  """
                                                                  Initialisation des cases.
                                                                  Cette fonction pourra être surchargée si une classe fille désire 
                                                                  utiliser une autre classe pour les cases. (voir interface)
                                                          
                                                                  """
                                                                  self.cells = [Cell() for _ in xrange(self.rows * self.cols)]
                                                          
                                                              def _count_mines(self, row, col):
                                                                  """
                                                                  Incrémente les compteurs de mines autour de la case (row, col)
                                                                  row: numéro de ligne de la case.
                                                                  col: numéro de colonne de la case.
                                                          
                                                                  """
                                                                  for r in xrange(max(row-1, 0), min(row+2, self.rows)):
                                                                      for c in xrange(max(col-1, 0), min(col+2, self.cols)):
                                                                          self.cells[r * self.cols + c].value += 1
                                                              
                                                              @property
                                                              def won(self):
                                                                  """
                                                                  Propriété (s'utilise comme un attribut 'won' en lecture seule).
                                                                  Retourne True si la partie est gagnée, False sinon.
                                                          
                                                                  """
                                                                  return self.n_mines == self.hidden
                                                          
                                                              def flag_cell(self, row, col):
                                                                  """
                                                                  Pose un drapeau sur la case à la position (row, col) et incrémente le
                                                                  compteur de drapeaux posés.
                                                                  Effectue l'inverse si un drapeau est déjà présent sur cette case.
                                                                  Ne fait rien si la case n'est pas masquée.
                                                                  
                                                                  row: numéro de ligne de la case.
                                                                  col: numéro de colonne de la case.
                                                          
                                                                  """
                                                                  cell = self.cells[row * self.cols + col]
                                                                  if not cell.show:
                                                                      cell.flag = not cell.flag 
                                                                      if cell.flag:
                                                                          self.flagged += 1
                                                                      else:
                                                                          self.flagged -= 1
                                                              
                                                              def play_cell(self, row, col):
                                                                  """
                                                                  Joue ("creuse") la case à la position (row, col).
                                                                  row: numéro de ligne de la case.
                                                                  col: numéro de colonne de la case.
                                                          
                                                                  """
                                                                  cell = self.cells[row * self.cols + col]
                                                                  # si la case porte un drapeau ou si elle est déjà découverte,
                                                                  # ne rien faire
                                                                  if cell.show or cell.flag:
                                                                      return
                                                                  # si la case porte une mine, la partie est terminée.
                                                                  if cell.mine:
                                                                      self.gameover = True
                                                                  # sinon...
                                                                  else:
                                                                      # on découvre la case
                                                                      cell.show = True
                                                                      self.hidden -= 1
                                                                      # si la case est nulle, on creuse aussi son voisinage
                                                                      if cell.value == 0:
                                                                          for r in xrange(max(row-1, 0), min(row+2, self.rows)):
                                                                              for c in xrange(max(col-1, 0), min(col+2, self.cols)):
                                                                                  self.play_cell(r, c)
                                                                      # enfin, on regarde si la partie est gagnée
                                                                      self.gameover = self.won
                                                          
                                                              def __str__(self):
                                                                  """
                                                                  Retourne une représentation du champ de mines sous forme de string,
                                                                  pour l'affichage.
                                                          
                                                                  """
                                                                  str_grid = '+' + '-' * self.cols + '+'
                                                                  for idx, cell in enumerate(self.cells):
                                                                      ch_line = idx % self.cols
                                                                      if ch_line == 0:
                                                                          str_grid += '\n|'
                                                                      if self.gameover and cell.mine:
                                                                          str_grid += MINE
                                                                      else:
                                                                          str_grid += str(cell)
                                                                      if ch_line == self.cols-1:
                                                                          str_grid += '|'
                                                                  str_grid += '\n+' + '-' * self.cols + '+'
                                                                  return str_grid
                                                          
                                                          class Game(object):
                                                              """
                                                              Classe gérant l'exécution du jeu.
                                                          
                                                              """
                                                              def __init__(self, rows, cols, n_bombs):
                                                                  """
                                                                  Initialisation du jeu.
                                                          
                                                                  """
                                                                  self.field = Field(rows, cols, n_bombs)
                                                                  self.flag = False   # mode 'creusage' ou 'drapeau'
                                                          
                                                              def run(self):
                                                                  """
                                                                  Exécution du jeu.
                                                          
                                                                  """
                                                                  prompt = "[c : creuser, d : drapeau, q : quitter]\n{0} > "
                                                                  while not self.field.gameover:
                                                                      print(self.field)
                                                                      entree = raw_input(
                                                                              prompt.format('drapeau' if self.flag else 'creuser'))
                                                                      self.parse_input(entree.strip().lower())
                                                                  print(self.field)
                                                                  if self.field.won:
                                                                      print('Gagné !')
                                                                  else:
                                                                      print('BOOM ! Perdu')
                                                          
                                                              def parse_input(self, in_str):
                                                                  """
                                                                  Traite la saisie de l'utilisateur.
                                                          
                                                                  """
                                                                  if in_str == 'q':
                                                                      raise SystemExit
                                                                  if in_str == 'c':
                                                                      self.flag = False
                                                                      return
                                                                  if in_str == 'd':
                                                                      self.flag = True
                                                                      return
                                                                      
                                                                  try:
                                                                      row, col = [int(num) for num in in_str.split()]
                                                                      if self.flag:
                                                                          self.field.flag_cell(row, col)
                                                                      else:
                                                                          self.field.play_cell(row, col)
                                                                  except (ValueError, TypeError):
                                                                      print('Entrée invalide : 2 nombres attendus')
                                                                  except IndexError:
                                                                      print('Entrée invalide : [0 <= ligne < {0}] [0 <= colonne < {1}]\
                                                                              '.format(self.field.rows, self.field.cols))
                                                          
                                                          if __name__ == '__main__':
                                                              g = Game(5, 5, 3)
                                                              g.run()
                                                          


                                                          cursesui.py (programme "principal", interface ncurses)

                                                          #!/usr/bin/env python
                                                          #-*- coding: utf-8
                                                          
                                                          from __future__ import division
                                                          import curses
                                                          from curses.wrapper import wrapper
                                                          import core
                                                          
                                                          ###############################################################################
                                                          # Constantes globales
                                                          
                                                          # jeux de couleurs
                                                          COLOR_DEFAULT = 0  # jeu de couleurs de base
                                                          COLOR_LOW     = 1  # peu de danger
                                                          COLOR_MEDIUM  = 2  # danger modéré
                                                          COLOR_HIGH    = 3  # danger élevé
                                                          COLOR_HIDDEN  = 4  # case masquée
                                                          COLOR_CURSOR  = 5  # curseur
                                                          COLOR_MINE    = 6  # case avec une mine
                                                          
                                                          # dimensions / positions de l'interface (en caractères/lignes)
                                                          FIELD_COLS = 50
                                                          FIELD_ROWS = 20
                                                          FIELD_POS_R = 3
                                                          FIELD_POS_C = 27
                                                          
                                                          INFO_ROWS = 7
                                                          INFO_COLS = 27
                                                          INFO_POS_R = 3
                                                          INFO_POS_C = 0
                                                          
                                                          HELP_ROWS = 7
                                                          HELP_COLS = 27
                                                          HELP_POS_R = 10
                                                          HELP_POS_C = 0
                                                          
                                                          DEFAULT_MINES = 100
                                                          
                                                          TITLE = "DeMiNaToR v0.2"
                                                          
                                                          ###############################################################################
                                                          
                                                          class CursesCell(core.Cell):
                                                              """
                                                              Case du champ de mines dans l'interface.
                                                              Hérite principalement du comportement d'une case normale, mais implémente
                                                              une méthode 'display' pour l'affichage (au lieu de __str__).
                                                          
                                                              """
                                                              def display(self, win, highlight=False, gameover=False):
                                                                  """
                                                                  Affiche une case à l'écran.
                                                                  win: "fenêtre" ncurses représentant le champ
                                                                  highlight: True si le curseur se trouve sur cette case.
                                                                  gameover: True si la partie est terminée (affiche les mines).
                                                          
                                                                  """
                                                                  if gameover and self.mine:
                                                                      attr = curses.color_pair(COLOR_MINE)
                                                                      char = core.MINE
                                                                      if highlight:
                                                                          attr |= curses.A_REVERSE
                                                                  elif not self.show:
                                                                      pair = COLOR_CURSOR if highlight else COLOR_HIDDEN
                                                                      char = core.FLAG if self.flag else core.NOTHING
                                                                      attr = curses.color_pair(pair) | curses.A_BOLD
                                                                  else:
                                                                      char = str(self.value) if self.value else core.NOTHING
                                                                      res = cmp(self.value, 3)
                                                                      if res < 0:
                                                                          pair = COLOR_LOW
                                                                      elif res == 0:
                                                                          pair = COLOR_MEDIUM
                                                                      else:
                                                                          pair = COLOR_HIGH
                                                                      attr = curses.color_pair(pair) | curses.A_BOLD
                                                                      if highlight:
                                                                          attr |= curses.A_REVERSE
                                                                  win.addstr(char, attr)
                                                          
                                                          class CursesField(core.Field):
                                                              """
                                                              Champ de mines affichable dans une interface ncurses.
                                                          
                                                              """
                                                              def __init__(self, rows, cols, n_mines, row_pos, col_pos):
                                                                  """
                                                                  Constructeur.
                                                                  rows, cols, n_mines: voir Field.__init__(self, rows, cols, n_mines)
                                                                  row_pos, col_pos: position (ligne et colonne) de la fenêtre ncurses.
                                                          
                                                                  """
                                                                  core.Field.__init__(self, rows, cols, n_mines)
                                                                  # position du curseur
                                                                  self.cur_row = 0    
                                                                  self.cur_col = 0
                                                                  self.window = curses.newwin(rows+2, cols+2, row_pos, col_pos)
                                                          
                                                              def _init_cells(self):
                                                                  """
                                                                  Surcharge de la fonction d'initialisation des cases.
                                                                  Utilise des CursesCells au lieu de Cells "de base".
                                                          
                                                                  """
                                                                  self.cells = [CursesCell() for _ in xrange(self.rows * self.cols)]
                                                          
                                                              def _refresh_cursor(self):
                                                                  """
                                                                  Raffraichit la position du curseur à l'écran.
                                                          
                                                                  """
                                                                  self.window.move(self.cur_row+1, self.cur_col+1)
                                                          
                                                              def display(self):
                                                                  """
                                                                  Affiche le champ de mines dans l'interface.
                                                          
                                                                  """
                                                                  self.window.border()
                                                                  for row in xrange(self.rows):
                                                                      for col in xrange(self.cols):
                                                                          self.window.move(row+1, col+1)
                                                                          cell = self.cells[row * self.cols + col]
                                                                          highlight = (row == self.cur_row and col == self.cur_col)
                                                                          cell.display(self.window, highlight, 
                                                                                  self.gameover and not self.won)
                                                                  self._refresh_cursor()
                                                                  self.window.refresh()
                                                          
                                                              def move_cursor(self, d_row, d_col):
                                                                  """
                                                                  Déplace le curseur de d_row lignes et d_col colonnes.
                                                          
                                                                  """
                                                                  self.cur_row = max(0, min(self.cur_row + d_row, self.rows-1))
                                                                  self.cur_col = max(0, min(self.cur_col + d_col, self.cols-1))
                                                                  self._refresh_cursor()
                                                          
                                                              def play(self):
                                                                  """
                                                                  Joue (creuse) la case à la position actuelle du curseur.
                                                          
                                                                  """
                                                                  self.play_cell(self.cur_row, self.cur_col)
                                                          
                                                              def flag(self):
                                                                  """
                                                                  Pose ou retire un drapeau à la position actuelle du curseur.
                                                          
                                                                  """
                                                                  self.flag_cell(self.cur_row, self.cur_col)
                                                          
                                                          class CursesGame(object):
                                                              """
                                                              Classe gérant le runtime du jeu.
                                                          
                                                              """
                                                              def __init__(self, stdscr):
                                                                  """
                                                                  Constructeur.
                                                                  stdscr: fenêtre ncurses principale.
                                                          
                                                                  """
                                                                  height, width = stdscr.getmaxyx()
                                                                  if height - FIELD_ROWS - FIELD_POS_R < 0:
                                                                      raise SystemExit('Display is too small.')
                                                                  stdscr.addstr(
                                                                          1, 
                                                                          30, 
                                                                          TITLE, 
                                                                          curses.color_pair(COLOR_MEDIUM) | curses.A_BOLD
                                                                          )
                                                                          
                                                                  stdscr.refresh()
                                                                  self.infowin = curses.newwin(
                                                                          INFO_ROWS, INFO_COLS, 
                                                                          INFO_POS_R, INFO_POS_C
                                                                          )
                                                                  self.helpwin = curses.newwin(
                                                                          HELP_ROWS, HELP_COLS,
                                                                          HELP_POS_R, HELP_POS_C
                                                                          )
                                                                  self.field = CursesField(
                                                                          FIELD_ROWS, FIELD_COLS,
                                                                          DEFAULT_MINES,
                                                                          FIELD_POS_R, FIELD_POS_C
                                                                          )
                                                                  self.display_info()
                                                                  self.display_help()
                                                                  self.field.display()
                                                          
                                                              def display_info(self):
                                                                  """
                                                                  Affiche des informations sur la partie en cours.
                                                          
                                                                  """
                                                                  self.infowin.clear()
                                                                  self.infowin.border()
                                                                  self.infowin.addstr(0, 3, "Info", curses.A_BOLD)
                                                                  width = self.field.cols
                                                                  height = self.field.rows
                                                                  total = width * height
                                                                  mines = self.field.n_mines
                                                                  cleared = total - self.field.hidden
                                                                  self.infowin.addstr(1, 1, 
                                                                          'Width      : {0}'.format(width))
                                                                  self.infowin.addstr(2, 1, 
                                                                          'Height     : {0}'.format(height))
                                                                  self.infowin.addstr(3, 1, 
                                                                          'Mines      : {0} ({1:.0%})'.format(mines, mines/total))
                                                                  self.infowin.addstr(4, 1,
                                                                          'Flags used : {0}'.format(self.field.flagged))
                                                                  total -= mines
                                                                  self.infowin.addstr(5, 1,
                                                                          'Cleared    : {0:.0%}'.format(cleared / total))
                                                                  self.infowin.refresh()
                                                          
                                                          
                                                              def display_help(self):
                                                                  """
                                                                  Affiche l'aide.
                                                          
                                                                  """
                                                                  self.helpwin.clear()
                                                                  self.helpwin.border()
                                                                  self.helpwin.addstr(0, 3, 'Commands', curses.A_BOLD)
                                                                  self.helpwin.addstr(1, 1, 'Arrow Keys : move cursor')
                                                                  self.helpwin.addstr(2, 1, 'Space Bar  : dig cell')
                                                                  self.helpwin.addstr(3, 1, 'F          : put flag')
                                                                  self.helpwin.addstr(4, 1, 'N          : new game')
                                                                  self.helpwin.addstr(5, 1, 'Q          : quit game')
                                                                  self.helpwin.refresh()
                                                          
                                                              def display_gameover(self):
                                                                  """
                                                                  Affiche le cadre 'Game Over'
                                                          
                                                                  """
                                                                  row = FIELD_POS_R + FIELD_ROWS //2 - 3
                                                                  col = FIELD_POS_C + FIELD_COLS //2 - 11
                                                                  gowin = curses.newwin(4, 21, row, col)
                                                                  gowin.border()
                                                                  if self.field.won:
                                                                      attr = curses.color_pair(COLOR_LOW) | curses.A_BOLD
                                                                      gowin.addstr(1, 1, '    WIN!!1! FTW', attr)
                                                                      gowin.addstr(2, 1, '     Game Over ', attr)
                                                                  else:
                                                                      attr = curses.color_pair(COLOR_HIGH) | curses.A_BOLD
                                                                      gowin.addstr(1, 1, '    BOOOOM!!!1!', attr)
                                                                      gowin.addstr(2, 1, '     Game Over ', attr)
                                                                  gowin.refresh()
                                                                  gowin.getch()
                                                          
                                                              def new_game(self):
                                                                  """
                                                                  Démarre une nouvelle partie.
                                                                  Si la partie précédente a été gagnée, on augmente automatiquement la
                                                                  difficulté en rajoutant 2% de mines.
                                                          
                                                                  """
                                                                  currpc = self.field.n_mines * 100 // (FIELD_ROWS * FIELD_COLS)
                                                                  if self.field.gameover and self.field.won:
                                                                      currpc += 2
                                                                  mines = (currpc * FIELD_ROWS * FIELD_COLS) // 100
                                                                  self.field = CursesField(
                                                                          FIELD_ROWS, FIELD_COLS, 
                                                                          mines, 
                                                                          FIELD_POS_R, FIELD_POS_C
                                                                          )
                                                                  self.field.display()
                                                                  self.display_info()
                                                          
                                                              def handle_user_input(self):
                                                                  """
                                                                  Gère les actions de l'utilisateur.
                                                                  Retourne True si la partie continue, False sinon.
                                                                  
                                                                  """
                                                                  char = self.field.window.getch()
                                                                  if char == ord(' '):
                                                                      self.field.play()
                                                                      self.display_info()
                                                                  elif char == ord('f'):
                                                                      self.field.flag()
                                                                      self.display_info()
                                                                  elif char == ord ('q'):
                                                                      raise SystemExit
                                                                  elif char == ord('n'):
                                                                      return False
                                                                  elif char == curses.KEY_LEFT or char == 68:
                                                                      self.field.move_cursor(0, -1)
                                                                  elif char == curses.KEY_RIGHT or char == 67:
                                                                      self.field.move_cursor(0, 1)
                                                                  elif char == curses.KEY_UP or char == 65:
                                                                      self.field.move_cursor(-1, 0)
                                                                  elif char == curses.KEY_DOWN or char == 66:
                                                                      self.field.move_cursor(1, 0)
                                                                  self.field.display()
                                                                  return True
                                                          
                                                              def run(self):
                                                                  """
                                                                  Exécution du jeu.
                                                          
                                                                  """
                                                                  self.new_game()
                                                                  while not self.field.gameover:
                                                                      if not self.handle_user_input():
                                                                          return
                                                                  self.display_gameover()
                                                          
                                                                     
                                                          def main(stdscr):
                                                              curses.curs_set(0)
                                                              curses.init_pair(COLOR_LOW,    curses.COLOR_GREEN, curses.COLOR_BLACK)
                                                              curses.init_pair(COLOR_MEDIUM, curses.COLOR_YELLOW,curses.COLOR_BLACK)
                                                              curses.init_pair(COLOR_HIGH,   curses.COLOR_RED,   curses.COLOR_BLACK)
                                                              curses.init_pair(COLOR_HIDDEN, curses.COLOR_BLACK, curses.COLOR_WHITE)
                                                              curses.init_pair(COLOR_CURSOR, curses.COLOR_WHITE, curses.COLOR_GREEN)
                                                              curses.init_pair(COLOR_MINE,   curses.COLOR_RED,   curses.COLOR_WHITE)
                                                              game = CursesGame(stdscr)
                                                              while True:
                                                                  game.run()
                                                          
                                                          if __name__ == '__main__':
                                                              curses.wrapper(main)
                                                          


                                                          Comme je l'ai dit, j'ai simplement dérivé les classes "Field" et "Cell" de manière à les rendre utilisables dans une interface ncurses (donc avec une méthode "display" et une petite adaptation des méthodes pour creuser et poser un drapeau de manière à gérer un curseur), et créé une classe "CursesGame", qui se contente d'orchestrer le déroulement de la partie et de maintenir l'interface à jour.

                                                          Le programme se lance en appelant python (2) sur le fichier cursesui.py

                                                          Je vous remercie d'avance pour toute suggestion ou remarque quant à ce code.
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                          Zeste de Savoir, le site qui en a dans le citron !
                                                            13 septembre 2010 à 15:29:05

                                                            Bonjour,

                                                            je trouve ton jeu particulièrement nul superbe ;) .
                                                            Je n'en attendais pas moins de ta part, beau boulot :) .

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

                                                            Pour info, je n'ai toujours pas commencé mon interface graphique, je suis en désaccord avec tkinter. Le temps que je le prenne en main et le dompte, il faudra attendre un bon momment :D .
                                                            Bonne journée.
                                                            • 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