TD de programmation structurée : 1ère année

2006-2007

TD n° 7
Buts Durée : Tableau 2D, lecture dans un fichier : 1 semaine

Exemple : Carré magique
Enoncé :
4 3 8 9 5 1 2 7 6

Exemple d'un carré magique d'ordre 3

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 utilisés une seule fois. [2] Ces nombres sont disposés de telle sorte que les sommes de chaque ligne, de chaque colonne, de chaque diagonale soient toutes égales. Plusieurs algorithmes permettent de construire des carrés magiques pourvu que l'ordre donné n soit impair. Voici l'un d'entre eux : [1] On commence par créer un carré d'ordre n vide. [2] Le nombre 1 est placé ensuite dans la case juste au-dessous du centre. [3] Aussitôt qu'un déplacement décrit 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 déplacements décrits. [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 précédemment, 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 présenter: - La case atteinte est vide, on y place alors le nombre suivant. - La case atteinte est déjà remplie, on en choisit alors une autre en effectuant deux déplacements verticaux successifs vers le bas à partir de la case précédemment remplie (Tant que le carré n'est pas complètement rempli, cette case est nécessairement nulle).

j tab[i][j] Finpour Finpour Mettre 1 dans l’élément en dessous de la case du centre tab[n/2+1][n/2] Fonction d’affichage Paramètres d’entrée : le tableau tab et la taille n Paramètres de sortie : aucun Paramètres d’entrée/sortie : aucun Valeur de retour : aucune Rôle : affichage du contenu du tableau Définir deux indices de boucle i et j Pour i variant de 0 à n-1 faire Pour j variant de 0 à n-1 faire Afficher à l’écran l’élément i. la taille n Paramètres de sortie : Paramètres d’entrée/sortie : les coordonnées i et j de l’ancienne position et de la nouvelle position Valeur de retour : aucune Rôle : trouver les nouvelles coordonnées du nombre à placer. . Définir deux indices intermédiaires ni.Exemple 3 4 3 4 4 5 1 6 2 3 1 1 2 1 2 3 1 2 ....j tab[i][j] Finpour Finpour Fonction une_étape Paramètres d’entrée : le tableau tab . 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 . Positionnement du 1 Exemple d'un carré magique d'ordre 5 Positionnement du 2 Positionnement du 3 Positionnement du 4 Positionnement du 6 Algorithme Fonction d’initialisation Paramètres d’entrée la taille n Paramètres de sortie : aucun Paramètres d’entrée/sortie : : le tableau tab à deux dimension Valeur de retour : aucune Rôle : lecture des données Définir 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 l’élément i..nj Calculer la nouvelle position ni..

} printf("\n"). } /* Affichage en mode graphique du tableau */ void affgraph(PFENETRE f1. j=n/2. j<n. i<n. int k) { char bidon[256].Sinon changer i en (i+2) modulo n Finsi Fonction principale Définir la taille maximale du carré (constante DIM) Définir la taille du carré (variable n) Définir un tableau 2D t pouvant contenir le nombre maximal d’éléments (constante DIM) Définir une variable etape contenant le numero a positionner Définir deux variables i et j indiquant les coordonnées de la case à remplir Initialiser (t. bidon).n. i<n. Chaine ( f1.j. int xd.&i.c #include "mesfonctions. tab[i][j]). xd. getchar(). Affichage du tableau(t.j. } /* Affichage en mode texte du tableau */ void afftab(char tab[][DIM].k).n) Pour etape variant de 1 à n faire Calculer les nouvelles coordonnées (une_etape(t.n) i=n/2+1. j<n. for (i=0. tab[n/2+1][n/2]=1. j++) tab[i][j]=0. /* Conversion entier  chaine de caracteres */ sprintf(bidon.h" /* Initialisation du tableau tab*/ void inittab(char tab[][DIM]. int n){ int i. int yd. puts("Taper CR pour continuer").c /* Calcul une etape du carre en calculant les nouvelles coordonnées */ 3/7 . } Fichier calcul et verification : f2. i++) { for (j=0."%d". printf("\n"). int n){ int i. i++) for (j=0.yd . for (i=0.&j)) Mettre k dans le tableau (tab[i][j]=k) Afficher le tableau Finpour Programme C : Fichier entrées/sortie : f1. j++) printf ("%d ".

4/7 . void affgraph(PFENETRE f1. i++) s +=tab[i][i]. int n) .void une_etape(char tab[][DIM]. char **av) char tab[DIM][DIM]. i<n.j. } } int ni. j<n. c'est un carre magique */ return 1.c #include "mesfonctions. int n) . int xd. } /* Somme des colonnes */ for (i=0. /* Verifie si le tableau est bien un carre magique Calcul de la somme de la premiere ligne Verification des sommes des lignes et colonnes. i++) { for (s=j=0. j<n. i++) { for (s=j=0. { int etape. int n. i<n. void inittab(char tab[][DIM]. Fichier principal : p. if (tab[ni][nj]) /* Case deja occupee */ *ai = (*ai +2)%n. else { *ai= ni. int n) . if (s !=s0) return(0). i<n. j++) s +=tab[j][i]. /* Ici. int k) . int *ai. if (s !=s0) return(0). i<n. i<n.j.s. int yd. j++) s +=tab[i][j]. *aj=nj. void afftab(char tab[][DIM]. de la diagonale Et de l’antidiagonale */ int verification(char tab[][DIM]. i++) s +=tab[i][n-1-i]. i++) s0+=tab[0][i]. n. nj=(*aj+1)%n.h" main (int ac. /* Somme de l'antidiagonale */ for (s=i=0. if (s !=s0) return(0). void une_etape(char tab[][DIM]. int n. int n) { int i.s0.h" #define DIM 15 int verification(char tab[][DIM]. /* Somme de la premiere ligne */ for (s0=i=0. if (s !=s0) return(0).nj. int *ai. } /* Somme de la diagonale */ for (s=i=0. } Fichier d’entete : mesfonctions. int *aj) . int *aj){ ni=(*ai+1)%n.h> #include "ERGgraphics. /* Somme des lignes */ for (i=0.h #include <stdio. i.

o p. } Fichier Makefile p : f1.o TAB gcc –o p p. i=n/2+1.9)*(diml/n-2). scanf("%d".1.2)*(dimc/n-2). et non taper les caractères ’T’ ’A’ ’B’ 5/7 .o : f2. if ( !(n%2) || n<1 || n > DIM) { printf("Erreur : n impair compris entre 3 et %d\n". puts("Entrer la taille du carré").o : p.diml/n-2.o f1. affgraph(f1.1). afftab(tab. etape++) { une_etape(tab. &n). exit (1)./* pour l’affichage graphique uniquement */ int diml.n. else printf("Ce n'est pas un carre magique\n"). PFENETRE f1. Grille(f1. /* Traitement principal : place en i.1 ).o -L/users/prog1a/C/librairie -lERG - f1. affgraph(f1.c -I/users/prog1a/C/librairie Attention : TAB signifie qu’il faut utiliser la touche Tabulation (|).(j+.&j).(i+.&i.2)*(dimc/n-2).(j+.n. tab[i][j]=etape. } if (verification( tab.dimc/n-2.(i+.n)) printf("C'est un carre magique\n").o L/usr/X11R6/lib -lX11 -lpthread f2.n).dimc=25*n).o : f1.etape ).c TAB gcc –c p.c -I/users/prog1a/C/librairie p.c TAB gcc –c f2.dimc.n. j=n/2.c TAB gcc –c f1.9)*(diml/n-2).j le nombre etape et affiche a chaque iteration le tableau en mode texte ET en mode graphique */ for (etape=2. etape<=n*n. inittab(tab. } /* Initialisation de l’affichage graphique */ f1 = newfenetregraphique(diml=25*n.c -I/users/prog1a/C/librairie f2.o f2.n).DIM).

l'évolution de l'univers conduit plusieurs fois à la même configuration (boucle). l'univers sera fini et limité à la taille de votre écran. c'est à dire que la colonne d'indice 0 a pour voisines la colonne 1 ET la colonne la plus à droite. Chaque cellule est donc entourée de huit cases susceptibles de contenir d'autres cellules. Chaque cellule n'ayant qu'une ou aucune cellule adjacente meurt d'isolement. Il est bien entendu que cette question ne se pose que pour un univers infini : dans un univers fini (un tableau informatique classique). Ce jeu s'insère dans la théorie des automates cellulaires et de nombreux travaux de recherche existent dans ce domaine. qui met en œuvre des "cellules" susceptibles de se reproduire. Il est important de remarquer que toutes les naissances et toutes les morts ont lieu en même temps au cours d'une génération. * * * ** * ** ******* ******* ***** Génération 3 Génération 4 ******* * * * Dans notre cas. dit "Jeu de la Vie". int nb) : initialise le tableau utilisant nb lignes x nb colonnes • void nouvellegeneration(char ancienne[][DIM]. ou meurt par surpopulation.Exercice : Jeu de la vie Présentation du jeu: Le mathématicien Conway a imaginé un jeu. au minimum besoin des fonctions suivantes : • void initialisation(char tab[][DIM]. Ceci peut être facilement réalisé grâce à la fonction modulo (%).. que la ligne la plus haute (indice 0) a pour voisines la ligne 1 ET la ligne la plus basse (et réciproquement). Vous considérerez cependant que l'univers est rond. b) la mort : chaque cellule ayant quatre ou plus cellules adjacentes disparaît. Les règles sont les suivantes : a) la survie : chaque cellule ayant deux ou trois cellules adjacentes survit jusqu'à la génération suivante. int nb) : calcul la nouvelle génération à partir de l’ancienne. Ces cellules sont représentées par des éléments sur un damier de taille infinie : l'univers. char nouvelle[][DIM]. Exemple: * * ** ** * * * ** ** * * ** ** ** * ** * * ** * ** ** ** Génération 1Génération 2 Travail à réaliser ***** ******* ** * ** * * ** ** . c) la naissance : chaque emplacement ayant exactement trois cellules adjacentes fait naître une nouvelle cellule pour la génération suivante.. de disparaître ou de survivre lorsqu'elles obéissent à certaines règles. Vous aurez. Une des questions posée est de savoir si à partir d'une configuration donnée. Cette fonction aura besoin de la fonction suivante : 6/7 . appelées "génétiques". le nombre de configuration est limité.

Utilisez donc (i-1+nb)%nb par exemple pour trouver la ligne précédente. j<nb. i*(3*taille+1)+3*taille/2. Grille(f1. j<nb. /* A FAIRE */ memcpy(tab1. • Réaliser la lecture de la génération initiale dans un fichier sur disque. int nb) : affiche d’une génération Travail facultatif • Vous pourrez aussi tester si votre configuration initiale conduit à une population stable (i. Le nom du fichier contenant la génération initiale sera passé en argument de la ligne de commande. char **av) { int n. PFENETRE f1. /* Attente */ } 7/7 .tab2. char tab1[DIM][DIM]. tab[i][j]?WHITE(f1):BLUE(f1)). int taille) { int i. char tab2[DIM][DIM].tab2.h" #define DIM 100 #define TAILLE 5 /* Taille d'une case du tableau */ void Affichejeudevie(PFENETRE f1. int i.j. void affichegeneration(char tab[][DIM].0).nb. expression qui sera toujours comprise en 0 et nb-1. n*(3*TAILLE+1)). scanf("%d".DIM*DIM*sizeof(char)) .j. une population qui n'évolue plus) ou plus difficile. /* Affichage d’une génération */ nouvellegeneration(tab1. int j.• • int nbvoisin(char tab[][DIM]. do { Affichejeudevie(f1.tab1. Voici le code permettant un affichage graphique d’une génération #include "ERGgraphics. i++) for (j=0. à une population qui boucle sur elle-même au bout de X générations. } main (int ac. for (i=0.taille. i++) for (j=0.n) . i<nb. } /* Generation aleatoire des cellules */ void inittab(char tab[][DIM].TAILLE).n). &n).3*taille+1.0. /* recopie la nouvelle génération dans l’ancienne pour recommencer */ } while (getchar() !=’q’). j++) CerclePleinCouleur(f1.nb.e.n. int nb. j++) tab[i][j] = rand() % 2. Attention. l’operateur modulo du C peut retourner une valeur négative si le dividende est négatif. int nb) { int i.j*(3*taille+1)+3*taille/2.char tab[][DIM].3*taille+1. /* On utilise que les n x n elements du tableau tab */ puts("Entrer la taille du carré"). for (i=0. i<nb. inittab(tab1. /* Initialisation de l'affichage graphique */ f1 = newfenetregraphique(n*(3*TAILLE+1). int nb) : calcule le nombre de voisins vivants du point de coordonnées i et j dans le tableau tab. N’oubliez pas de calculer les coordonnées des voisins à l’aide du modulo.

Sign up to vote on this title
UsefulNot useful