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 06-03-2009 20:45:28

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

[Python] Construction de carrés magiques de dimension n=2(2k+1)

Bonsoir,

Voilà revu et corrigé un programme de constructions de carrés magiques de dimension "impairement paire" n = 2(2k+1) avec [tex]k\in \mathbb{N}^*[/tex].
Ainsi que vous le verrez sur la page http://www.bibmath.net/carres/index.php … =impapairs où tout est expliqué pour la construction "à la main", à partir d'un carré déjà rempli, on applique 3 symétries : 2 axiales par rapport à l'horizontale et la verticale et la symétrie centrale.
Toute la difficulté a été
1. D'informatiser ces symétries
2. Et surtout de repérer mathématiquement (puis traduire en Python) l'appartenance d'un nombre à une forme, laquelle forme conditionne son déplacement...

Voilà, essayez-le, regardez la répartition des nombre dont la somme est n^2+1, la répartition pairs/impairs...

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

# Pour un fonctionnement en mode console (DOS), remplacer # -*- coding: Latin-1 -*-
# par # -*-coding:cp437-*-

from os import getcwd

def titre_general():
    print
    print
    print "               *********************************************"
    print "               *   CARRES DE DIMENSIONS IMPAIREMENT PAIRE  *"
    print "               *         Modèle du Carré du Soleil         *"
    print "               *********************************************"
    print
    print
    print  
   
def initialisation_carres(car_init,car_mag,n):
    L1,L2=[],[]
    for j in range(n):
        for i in range(n):
            L1.append(0)
            L2.append(0)
        car_init.append(L1)
        car_mag.append(L2)
        L1,L2=[],[]
    return car_init,car_mag

def choix_dimension(n):
    while 1:
        try:
            n = int(raw_input("Veuillez choisir la dimension du carré : "))
            if n % 2 == 0 and n % 4 != 0:
                if (n/2) % 2 == 1:
                    break
            print "Désolé ! Vous n'avez pas entré un nombre valide. Veuillez recommencer..."
        except ValueError:
            print "Désolé ! Ce n'est pas un nombre. Essayez encore..."
    return n

# Procédure centrale de calcul
def calcul(n,mode,car_init,car_mag):
    nn,tnb=n/2,0
    for no_qd in range(4):
        for l in range(nn):
            for c in range(nn):
                j = l + nn*(no_qd>1)
                i = c + nn*(no_qd % 2)
                if mode == 1:
                    tnb=normal(i,j,n,nn,tnb)
                elif mode == 2:
                    tnb=normal_quadr(c,l,no_qd,nn,tnb)
                elif mode == 3:
                    tnb=ip_puis_pa(i,j,n,nn,tnb)
                elif mode == 4:
                    tnb=ip_pa_1li(i,j,n,nn,tnb)
                elif mode == 5:
                    tnb=normal_1s2(i,j,n,nn,tnb)
                elif mode == 6:
                    tnb=pairs_impairs_en_colonnes_sym(i,j,n,nn,tnb)
                else:
                    tnb=normal_1s2_avec_symetrie_centrale_par_paires(i,j,n,nn,tnb)                    
                car_init[j][i] = tnb
                if i == j or i+j == n-1:   # Les diagonales restent en place
                    car_mag[j][i] = tnb
                else:           # initialisation du drapeau d'appartenance à une forme
                    tem = (i == nn-1 or i == nn) and (j == 0 or j == n-1)
                    tem = tem + ((j == nn-1 or j == nn) and (i == 0 or  i == n-1))
                    tem = tem + (i == j - 1 or i + j == n-2 or i+j == n or i == j+1)
                    if no_qd== 0:
                        quadr1(c,l,i,j,n,nn,car_mag,tnb,tem)
                    elif no_qd == 1:
                        quadr2(c,l,i,j,n,nn,car_mag,tnb,tem)
                    elif no_qd == 2:
                        quadr3(c,l,i,j,n,nn,car_mag,tnb,tem)
                    else:
                        quadr4(c,l,i,j,n,nn,car_mag,tnb,tem)
    return car_init,car_mag

def affichage_stockage(car_init,car_mag,mode,n):
    print
    if n > 34:
        print
        print "Dimension trop grande : création d'un fichier"
        ecriture_dans_fichier(car_mag,mode,n)            
    else:
        affichage(car_mag,car_init,n)
        print
    print
    teste_magie(car_mag,n)
    return

# Pour voir le carré initial, remplacer après le print car_mag par car_init
def affichage(car_mag,car_init,n):
    print
    print "#############################################"
    print "           Carré d'ordre ",n
    print "#############################################"
    print
    for j in range(n):
        for i in range(n):
           if n == 6:
               print "%2i" % car_mag[j][i],
           elif n < 34:
               print "%3i" % car_mag[j][i],
        print
        if n > 10:
            print        

def ecriture_dans_fichier(car_mag,mode,n):
    rep = getcwd()
    nom = "Impapairs_" + str(n)+".txt"      
    chemin_nom=rep+chr(92)+nom
    fichier = open(nom,'w')
    lgmax = 1 + len(str(n**2))
    blanc ="                   "
    for j in range(n):
        enreg=""
        for i in range(n):
            nb = str(car_mag[j][i])
            lg = len(nb)
            enreg += blanc[0:lgmax-lg]+nb            
        fichier.write(chaine+"\n")
    fichier.close()
    print "Vous trouverez votre fichier ici",chemin_nom
    return
           
def teste_magie(car_mag,n):
    print "Test des lignes"
    for j in range(n):
        tot = 0
        for i in range(n):
            tot = tot + car_mag[j][i]
        print tot,
    print
    print
    print "Test des colonnes"
    for i in range(n):
        tot=0
        for j in range(n):
            tot = tot + car_mag[j][i]
        print tot,
    print
    print
    print "Test des diagonales"
    tot1 = 0
    tot2 = 0
    for j in range(n):
        i = j
        tot1 = tot1 + car_mag[j][i]
        tot2 = tot2 + car_mag[j][i]
    print tot1,tot2
    print

# Application des symétries dans chaque quadrant
def quadr1(c,l,i,j,n,nn,car_mag,tnb,tem):
    if ((c - l) > n/4.0 and c > l) or ((l - c)< n/4.0 and c < l):
        car_mag[j][n-1-i] = tnb
    else:
        car_mag[n-j-1][i]= tnb
    return car_mag

def quadr2(c,l,i,j,n,nn,car_mag,tnb,tem):
    if (c + l < nn-1 and c + l > n/4.0-1)or c + l > 3*n/4.0-1:
        car_mag[n - j-1][i] = tnb
    elif tem == 0 and (c + l < n/4.0-1 or (c + l > nn-1 and c + l< 3*n/4.0-1)):
        car_mag[j][n-i-1] = tnb
    else:
        car_mag[n-j-1][n-i-1] = tnb
    return car_mag

def quadr3(c,l,i,j,n,nn,car_mag,tnb,tem):
    if (c + l> n/4.0 -1 and c + l < nn-1) or c + l> 3*n/4.0-1:
        car_mag[j][n-i-1] = tnb
    elif tem == 0 and (c + l < n/4.0-1 or (c + l >nn-1 and c + l < 3*n/4.0-1)):
        car_mag[n -j- 1][i] = tnb
    else:
        car_mag[n-j-1][n-i-1] = tnb
    return car_mag

def quadr4(c,l,i,j,n,nn,car_mag,tnb,tem):
    if tem == 1:
        car_mag[n-j-1][n-i-1] = tnb
    elif (c<l and l-c > n/4.0) or (c > l and c-l < n/4.0):
        car_mag[j][n-i-1] = tnb
    else:
        car_mag[n-j-1][i]= tnb
    return car_mag

# Méthodes de calcul (dans l'ordre)
def normal(i,j,n,nn,tnb):
    tnb = n*j + i + 1
    return tnb

def normal_quadr(c,l,no_qd,nn,tnb):
    tnb = nn**2*no_qd + nn*l + c + 1
    return tnb

def ip_puis_pa(i,j,n,nn,tnb):
    tnb = (2*i+1+j*2*n)*(j<nn)+(j>=nn)*(2+2*i+(j-nn)*2*n)
    return tnb

def ip_pa_1li(i,j,n,nn,tnb):
    if j %2 == 0:
        tnb = 2 * i+ 1 + 2*n*(j/2)*(j>0)
    else:
        tnb = 2*(i+1)+ 2*n*(j/2)
    return tnb

def normal_1s2(i,j,n,nn,tnb):
    tnb = 1+i/2+2*nn**2*(i%2)+nn*j          
    return tnb

def pairs_impairs_en_colonnes_sym(i,j,n,nn,tnb):
    if i == 0 or i == n-1:
        tnb=normal(i,j,n,nn,tnb)
    else:
        dp = (((i+1 - 2*(i>nn-1))/2)% 2 == 1)
        if dp == 1:
            tnb = n*j + n - i
        else:
            tnb=normal(i,j,n,nn,tnb)
    return tnb

def normal_1s2_avec_symetrie_centrale_par_paires(i,j,n,nn,tnb):
    tnb=i/2+1+nn**2*(i%2==1)+nn*j+nn**2*(j>nn-1)
    return tnb

mode=10
while mode!= 0:
    try:
        titre_general()
        print
        print " 1. Dans l'ordre normal par ligne du carré"
        print " 2. Dans l'ordre normal par ligne de quadrant"
        print " 3. Tous les nombres impairs, puis les pairs"
        print " 4. Avec lignes de nombres impairs et pairs alternées"
        print " 5. Ordre normal en sautant une case à chaque fois dans le carré"
        print " 6. Par 2 colonnes à la fois avec symétrie dans chaque quadrant"
        print " 7. Ordre normal en sautant une case et par paires symétriques de somme n²"
        print "                   0. Sortie du programme"
        print
        mode = int(raw_input("     Votre choix : "))
        if mode > 7:
            print "Désolé ! Vous n'avez pas entré un nombre valide. Veuillez recommencer..."
            print
            print
        elif mode >0:
            n=0
            n=choix_dimension(n)
            car_init,car_mag=[],[]
            car_init,car_mag=initialisation_carres(car_init,car_mag,n)
            car_init,car_mag=calcul(n,mode,car_init,car_mag)
            affichage_stockage(car_init,car_mag,mode,n)
            print
            raw_input('                ... Appuyer sur ENTREE ... ')
            print
    except ValueError:
        print "Désolé ! Ce n'est pas un nombre. Essayez encore..."
        print
print
print
print "                       Au revoir !"

Commentaires ?

@+


Arx Tarpeia Capitoli proxima...

Hors ligne

#2 06-03-2009 23:18:39

tibo
Membre actif
Inscription : 23-01-2008
Messages : 922

Re : [Python] Construction de carrés magiques de dimension n=2(2k+1)

J'en reste sans voix...

Meme en le poussant à la limite (carré de taille 10002), aprés 2h consécutives de calculs, et je pense le double d'affichage (c'est en cours là), j'obtiens un résultat.

Franchement BRAVO

(allez j'emet quand meme une critique, est-ce vraiment nécéssaire d'afficher les test de lignes, de colonne et de diagonales? que le programme test, oui. afficher le somme, oui. mais pas tout afficher)

bon maintenant je vais décortiquer ton code. Enfin ce week-end, parce que demain j'ai DS de math quand meme, il faudrait relire son cours un peu non?

Dernière modification par tibo (06-03-2009 23:19:18)


A quoi sert une hyperbole?
----- A boire de l'hypersoupe pardi !

Hors ligne

#3 07-03-2009 08:41:28

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

Re : [Python] Construction de carrés magiques de dimension n=2(2k+1)

Salut,


le test de magie peut s'enlever facilement ou devenir optionnel : je vais voir ça...
n=10002 ???  J'aurais jamais pensé que quelqu'un aille jusque là...
En principe, il n'y a pas d'affichage au delà de n = 34, mais stockage dans un fichier (dans le même dossier que le prog) séquentiel dont le nom te sera donné.
Pourquoi cela ? Pour permettre la récupération via un traitement de textes puis imprimer des morceaux sur une page A4 pour enfin les assembler : je l'avais fait avec une dimension autour de 100...
La taille estimée pour n= 10002 ? Environ 400 Mo !!!!

Je vais voir pour un fichier à accès direct...

Pour avoir une chance de comprendre le code, il faut bien lire la page de BibM@th où la méthode à la main est décrite...
A ma connaissance, personne n'avait pu, jusqu'à ce que je le fasse, sauter le pas de la dimension 6 à 10 et au-delà : des formes nouvelles apparaissent à partir de 10.  Depuis le temps que j'affirme cela, je n'ai jamais été démenti...
L'identification de ces formes nouvelles est due à l'un de mes amis ex-libraire et grand amateur de la magie des nombres : il a travaillé avec n = 10. Au delà, c'est un coup de chance et une intuition personnelle, un jour il y a près de 20 ans.

L'étape suivante, l'informatisation, a été longue et semée d'embûches.
Même avec une version de secours qui fonctionnait, sachant ce que j'avais imaginé, la modification du programme pour :
- qu'il fonctionne à partir de l'indice 0 et non plus 1, avec le passage d'une seule liste de n^2 nombres à une liste comprenant n listes de n nombres pour simuler les tableaux (n'existent pas en Python) du BASIC et d'autres langages,
- ne plus utiliser de variables déclarées globales
m'a demandé une dizaine d'heures...

Merci pour cette première réaction...

@+


Arx Tarpeia Capitoli proxima...

Hors ligne

#4 07-03-2009 14:59:27

tibo
Membre actif
Inscription : 23-01-2008
Messages : 922

Re : [Python] Construction de carrés magiques de dimension n=2(2k+1)

oups en effet c'est beaucoup 10002,
j'ai mis un 0 en trop
en fait c'est 1002, et vu le temps que ça m'a pris je ne tenterai pas plus
et bien pensé aussi cette histoire de ficher "annexe", par contre l'affichage est un peu bizar quand les nombres sont trop grands


A quoi sert une hyperbole?
----- A boire de l'hypersoupe pardi !

Hors ligne

#5 18-03-2009 08:21:59

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

Re : [Python] Construction de carrés magiques de dimension n=2(2k+1)

Bonjour,

Je pense, sans avoir essayé, savoir pourquoi tibo a déclaré que les nombres stockés étaient bizarres.
J'ai modifié la méthode de stockage et de nommage du fichier contenant les nombres du carré magique.
Je n'avais pas testé la méthode avant, mais recopié icelle directement de l'ancien programme de construction, et comme je ne gère plus maintenant une liste, mais une liste de listes, il devait y avoir effectivement quelques "bizarreries".

Dont acte...

S'il y a encore une bricole, me le faire savoir, merci

@+


Arx Tarpeia Capitoli proxima...

Hors ligne

#6 21-03-2009 18:29:34

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

Re : [Python] Construction de carrés magiques de dimension n=2(2k+1)

Bonsoir,

Encore une (toute) petite destinée à "standardiser" (pour traitement ultérieur --> utilitaire mis en ligne) les noms de carrés magiques enregistrés :
remplacer dans :

def ecriture_dans_fichier(car_mag,mode,n):

    nom = "Impapairs_" + str(n) par  nom = "Impapairs_"+str(n)+".txt"

@+


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.

Ecrire en lettres le nombre suivant : 2

Pied de page des forums