Partage
  • Partager sur Facebook
  • Partager sur Twitter

Bouton Nouvelle Partie avec TkInter

    20 juin 2021 à 10:52:33

    C'est moi qui ait écrit les cinq fonctions du module matUtil et je m'"autorise" à l'importer sans le nommer, mes fonctions ont des noms suffisamment particuliers il me semble.

    Je comprends très bien la nécessité de présenter l'intégralité du code pour que ceux qui veuent aider puissent tester chez eux mais il se trouve déjà dans ce fill de discussion 10 messages au dessus, je le poste de nouveau ici :
    #====================================================
    #            module   matUtil
    # Liste de  toutes les fonctions vues en cours pour 
    # tester lignes, colonnes et diagonales d'une matrice
    #====================================================
    
    def egalListe(tab):
        """ teste si tous les élements d'une liste plate sont égaux
         arg : une liste plate (non vide); retour : un booléen
         [2, 2, 2,] --> True, [2, 1, 2,] --> False"""
        for elmt in tab:
            if elmt != tab[0]:
                return False
        return True
    
    
    def extraitColonne(mat, n):
        """ extrait une colonne d'une matrice
    arg : une matrice n x p (non vide), num de colonne(int) < p; retour : une liste"""
        colonne = []
        for i in range(len(mat)):
            colonne.append(mat[i][n])
        return colonne
    
    
    def extraitDiagonales(mat):
        """ extrait les deux diagonales d'une matrice carrée
    arg : une matrice carrée; retour : une liste de deux listes
    [première diagonale, deuxième diagonale]
    [[1, 2], [3, 4] --> [[1, 4], [2, 3]]"""
        diags = [[], []]
        for i in range(len(mat)):
            diags[0].append(mat[i][i])
            diags[1].append(mat[i][-i-1])
        return diags
    
    
    def egalLigne(mat, n):
        """ teste si tous les élements d'une ligne d'une matrice  sont égaux
    arg : une matrice n x p (non vide), num de ligne(int) < n; retour : un booléen """
        return egalListe(mat[n])
    
    
    def egalColonne(mat, n):
        """ teste si tous les élements d'une colone d'une matrice sont égaux
    arg : une matrice n x p (non vide), num de colonne(int) < p; retour : un booléen """
        return egalListe(extraitColonne(mat, n))
    
    
    if __name__ == "__main__":
        print(extraitDiagonales([[1, 2], [3, 4]]))

    -
    Edité par Tchae 20 juin 2021 à 10:52:52

    • Partager sur Facebook
    • Partager sur Twitter
      20 juin 2021 à 11:21:18

      Tchae a écrit:

      Merci pour tous ces conseils,

      Quelques réponses :

      1) le module matUtil est posté ici quelques messages plus haut, j'ai décidé d'extraire ces fonctions dans un module pour améliorer la lisibilité du code principal, il a été amélioré sur les conseils de fred1599


      2) ce "projet" est un exercice imposé par un enseignant (mon choix étant d'y ajouter une interface graphique) et l'algorithme de détection d'alignement était guidé dans l'exercice. Cependant il ne teste pas du tout toutes les colonnes, lignes et diagonales à chaque coup.
      Il ne teste que la ligne et la colonne courante et éventuellement les diagonales si on se trouve sur l'une (ou les deux) d'entre elles (fonction aGagne() )

      3) un futur développement de ce "projet" sera d'y insérer une "IA" contre laquelle on pourra jouer.

      4) Je ne souhaite pas proposer une nouvelle partie avant que la partie courante soit terminée.


      OK pour les points 1, 3 et 4. Et le morpion de Google propose de jouer à deux, après tout.

      Concernant 2, effectivement, tu n'en fais pas autant que ce que j'ai dit. Il n'empêche que je trouve le code assez lourd pour quelque chose d'aussi simple et que des calculs inutiles sont effectués.

      D'abord, et comme te l'as dit fred, il faut limiter autant que possible la dépendance d'une fonction à des variables externes qui ne sont pas des paramètres surtout s'il est crédible que ces variables ne soient pas constantes. Cela empêche de faire des tests unitaires et ça nuit à la lisibilité. Le cas typique est ta fonction aGagne (nom pas terrible + mixedCase mais je considère ça comme un détail) dont le code dépend d'une variable grille qui n'est pas un paramètre alors que grille varie tout le temps. En outre cette fonction devrait être placée dans matUtil car elle fait juste un calcul abstrait qui ne dépend pas de ton interface graphique en Tkinter (principe fondamental de codage d'une UI : essayer de se rapprocher d'un MVC et bien séparer la logique de la vue). Ça pour moi c'est une erreur ennuyeuse. Dans le même genre même si c'est plus discutable, ta variable TAILLE qui est une dépendance cachée dans de nombreuses fonctions. Je la mettrais en paramètre (et en minuscules car par convention les variables en capitales sont réservés aux variables invariables).

      Maintenant, concernant le codage de tes fonctions de matUtil, dans un premier temps, elles vont bien, elles marchent, c'est déjà ça. La fonction egalListe est algorithmiquement parfaite mais c'est peu lisible et Python permet d'obtenir le même résultat en une ligne de code (l'opérateur == permet de comparer des listes et il le fera de manière optimale par court-circuit)

      Ta fonction 

      def extraitColonne(mat, n):
          """ extrait une colonne d'une matrice
      arg : une matrice n x p (non vide), num de colonne(int) < p; retour : une liste"""
          colonne = []
          for i in range(len(mat)):
              colonne.append(mat[i][n])
          return colonne

      n'est pas incorrecte (toutefois : la docstring est peu lisible et le paramètre ne doit pas s'appeler n mais k) mais l'usage est d'écrire une liste en compréhension.

      Par ailleurs, ta fonction extraitDiagonales extrait les deux diagonales ce qui n'est clairement pas optimisé (si la première est gagnante, on aura construit la 2e pour rien).

      Mais, au-delà de ces détails, ta méthode de détection d'alignement a un inconvénient qu'on a tendance à retrouver dans du code plus avancé : le fait de (re)stocker ce qui n'a pas à l'être. Pour savoir si telle ligne de mon morpion est remplie, ai-je besoin de placer le contenu de la ligne dans une liste (et donc de recopier) pour ensuite les comparer ? Ai-je besoin de recopier la ligne OXOO pour voir si c'est un alignement ou pas (et encore pire si la première case est vide) ? Certainement pas, je suis dans une matrice et j'ai donc des indices qui me permettent de me diriger dans n'importe quelle direction et de faire la comparaison directement. Pour faire ça pythoniquement, utilise des expressions génératrices ainsi que la fonction standard all .

      • Partager sur Facebook
      • Partager sur Twitter
        20 juin 2021 à 12:31:10

        J'ai donc repris matUtil selon (certains de ) vos conseils :
        (les fonctions de matUtil et leur utilisation étant imposées par l'enseignant)

        #=====================================================
        #            module   matUtil
        # Liste de  toutes les fonctions vues en cours pour 
        # tester lignes, colonnes et diagonales d'une matrice
        #=====================================================
        
        def egalListe(tab):
            """ teste si tous les élements d'une liste plate sont égaux
             arg : une liste plate (non vide); retour : un booléen
             [2, 2, 2,] --> True, [2, 1, 2,] --> False"""
            for elmt in tab:
                if elmt != tab[0]:
                    return False
            return True
        
        
        def extraitColonne(mat, k):
            """ extrait une colonne d'une matrice
        arg : une matrice n x p (non vide), num de colonne(int) < p; retour : une liste"""
            return [mat[i][k] for i in range(len(mat))]
            
        
        
        def extraitDiagonales(mat):
            """ extrait les deux diagonales d'une matrice carrée
        arg : une matrice carrée; retour : une liste de deux listes
        [première diagonale, deuxième diagonale]
        [[1, 2], [3, 4] --> [[1, 4], [2, 3]]"""
            diags = [[], []]
            for i in range(len(mat)):
                diags[0].append(mat[i][i])
                diags[1].append(mat[i][-i-1])
            return diags
        
        
        def egalLigne(mat, k):
            """ teste si tous les élements d'une ligne d'une matrice  sont égaux
        arg : une matrice n x p (non vide), num de ligne(int) < n; retour : un booléen """
            return egalListe(mat[k])
        
        
        def egalColonne(mat, k):
            """ teste si tous les élements d'une colone d'une matrice sont égaux
        arg : une matrice n x p (non vide), num de colonne(int) < p; retour : un booléen """
            return egalListe(extraitColonne(mat, k))
        
        
        def aGagne(grille, lig, col):
            """ teste si tous les élements de la colonne ou de la ligne passant par
        la case (lig, col) d'une matrice carrée sont égaux,  si nécessaire teste
        aussi les diagonales.  arg : une matrice carree n x n (non vide),
        num de ligne, num de colonne (int) < n;  retour : un booléen """
            return (egalColonne(grille, col) or egalLigne(grille, lig) or
                        ((lig == col) and egalListe(extraitDiagonales(grille)[0])) or 
                        ((lig == len(grille) - col - 1)
                            and egalListe(extraitDiagonales(grille)[1])))
        
        
        if __name__ == "__main__":
            print(extraitDiagonales([[1, 2], [3, 4]]))
        


        -
        Edité par Tchae 20 juin 2021 à 12:32:42

        • Partager sur Facebook
        • Partager sur Twitter

        Bouton Nouvelle Partie avec TkInter

        × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
        • Editeur
        • Markdown