Bibm@th

Forum de mathématiques - Bibm@th.net

Bienvenue dans les forums du site BibM@th, des forums où on dit Bonjour (Bonsoir), Merci, S'il vous plaît...

Vous n'êtes pas identifié(e).

#1 17-03-2009 13:36:40

yoshi
Modo Ferox
Inscription : 20-11-2005
Messages : 11 421

[Python] Construction de carrés magiques impairs, simples ou gigognes.

Bonjour à tous,

En complément de la page http://www.bibmath.net/carres/index.php … oi=impairs, voici la version informatisée.

Ces carrés impairs, si leur dimension n'est pas multiple de 3, sont diaboliques. Voir la page précitée ou le le programme pour une définition de l'adjectif (on dit aussi pandiagonaux).
Une autre particularité intéressante de ce programme est la possibilité de construire des carrés gigognes (à deux dimensions).
Ainsi, vous pouvez construire un carré de dimension 35 (31 maximum pour l'affichage : il sera enregistré) :
- Soit sur la base de 35 = 5 x 7, c'est à dire de 7² = 49 carrés de dimension 5,
- Soit sur la base de 35 = 5 x 7, c'est à dire de 5² = 25 carrés de dimension 7.
Chacun des 49 carrés de dimension 5, ou des 25 carrés de dimension de 7, sera magique et diabolique, le carré de 35 étant lui-même globalement magique et diabolique...
Cela dit, vous pouvez aussi construire un carré "simple" (= à une dimension) d'ordre 35 : vous avez donc 3 carrés magiques et diaboliques possibles d'ordre 35.
Le seul carré gigogne magique et diabolique affichable est celui de 25 = 5 x 5...
Bien sûr la technique utilisée pour construire les carrés gigognes à deux dimensions est extensible à 3, 4... etc  dimensions : une explication figure pour 3 dimensions sur la page internet consacrée à ces carrés...

Une assistance, par l'exemple, à la construction de carrés magiques et diaboliques simples (dimension 5 ou 7), une démo détaillée de la construction du carré magique gigogne d'ordre 35 = 3 x 5 et une assistance à la construction du carré magique gigogne d'ordre 15 = 5 x 3 par vos soins sont incluses.
Je n'ai pas prévu la vérification du caractère magique (je vais voir pour la rendre optionnelle)...

#!/usr/bin/env python
# -*- coding: Latin-1 -*-

from os import getcwd

def titre_general():
    print
    print
    print "               *********************************************"
    print "               *      CARRES DE DIMENSIONS IMPAIRES        *"
    print "               *         simples et gigognes               *"
    print "               *********************************************"
    print    

def presentation():
    print "   Ce petit programme se propose de vous faire découvrir un certain type de carrés"
    print "magiques de dimension impaire."
    print "Tous les carrés construits de dimension multiple de 3 ne seront pas "+ chr(34)+"diaboliques"+chr(34)
    print "(ou pandiagonaux), les autres si."
    print "Outre les propriétés magiques classiques, pour les carrés non multiples de 3, il faut faire"
    print "intervenir la notion de "+chr(34)+" diagonale brisée"+chr(34)+"."
    print
    print "                      Exemple de diagonales brisées :"
    print "              |---|---|---|---|---|          |---|---|---|---|---|"
    print "              |   |   |   | X |   |          | O |   |   |   |   |"
    print "              |---|---|---|---|---|          |---|---|---|---|---|"
    print "              |   |   |   |   | X |          |   |   |   |   | O |"
    print "              |---|---|---|---|---|          |---|---|---|---|---|"
    print "              | X |   |   |   |   |          |   |   |   | O |   |"
    print "              |---|---|---|---|---|          |---|---|---|---|---|"
    print "              |   | X |   |   |   |          |   |   | O |   |   |"
    print "              |---|---|---|---|---|          |---|---|---|---|---|"
    print "              |   |   | X |   |   |          |   | O |   |   |   |"
    print "              |---|---|---|---|---|          |---|---|---|---|---|"
    print
    presse()
    print
    print "La somme des nombres figurés par un X, ou O est aussi égale à la constante magique, soit n(n²+1)/2,"
    print "65 pour un carré d'ordre 5."
    print "Partons du X sis en ligne 1, colonne 4, descendons d'une case vers la droite. Ensuite, comme"
    print "on ne peut sortir du carré, on descend sur la case en dessous et on ricoche vers la gauche "
    print "comme au billard !) et on reprend la descente. Le procédé est identique pour le O"
    print
    print "    Le carré cigogne (éventuellement diabolique) lui, est composé de carrés plus petits eux-mêmes"
    print "magiques (et éventuellement diaboliques). Ainsi le carré de 15 = 3 x 5 sera composé de 25 carrés"
    print "d'ordre 3, mais le carré de 15 = 5 x 3 sera lui composé de 9 carrés d'ordre 5."
    print "Il suffit de réfléchir quelques secondes pour voir que les deux carrés obtenus seront différents..."
    print " La multiplicationn magique n'est donc PAS COMMUTATIVE !"
    print
    return

def presse():
    print
    raw_input("                  ... Pour la suite, presser la touche ENTREE ...")
    print

def retour():
    print
    raw_input("                    ... Pour revenir au menu, presser ENTREE ...")
    print
   
def voici():
    print
    print "                      Voici le carré demandé :"
    print
   
def choix_type(gig):
    sortie=0
    while not sortie:
        try:
            gig = int(raw_input("Construction d'un carré simple ou gigogne (1/2) ? "))
            print
            if gig <1 or gig >2:
                print "Désolé ! Vous devez répondre avec 1 ou 2. Veuillez recommencer..."
                print
            else:
                sortie=1                  
        except ValueError:
            print "Désolé ! Ce n'est pas un nombre. Essayez encore..."
    return gig

def choix_dimension(dim):
    sortie=0
    while not sortie:
        try:
            dim = int(raw_input("Veuillez choisir une dimension impaire : "))
            if dim % 2 != 1:
                print "Désolé ! Vous n'avez pas entré une dimension valide. Veuillez recommencer..."
                print
            else:
                sortie=1
        except ValueError:
            print "Désolé ! Ce n'est pas un nombre. Essayez encore..."
    return dim

def calcul(dim,car_mag):
    L=[]
    dc,dl=(dim+1-2*(dim%3==0))/2,0
    lc,cc=dl,dc
    for j in range(dim):
        for i in range(dim):
            lc=lc-(i>0)
            lc+=dim*(lc==-1)
            cc=cc-(i>0)
            cc+=dim*(cc==-1)
            L.append(dim*lc+cc+1)
        car_mag.append(L)
        L=[]
        dl+=2
        dl-=dim*(dl>dim)
        lc=dl
        if dim%3==0:
            dc+=1
            dc-=dim*(dc==dim)
            cc=dc
        else:
            dc+=3
            dc-=dim*(dc>dim-1)
            cc=dc
    return dim,car_mag

def gigognes(n1,n2,car_nat,car_fin):
    dim,fin,car_mag,car_nat,car_fin=n1,n2**2,[],[],[]
    L1,L2,n=[],[],n1*n2
    dim,car_mag=calcul(dim,car_mag)
    for j in range(n):
        for i in range(n):
            L1.append(0)
            L2.append(0)
        car_nat.append(L1)
        car_fin.append(L2)
        L1,L2=[],[]
       
    for no_qd in range(fin):            
        # correctif pour passage dans le carré d'ordre n
        cl=no_qd/n2
        cc=no_qd%n2
        crl,crc=cl*n1,cc*n1
        for l in range(n1):
            for c in range(n1):
                # coordonnées de la case en cours
                j,i=l+crl,c+crc
                #print j,i," ",
                # nombre du carré n1 à mettre dans cette case
                dpl=car_mag[l][c]
                # coordonnées relatives dans carré n1 de ce nombre
                ll=(dpl-1)/n1
                cc=(dpl-1)%n1

                # coordonnées absolues dans carré n de ce nombre
                jj,ii=ll+crl,cc+crc
                car_nat[j][i]=n*jj+ii+1
             
    dim,car_mag=n2,[]
    dim,car_mag=calcul(dim,car_mag)
    # Boucle des nos de carrés (d'ordre n1) de 0 à n2^2
    for no_qd in range(fin):
        # Cordonnées des carrés d'ordre n1 (variant de 0 à n2)
        l_img=no_qd/n2
        c_img=no_qd%n2
        # correctif pour passage dans le carré d'ordre n
        cj,ci=l_img*n1,c_img*n1
        # numéro du carré aà déplacer
        ant=car_mag[l_img][c_img]
        # coordonnées absolues du 1er nombre du carré antécédent
        # variant de 0 à n2
        l_ant=(ant - 1)/n2
        c_ant=(ant -1)%n2
        # correctif pour passage dans le carré d'ordre n
        cl,cc=l_ant*n1,c_ant*n1
        # Déplacement des nombres du carré antécédent
        for l in range(n1):
            for c in range(n1):
                car_fin[cj+l][ci+c]=car_nat[cl+l][cc+c]
    return n1,n2,car_nat,car_fin

def demo3x5():
    n1,n2,n,ct,car_nat,car_fin,car_mag=3,5,15,1,[],[],[]
    print
    print
    print "                  ******************************************************"
    print "                  *      CONTRUCTION du CARRE d'ordre 15 = 3 x 5       *"
    print "                  ******************************************************"
    print    
    print "1. On commence par construire le carré naturel d'ordre 15 qu'on remplit avec"
    print "   les nombres de 1 à 225, puis on matérialise les 25 carrés de 3 x 3 :"
    print
    n1,n2,car_nat,car_fin=gigognes(n1,n2,car_nat,car_fin)
    cpc,cpl,sep=0,0,3
    affichage_separations(ct,sep,car_mag)
    dim,car_mag=3,[]
    presse()
    print "                                      2 7 6"
    print "2. A l'aide du carré de 3 que voici : 9 5 1"
    print "                                      4 3 8"
    print
    print"3. Dans chaque carré de 3 x 3, on déplace chaque nombre selon la structure ci-dessus :"
    print
    presse()
    car_mag=list(car_nat)
    ct=2
    affichage_separations(ct,dim,car_mag)
    presse()
    print "                                                                   ----------------"
    print "                                                                  |  4 23 17 11 10 |"
    print "4. On numérote de 1 à 25 les carrés de 3 dans l'ordre normal.     | 12  6  5 24 18 |"
    print "5. On déplace chaque carré à la place de son numéro dans le       | 25 19 13  7  1 |"
    print "   carré de 5 ci contre :                                         |  8  2 21 20 14 |"
    print "                                                                  | 16 15  9  3 22 |"  
    print "                                                                   ----------------"
    voici()
    car_mag=list(car_fin)
    print
    affichage_separations(ct,dim,car_mag)
    return

def solo5x3():
    n1,n2,n,ct,car_nat,car_fin,car_mag=5,3,15,1,[],[],[]
    print
    print
    print "                  ******************************************************"
    print "                  *      CONTRUCTION du CARRE d'ordre 15 = 5 x 3       *"
    print "                  ******************************************************"
    print
    print "1. Munissez-vous de quoi écrire..."
    print "2. Commencez par tracer trois grilles carrées de 15 x 15. Remplissez la"
    print "   première avec les nombres de 1 à 225, puis matérialisez les 9 carrés"
    print "   de 5 x 5 :"
    n1,n2,car_nat,car_fin=gigognes(n1,n2,car_nat,car_fin)
    cpc,cpl,sep,ct=0,0,5,1
    presse()
    affichage_separations(ct,sep,car_mag)
    print
    print "3. Construisez les carrés magiques d'ordre 5 et 3,"
    presse()
    print "                      -------------------- "
    print "                     |  4  23  17  11  10 |             -------"
    print "                     | 12   6   5  24  18 |            | 2 7 6 |"
    print "                     | 25  19  13   7   1 |            | 9 5 1 |"
    print "                     |  8   2  21  20  14 |            | 4 3 8 |"
    print "                     | 16  15   9   3  22 |             -------"  
    print "                      -------------------- "
    print " 4. Complétez chaque carré de base de la deuxième grille, avec les nombres"
    print "    du carré correspondant de la première grille, placés dans l'ordre de la"
    print "    strucure du carré d'ordre de 5 ci-dessus,"
    presse()
    car_mag=list(car_nat)
    ct=2
    affichage_separations(ct,sep,car_mag)
    print
    print "5. Numérotez les blocs de la deuxième grille de 1 à 9, puis complétez la"
    print "   dernière grille en plaçant chaque carré numéroté à la place qu'il occupe"
    print "   dans le carré de 3."
    presse()
    car_mag=list(car_fin)
    voici()
    affichage_separations(ct,sep,car_mag)
    return
   
def affichage_separations(ct,sep,car_mag):
    cpl,cpc=0,0
    tirets="----"
    ligne="         |------------------------------------------------\
-----------------"+tirets[0:4*(sep==3)]+"|"
    print ligne
    for j in range (15):
        print "         |",
        cpl+=1
        for i in range(15):
            cpc+=1
            if ct==1:
                nb=str(15*j+i+1)
            else:
                nb=str(car_mag[j][i])
            lg=len(nb)
            if lg==1:
                print"  "+nb,
            elif lg==2:
                print" "+nb,
            else:
                print nb,
            if cpc%sep==0 and i>0:
                print"|",
        print
        if cpl%sep==0 and j>0:
             print ligne
    return

def affichage(dim,n1,n2,car_mag):
    if dim<32:
        print
        for j in range(dim):
            for i in range(dim):
                if dim<10:
                    print "%2i" % car_mag[j][i],
                else:
                    print "%3i" % car_mag[j][i],
            print
    else:
        print "... Dimension trop grande pour l'affichage : écriture dans un fichier ..."
        presse()
        stockage(dim,n1,n2,car_mag)
    return

def stockage(dim,n1,n2,car_mag):
    rep = getcwd()
    if n2>1:
        nom = "Impairs_G" + str(n1)+"x"+str(n2)+".txt"
    else:
        nom = "Impairs_S" + str(dim)+".txt"
    chemin_nom=rep+chr(92)+nom
    fichier = open(nom,'w')
    lgmax = 1 + len(str(dim**2))
    blanc = "             "
    for j in range(dim):
        enreg=""
        for i in range(dim):
            nb = str(car_mag[j][i])
            lg = len(nb)
            enreg += blanc[0:lgmax-lg]+nb            
        fichier.write(enreg+"\n")
    fichier.close()
    print "Vous trouverez votre fichier ici",chemin_nom
    return

def gere_carres():
    gig,dim,n1,n2,Dim,car_nat,car_fin,car_mag=1,1,1,1,[],[],[],[]
    titre_general()  
    gig=choix_type(gig)
    for i in range(gig):
        dim=choix_dimension(dim)
        Dim.append(dim)
    if gig>1:
        n1,n2=Dim[0],Dim[1]
        n1,n2,car_nat,car_fin=gigognes(n1,n2,car_nat,car_fin)
        voici()
        dim=n1*n2
        car_mag=list(car_fin)
        if dim<32:
            voici()
        affichage(dim,n1,n2,car_mag)
    else:
        dim,car_mag=calcul(dim,car_mag)
        n1=dim
        if dim < 32:
            voici()
        affichage(dim,n1,n2,car_mag)
    return

def menu(mode):
    while mode >5 or mode <0:
        try:
            print
            print "                          ***********************"
            print "                          *   Menu principal    *"
            print "                          ***********************"
            print
            print "1. Voir un carré simple ou gigogne"
            print "2. Voir la méthode de construction d'un carré simple (n = 5 ou 7)"
            print "3. Construire vous-même le carré simple de dimension n = 11 et le vérifier"
            print "4. Voir la méthode construction du carré gigogne de 3 x 5"
            print "5. Construire vous-même le carré gigogne de 5 x 3"
            print "          0. Sortie du programme."
            print
            mode = int(raw_input("                            < Votre choix ? >  "))
            print
            if mode > 5 or mode <0 :
                print
                print "Désolé ! Votre choix n'est pas valide. Veuillez recommencer..."
                print
        except ValueError:
            print "Désolé ! Ce n'est pas un nombre. Essayez encore..."
            print
    return mode

def methode_car_simple(dim,car_mag):
    print
    print "              ********************************************************"
    print "              *  Méthode de constructions de carrés impairs simples  *"
    print "              ********************************************************"
    print
    print "Chacun des nombres de ce carré est répéré par un couple de coordonnées (ligne,colonne)"
    print "Voici pour chacun des nombres du carré magique, le n° de ligne puis le n° de colonne"
    print "donnant sa position dans le carré naturel ci-dessus :"
    print "                  N° de ligne                     N° de colonne"
    dim,car_mag=calcul(dim,car_mag)
    affiche_coordonnees(dim,car_mag)
    affiche_methode_coordonnees(dim)
    if dim==5:
        print "(3 ; 3) et donc le nombre 13."
    else:
        print "(6, 7) et donc le nombre 42."
    presse()
    print "Voici le carré "+chr(34)+"naturel"+chr(34)+" de dimension",dim,"et le carré magique correspondant"
    print
    for l in range(dim):
        print "                  ",
        for k in range(dim):
            nb=dim*l+k+1
            print "%2i" % nb,
        print "                  ",
        for k in range(dim):
            print "%2i" % car_mag[l][k],
        print
    return
 
def calcul_solo():
    print "                               ** RAPPEL **"
    print
    affiche_methode_coordonnees(11)
    print "(1 ; 4) dans le carré naturel et donc le nombre 4"
    print
    print "Construisez vos deux matrices de nos de lignes et de nos de colonne...",
    dim,car_mag=11,[]
    dim,car_mag=calcul(dim,car_mag)
    print
    raw_input("                     C'est fait ? Alors appuyez sur ENTREE")
    print
    print "                     N° de ligne                             N° de colonne"
    affiche_coordonnees(dim,car_mag)
    print "                 C'était juste ? Non ? Relisez encore les explications..."
    presse()
    voici()
    affichage(dim,n1,n2,car_mag)
    return
               
def affiche_methode_coordonnees(dim):
    print
    print "          Pour trouver les n°s de ligne :"
    print "Partir de 1."
    print "- Horizontalement, chaque n° de ligne se déduit du précédent en lui soustrayant 1."
    print "  Mais vous devrez ajouter n, dès le 0 atteint, puis reprendre les additions."
    print "- Verticalement, chaque n° se déduit du précédent en lui ajoutant 2."
    print "  Mais vous devrez soustraire n, dès que le n° de ligne dépassera cette valeur."
    print "  puis reprendre les additions."
    print
    print "          Pour trouver les n°s de colonne :"
    print "Partir de (n+3)/2 si la dimension n n'est pas multiple de 3, de (n+1)/2 sinon."
    print "Ici : ("+str(dim)+"+3)/2 =",(dim+3)/2,"."
    print "- Horizontalement, chaque n° de colonne se déduit du précédent en lui ôtant 1."
    print "  Mais vous devrez ajouter n, dès que le n° de colonne dès le 0 atteint"
    print "  puis reprendre les additions."
    print "- Verticalement, chaque n° se déduit du précédent en lui ajoutant 3."
    print "  Mais vous devrez soustraire n dès que le n° de ligne dépassera cette valeur,"
    print "  puis reprendre les additions."
    print
    print "Ainsi, dans la case de coordonnées ("+str(dim-2)+" ; " +str((dim+1)/2)+") se trouvera le nombre de"
    print "coordonnées",
    return        
   
def affiche_coordonnees(dim,car_mag):
    print
    for j in range(dim):
        print "           ",
        for i in range(dim):
            nc=car_mag[j][i]
            l=1+(nc-1)/dim
            if dim>9:
                print "%2i" % l,
            else:
                print l,
        print "           ",        
        for i in range(dim):
            nc=car_mag[j][i]
            c=1+(nc-1)%dim
            if dim>9:
                print "%2i" % c,
            else:
                print c,
        print
    print
    return
     
# Gestion des choix
mode,pres=10,0
while mode!=0:
    pres+=1
    titre_general()
    if pres==1:
        presentation()
    car_mag=[]
    mode=menu(mode)
    if mode==1:
        gere_carres()
        mode=10
    elif mode==2:
        dim=choix_dimension(5)
        car_mag=[]
        dim,car_mag=calcul(dim,car_mag)
        methode_car_simple(dim,car_mag)
        mode=10
    elif mode==3:
        titre_general()
        calcul_solo()
        mode=10
    elif mode==4:
        demo3x5()
        mode=10
    elif mode==5:
        solo5x3()
        mode=10
    if mode > 0:
        retour()    
print
print "                       Au revoir !"

Si vous décidiez d'exécuter ce grogramme dans une fenêtre DOS remplacer la 2e ligne :
# -*- coding: Latin-1 -*-
par celle-ci :
# -*- coding: cp437 -*-
afin de profiter des caractères accentués.

Réactions, Commentaires bienvenus...

@+


Arx Tarpeia Capitoli proxima...

Hors ligne

#2 18-03-2009 07:09:06

yoshi
Modo Ferox
Inscription : 20-11-2005
Messages : 11 421

Re : [Python] Construction de carrés magiques impairs, simples ou gigognes.

Bonjour à tous,

J'ai modifié la méthode de stockage et le nommage du fichier : il a donc quelques modifs un peu partout...
Désolé.
J'ai encore aussi purgé le code de différentes "déclarations" inutiles, mais ça ce sont des broutilles...

Enjoy !

@+


Arx Tarpeia Capitoli proxima...

Hors ligne

#3 21-03-2009 17:58:30

yoshi
Modo Ferox
Inscription : 20-11-2005
Messages : 11 421

Re : [Python] Construction de carrés magiques impairs, simples ou gigognes.

Bonsoir,

Encore une retouche mineure, pour rendre les messages affichés, en cas d'appel au module de stockage, plus aérés...
Voici le code retouché :

def affichage(dim,n1,n2,car_mag):
    if dim<33:
        print
        for j in range(dim):
            for i in range(dim):
                if dim<10:
                    print "%2i" % car_mag[j][i],
                else:
                    print "%3i" % car_mag[j][i],
            print
    else:
        print
        print "        ... Dimension trop grande pour l'affichage : écriture dans un fichier ..."
        stockage(dim,n1,n2,car_mag)
    return

def stockage(dim,n1,n2,car_mag):
    rep = getcwd()
    if n2>1:
        nom = "Impairs_G" + str(n1)+"x"+str(n2)+".txt"
    else:
        nom = "Impairs_S" + str(dim)+".txt"
    chemin_nom=rep+chr(92)+nom
    fichier = open(nom,'w')
    lgmax = 1 + len(str(dim**2))
    blanc = "             "
    for j in range(dim):
        enreg=""
        for i in range(dim):
            nb = str(car_mag[j][i])
            lg = len(nb)
            enreg += blanc[0:lgmax-lg]+nb            
        fichier.write(enreg+"\n")
    fichier.close()
    print
    print "      Vous trouverez votre fichier ici",chemin_nom
    return

Et je mets en ligne un utilitaire de découpe des carrés en vue de l'impression si dimension > 31...

@+


Arx Tarpeia Capitoli proxima...

Hors ligne

Réponse rapide

Veuillez composer votre message et l'envoyer
Nom (obligatoire)

E-mail (obligatoire)

Message (obligatoire)

Programme anti-spam : Afin de lutter contre le spam, nous vous demandons de bien vouloir répondre à la question suivante. Après inscription sur le site, vous n'aurez plus à répondre à ces questions.

Quel est le résultat de l'opération suivante ?47 - 47
Système anti-bot

Faites glisser le curseur de gauche à droite pour activer le bouton de confirmation.

Attention : Vous devez activer Javascript dans votre navigateur pour utiliser le système anti-bot.

Pied de page des forums