Académique Documents
Professionnel Documents
Culture Documents
2006-2007
TD n 7
Buts Dure : Tableau 2D, lecture dans un fichier : 1 semaine
Dans leur explication du monde, les chinois racontent qu'une tortue marine aborda un jour la terre avec un carr magique d'ordre 3 sur la carapace. Un carr d'ordre n est un tableau d'entiers dont les 2 dimensions sont gales n. Un carr (d'ordre n) est magique quand : [1] Tous les nombres entiers de 1 n*n sont utiliss une seule fois. [2] Ces nombres sont disposs de telle sorte que les sommes de chaque ligne, de chaque colonne, de chaque diagonale soient toutes gales. Plusieurs algorithmes permettent de construire des carrs magiques pourvu que l'ordre donn n soit impair. Voici l'un d'entre eux : [1] On commence par crer un carr d'ordre n vide. [2] Le nombre 1 est plac ensuite dans la case juste au-dessous du centre. [3] Aussitt qu'un dplacement dcrit par la suite oblige sortir du carr en traversant l'un des bords, on se place alors dans la case correspondante du bord oppos et on continue effectuer la suite des dplacements dcrits. [4] Une fois qu'une case a t remplie, on en choisit une autre en effectuant, par rapport la case qui vient d'tre remplie prcdemment, deux mouvements successifs: - l'un horizontal, d'une case vers la droite. - l'autre vertical d'une case vers le bas. Deux cas peuvent se prsenter: - La case atteinte est vide, on y place alors le nombre suivant. - La case atteinte est dj remplie, on en choisit alors une autre en effectuant deux dplacements verticaux successifs vers le bas partir de la case prcdemment remplie (Tant que le carr n'est pas compltement rempli, cette case est ncessairement nulle).
Exemple
3 4 3 4 4 5 1 6 2 3
1 2
1 2 3
1 2
...... .
Positionnement du 1
Positionnement du 2
Positionnement du 3
Positionnement du 4
Positionnement du 6
Dfinir deux indices de boucle i et j Pour i variant de 0 n-1 faire Pour j variant de 0 n-1 faire Mettre 0 dans llment i,j tab[i][j] Finpour Finpour Mettre 1 dans llment en dessous de la case du centre tab[n/2+1][n/2] Fonction daffichage
Paramtres dentre : le tableau tab et la taille n Paramtres de sortie : aucun Paramtres dentre/sortie : aucun Valeur de retour : aucune Rle : affichage du contenu du tableau
Dfinir deux indices de boucle i et j Pour i variant de 0 n-1 faire Pour j variant de 0 n-1 faire Afficher lcran llment i,j tab[i][j] Finpour Finpour Fonction une_tape
Paramtres dentre : le tableau tab , la taille n Paramtres de sortie : Paramtres dentre/sortie : les coordonnes i et j de lancienne position et de la nouvelle position Valeur de retour : aucune Rle : trouver les nouvelles coordonnes du nombre placer.
Dfinir deux indices intermdiaires ni,nj Calculer la nouvelle position ni, nj partir de i et j (ni=(i+1) modulo n et nj=(j+1)modulo n) Si cette case (tab[ni][nj] est vide) Alors changer les valeurs de i et j en ni et nj
2/7
Initialiser (t,n) i=n/2+1; j=n/2; Affichage du tableau(t,n) Pour etape variant de 1 n faire Calculer les nouvelles coordonnes (une_etape(t,n,&i,&j)) Mettre k dans le tableau (tab[i][j]=k) Afficher le tableau Finpour Programme C : Fichier entres/sortie : f1.c
#include "mesfonctions.h" /* Initialisation du tableau tab*/ void inittab(char tab[][DIM], int n){ int i,j; for (i=0; i<n; i++) for (j=0; j<n; j++) tab[i][j]=0; tab[n/2+1][n/2]=1; } /* Affichage en mode texte du tableau */ void afftab(char tab[][DIM], int n){ int i,j; for (i=0; i<n; i++) { for (j=0; j<n; j++) printf ("%d ", tab[i][j]); printf("\n"); } printf("\n"); } /* Affichage en mode graphique du tableau */ void affgraph(PFENETRE f1, int xd, int yd, int k) { char bidon[256]; /* Conversion entier chaine de caracteres */ sprintf(bidon,"%d",k); Chaine ( f1, xd,yd , bidon); puts("Taper CR pour continuer"); getchar(); }
void une_etape(char tab[][DIM], int n, int *ai, int *aj){ ni=(*ai+1)%n; nj=(*aj+1)%n; if (tab[ni][nj]) /* Case deja occupee */ *ai = (*ai +2)%n; else { *ai= ni; *aj=nj; } }
int ni,nj;
/* Verifie si le tableau est bien un carre magique Calcul de la somme de la premiere ligne Verification des sommes des lignes et colonnes, de la diagonale Et de lantidiagonale */ int verification(char tab[][DIM], int n) { int i,j,s0,s; /* Somme de la premiere ligne */ for (s0=i=0; i<n; i++) s0+=tab[0][i]; /* Somme des lignes */ for (i=0; i<n; i++) { for (s=j=0; j<n; j++) s +=tab[i][j]; if (s !=s0) return(0); } /* Somme des colonnes */ for (i=0; i<n; i++) { for (s=j=0; j<n; j++) s +=tab[j][i]; if (s !=s0) return(0); } /* Somme de la diagonale */ for (s=i=0; i<n; i++) s +=tab[i][i]; if (s !=s0) return(0); /* Somme de l'antidiagonale */ for (s=i=0; i<n; i++) s +=tab[i][n-1-i]; if (s !=s0) return(0); /* Ici, c'est un carre magique */ return 1; }
4/7
/* pour laffichage graphique uniquement */ int diml,dimc; PFENETRE f1; puts("Entrer la taille du carr"); scanf("%d", &n); if ( !(n%2) || n<1 || n > DIM) { printf("Erreur : n impair compris entre 3 et %d\n",DIM); exit (1); } /* Initialisation de laffichage graphique */ f1 = newfenetregraphique(diml=25*n,dimc=25*n); Grille(f1,n,n,diml/n-2,dimc/n-2,1,1); inittab(tab,n); i=n/2+1; j=n/2; affgraph(f1,(j+.2)*(dimc/n-2),(i+.9)*(diml/n-2),1 ); /* Traitement principal : place en i,j le nombre etape et affiche a chaque iteration le tableau en mode texte ET en mode graphique */ for (etape=2; etape<=n*n; etape++) { une_etape(tab,n,&i,&j); tab[i][j]=etape; affgraph(f1,(j+.2)*(dimc/n-2),(i+.9)*(diml/n-2),etape ); afftab(tab,n); } if (verification( tab,n)) printf("C'est un carre magique\n"); else printf("Ce n'est pas un carre magique\n"); }
Fichier Makefile
p : f1.o f2.o p.o TAB gcc o p p.o f1.o L/usr/X11R6/lib -lX11 -lpthread f2.o -L/users/prog1a/C/librairie -lERG -
f1.o : f1.c TAB gcc c f1.c -I/users/prog1a/C/librairie f2.o : f2.c TAB gcc c f2.c -I/users/prog1a/C/librairie p.o : p.c TAB gcc c p.c -I/users/prog1a/C/librairie Attention : TAB signifie quil faut utiliser la touche Tabulation (|), et non taper les caractres T A B
5/7
Dans notre cas, l'univers sera fini et limit la taille de votre cran. Vous considrerez cependant que l'univers est rond, c'est dire que la colonne d'indice 0 a pour voisines la colonne 1 ET la colonne la plus droite, que la ligne la plus haute (indice 0) a pour voisines la ligne 1 ET la ligne la plus basse (et rciproquement). Ceci peut tre facilement ralis grce la fonction modulo (%). Vous aurez, au minimum besoin des fonctions suivantes : void initialisation(char tab[][DIM], int nb) : initialise le tableau utilisant nb lignes x nb colonnes void nouvellegeneration(char ancienne[][DIM], char nouvelle[][DIM], int nb) : calcul la nouvelle gnration partir de lancienne. Cette fonction aura besoin de la fonction suivante :
6/7
int nbvoisin(char tab[][DIM], int i, int j, int nb) : calcule le nombre de voisins vivants du point de coordonnes i et j dans le tableau tab. Noubliez pas de calculer les coordonnes des voisins laide du modulo. Attention, loperateur modulo du C peut retourner une valeur ngative si le dividende est ngatif. Utilisez donc (i-1+nb)%nb par exemple pour trouver la ligne prcdente, expression qui sera toujours comprise en 0 et nb-1. void affichegeneration(char tab[][DIM], int nb) : affiche dune gnration
Travail facultatif Vous pourrez aussi tester si votre configuration initiale conduit une population stable (i.e. une population qui n'volue plus) ou plus difficile, une population qui boucle sur elle-mme au bout de X gnrations. Raliser la lecture de la gnration initiale dans un fichier sur disque. Le nom du fichier contenant la gnration initiale sera pass en argument de la ligne de commande. Voici le code permettant un affichage graphique dune gnration
#include "ERGgraphics.h" #define DIM 100 #define TAILLE 5 /* Taille d'une case du tableau */
void Affichejeudevie(PFENETRE f1,char tab[][DIM], int nb, int taille) { int i,j; Grille(f1,nb,nb,3*taille+1,3*taille+1,0,0); for (i=0; i<nb; i++) for (j=0; j<nb; j++) CerclePleinCouleur(f1,j*(3*taille+1)+3*taille/2, i*(3*taille+1)+3*taille/2,taille, tab[i][j]?WHITE(f1):BLUE(f1)); } /* Generation aleatoire des cellules */ void inittab(char tab[][DIM], int nb) { int i,j; for (i=0; i<nb; i++) for (j=0; j<nb; j++) tab[i][j] = rand() % 2; } main (int ac, char **av) { int n; char tab1[DIM][DIM]; char tab2[DIM][DIM]; PFENETRE f1; /* On utilise que les n x n elements du tableau tab */ puts("Entrer la taille du carr"); scanf("%d", &n); inittab(tab1,n); /* Initialisation de l'affichage graphique */ f1 = newfenetregraphique(n*(3*TAILLE+1), n*(3*TAILLE+1)); do { Affichejeudevie(f1,tab1,n,TAILLE); /* Affichage dune gnration */ nouvellegeneration(tab1,tab2,n) ; /* A FAIRE */ memcpy(tab1,tab2,DIM*DIM*sizeof(char)) ; /* recopie la nouvelle gnration dans lancienne pour recommencer */ } while (getchar() !=q); /* Attente */ }
7/7