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 Calculer la nouvelle position ni..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 à 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... .

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

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

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

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

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

Sign up to vote on this title
UsefulNot useful