Classe Carré magique en Python

Créer un carré magique en Python n’est pas nécessairement facile. Nous allons voir sur cette page comment créer un objet représentant un carré magique : à l’aide d’une classe.

Façade de la Passion de la Sagrada Familia, basilique de Barcelone

Cahier des charges du carré magique en Python

Faisons dans un premier temps une liste de tout ce que l’on souhaite:

  • créer un objet MagicSquare admettant en argument une liste dont la dimension sera notée n², n étant un entier naturel supérieur ou égal à 3;
  • afficher le carré magique sous forme de tableau;
  • vérifier si un carré est magique.

Le constructeur

Une classe est quelque chose qui commence très souvent par un constructeur : c’est ce qui définit les composantes de l’objet (pour faire simple).

Nous allons donc commencer par écrire;

class MagicSquare :
    def __init__(self, L) :
        self.dim = int( len(L)**0.5 )
        self.matrix = [ [ L[i+j*3] for i in range(self.dim) ] for j in range(self.dim) ]

Le constructeur définit ainsi avant tout une variable dim rattachée à l’objet (avec le “préfixe” self.), qui va représenter la dimension d’une matrice carrée définie à partir des éléments de la liste passée en argument lors de l’appel à la classe. Ainsi, quand on écrit:

>>> square = MagicSquare ( [ 1,2,3,4,5,6,7,8,9 ] )

on construit la matrice:$$\begin{pmatrix}1&2&3\\4&5&6\\7&8&9\end{pmatrix}$$ de dimension 3.

Affichage

Il nous faut maintenant pouvoir afficher le carré ainsi défini (la matrice). On écrit alors une fonction d’affichage dans la classe, que l’on appelle une méthode: comme son rôle est d’afficher l’objet, cette méthode doit être assimilée à une chaîne de caractères (mais pour l’objet défini); on va donc définir la méthode sous le nom “__str__”.

def __str__(self) :
        out = ''
        p = 1
        w = int( log( self.dim , 10) ) + 1 # nombre de chiffres dans self.dim pour le formattage de l'affichage
        formatage = '%' + str(w+3) + 'd'
        for row in self.matrix:
            for coef in row:
                out += str( formattage % ( coef ) )
                if p % self.dim == 0:
                    out += '\n'
                p += 1
        return out

Là, je me suis un peu lâché car je voulais un “bel” affichage (dans la mesure du possible). J’ai donc formaté chaque coefficient en leur attribuant une dimension horizontale dépendante des coefficients. Avec cette méthode, en écrivant:

>>> square = MagicSquare ( [ 12,11,10,9,6,3,5,2,5 ] )
>>> print(square)

s’affiche:

12 11 10
 9  6  3
 5  2  5

Vérifier si le carré est magique en Python

Un carré est dit magique si la somme de chaque ligne, de chaque colonne et des deux diagonales est égale au même nombre. On arrive à démontrer (en mathématiques) que ce nombre est nécessairement égal à \(\frac{n(n^2+1)}{2}\). On peut alors imaginer une méthode isMagic qui renvoie “False” si le carré n’est pas magique, et “True” s’il l’est:

def isMagic(self):
   # on vérifie d'abord si tous les nombres sont uniques
   liste_nombres = []
   for row in self.matrix:
      for coef in row:
         if coef not in liste_nombres:
            liste_nombres.append( coef )
         else:
            return False
   somme_theorique = self.dim * (self.dim**2 + 1) // 2
        
   # somme de chaque ligne
   for row in self.matrix:
      somme = 0
      for coef in row:
         somme += coef
      if somme != somme_theorique:
         return False
        
   # somme de chaque colonne
   for column in range(self.dim):
      somme = 0
      for row in range(self.dim):
         somme += self.matrix[row][column]
      if somme != somme_theorique:
         return False
            
   # somme des diagonales
   somme1 , somme2 = 0 , 0
   for i in range(self.dim):
      somme1 += self.matrix[i][i]
      somme2 += self.matrix[i][self.dim-1-i]
   if somme1 != somme_theorique or somme2 != somme_theorique:
      return False
        
   return True

Cette méthode n’est pas du tout optimale (car elle contient bien trop de boucles), mais cela fera l’affaire pour nous (mon but est d’être pédagogue et non de proposer tout de suite une méthode optimale). D’ailleurs, vous pouvez imaginer votre propre méthode en utilisant une autre philosophie que celle adoptée ici. Par exemple, vous pouvez jeter un coup d’œil sur cette page pour vous donner une autre idée (il y a des solutions bien plus efficaces, mais plus compliquées à comprendre).

Construire tous les carrés magiques d’une dimension donnée en Python

Nous allons nous servir de cette classe afin de construire tous les carrés magiques d’ordre 3.

def all_squares():
    for a1 in range(1,10):
        for a2 in range(1,10):
            for a3 in range(1,10):
                for b1 in range(1,10):
                    somme = a1 + a2 + a3
                    c1 = somme - a1 - b1
                    b2 = somme - a3 - c1
                    b3 = somme - b1 - b2
                    c2 = somme - a2 - b2
                    c3 = somme - c1 - c2
                    M = MagicSquare( [a1,a2,a3,b1,b2,b3,c1,c2,c3] )
                    if M.isMagic() and 0 < b2 < 10 and 0 < b3 < 10 and 0 < c1 < 10 and 0 < c2 < 10 and 0 < c3 < 10 :
                        print(M)
                        print("---------------")
                        
all_squares()

Cette solution, proposée par un élève du professeur qui a écrit cette page, fonctionne très bien. Elle affiche :

2 7 6
9 5 1
4 3 8
------------
2 9 4
7 5 3
6 1 8
------------
4 3 8
9 5 1
2 7 6
------------
4 9 2
3 5 7
8 1 6
------------
6 1 8
7 5 3
2 9 4
------------
6 7 2
1 5 9
8 3 4
------------
8 1 6
3 5 7
4 9 2
------------
8 3 4
1 5 9
6 7 2

Les abonné.e.s de mathweb.fr pourront trouver le programme Python complet sur cette page.

[Retour à la page principale]