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 Fonction une_étape Paramètres d’entrée : le tableau tab . 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.. . 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 .Exemple 3 4 3 4 4 5 1 6 2 3 1 1 2 1 2 3 1 2 .. 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.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.. Définir deux indices intermédiaires ni.nj Calculer la nouvelle position ni...

c /* Calcul une etape du carre en calculant les nouvelles coordonnées */ 3/7 . i<n. } /* Affichage en mode texte du tableau */ void afftab(char tab[][DIM].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. for (i=0.yd ."%d". for (i=0.j. int k) { char bidon[256].&i. printf("\n").j. puts("Taper CR pour continuer"). int xd. } /* Affichage en mode graphique du tableau */ void affgraph(PFENETRE f1. xd. Chaine ( f1. int yd.h" /* Initialisation du tableau tab*/ void inittab(char tab[][DIM].n. j<n. } printf("\n"). tab[i][j]). j<n.c #include "mesfonctions. int n){ int i. Affichage du tableau(t. i++) for (j=0.k). j++) printf ("%d ". } Fichier calcul et verification : f2. int n){ int i. tab[n/2+1][n/2]=1.n) Pour etape variant de 1 à n faire Calculer les nouvelles coordonnées (une_etape(t. /* Conversion entier  chaine de caracteres */ sprintf(bidon. getchar().n) i=n/2+1. i<n. j++) tab[i][j]=0. i++) { for (j=0. bidon). j=n/2.&j)) Mettre k dans le tableau (tab[i][j]=k) Afficher le tableau Finpour Programme C : Fichier entrées/sortie : f1.

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

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

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

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

Sign up to vote on this title
UsefulNot useful