- Travaux pratiques TP1 : Recherche par dichotomie I. Introduction. L objectif de ce TP est de mettre en pratique des notions de base du langage C (entrées/sorties, structure de contrôle, fonctions, ). I.1. Principe de dichotomie. L application choisie met en œuvre le principe de dichotomie, qui permet de retrouver rapidement un dans un ensemble fini ordonné (défini par un intervalle, par exemple, ou encore par un tableau trié). L n est pas recherché séquentiellement, mais comparé à l médian (présent en milieu d intervalle). S ils sont identiques, la recherche est terminée. Si l cherché est inférieur à l médian, on recommence la recherche sur la première moitié de l intervalle. Sinon, on recommence sur la seconde moitié de l intervalle. Dans le premier exercice, c est l utilisateur qui procède (mentalement) par dichotomie pour deviner un nombre inconnu généré par l ordinateur. Dans le second exercice, les rôles sont inversés : c est l ordinateur qui doit deviner le nombre secret auquel pense l utilisateur. Le troisième exercice est un autre exemple d application de la dichotomie. I.2. Exemple. Imaginons que A fasse deviner à B le nombre secret 11 dans l intervalle [0,16]. La première proposition de B est l médian de [0,16], soit 8 : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 A indique à B que cette proposition est trop petite. B réduit donc son espace de recherche à la moitié supérieure de l intervalle ([9,16]), puis propose le nouvel médian, soit 12 (ou 13) : 9 10 11 12 13 14 15 16 A indique à B que cette proposition est trop grande. B réduit donc son espace de recherche à la moitié inférieure de l intervalle précédent ([9,11]), puis propose le nouvel médian, soit 10 : 9 10 11 A indique à B que cette proposition est trop petite. B réduit donc son espace de recherche à la moitié supérieure de l intervalle précédent, qui se réduit à {11}. B propose cet et trouve la solution : 11 II. Recherche d un nombre secret par l utilisateur. Le programme reproduit le jeu où l utilisateur doit deviner, en un nombre maximal d essais, un nombre secret généré aléatoirement par l ordinateur. II.1. Génération aléatoire du nombre secret. Dans un premier temps, le programme génère un nombre aléatoire compris dans un intervalle donné. 1
Un menu doit permettre de définir les bornes de cet intervalle selon 2 modes : 1. Par défaut : l intervalle est [0, 0x7FFF] 2. Personnalisé : l intervalle est donné par l utilisateur sous la forme de ses 2 bornes entières [min, max] Pour générer le nombre secret, on utilise les 2 fonctions suivantes de stdlib.h (cf. aide en ligne avec F1) : srand() : initialise le générateur de nombres aléatoires grâce à un «germe» (en anglais, seed). rand() : génère un nombre (pseudo-)aléatoire dans l intervalle [0, RAND_MAX]. II.2. Recherche du nombre secret Dans un second temps, l utilisateur recherche le nombre secret. Il saisit d abord le nombre maximal d essais qu il s autorise, puis : il propose un nombre à l ordinateur, le programme lui indique alors si ce nombre est inférieur, supérieur ou égal au nombre secret, le nombre d essais restants, et ce, jusqu à ce que le nombre secret soit trouvé ou que le nombre maximal d essais soit atteint. III. Recherche d un nombre secret par l ordinateur Écrire un programme permettant à l ordinateur de trouver, par dichotomie, un nombre secret compris entre 0 et 1000 : le programme demande à l utilisateur de penser à un nombre entier entre 0 et 1000. le programme propose un nombre et demande à l utilisateur si ce nombre est égal au nombre secret, plus grand, ou plus petit que celui-ci. si la proposition n est pas le nombre secret, le programme propose un nouveau nombre en fonction de la réponse de l utilisateur. si la proposition est correcte, le programme affiche le nombre de propositions qui a été nécessaire pour trouver cette solution. IV. Recherche de la racine cubique d un nombre entier Écrire un programme permettant à l ordinateur de trouver, par dichotomie, la racine cubique d un nombre entier N donné par l utilisateur et compris entre 0 et 1 000 000. Le programme doit d abord rechercher une racine cubique entière, c est-à-dire une solution entière dans l intervalle [0,100]. Si cette racine entière existe, le programme l affiche. Si elle n existe pas, il affiche que la racine est réelle et donne les deux entiers N 1 et N 2 qui la bornent. 2
TP2 : Problèmes de saisie I. Introduction. Le problème concerne l acquisition de données auprès d un utilisateur. Il s agit d associer à une question un domaine de réponses. Plusieurs aspects sont à considérer : comment effectuer une demande, comment obtenir une réponse de l utilisateur à cette demande, et comment valider cette réponse. II. Description du fonctionnement. II.1. Menu du questionnaire. Il s agit de réaliser un questionnaire qui se compose des rubriques accessibles par le menu suivant : 1. Saisie du nom 2. Saisie du code postal 3. Saisie de la ville 4. Saisie de la date de naissance 5. Affichage des caractéristiques de la personne 6. Fin Dès le lancement du programme, on affiche ce menu. Pour accéder à l une des rubriques, l utilisateur saisit le numéro correspondant. II.2. Réponses au questionnaire. Lorsque l utilisateur a saisi une réponse au questionnaire, le programme doit vérifier que cette réponse est valide. Si ce n est pas le cas, le programme émet un message d erreur et redemander une saisie. Réponses du type alphabétique. Les rubriques concernées sont le nom et la ville. Dans ces rubriques, le programme doit vérifier que chaque caractère de la réponse est bien une lettre. Le nom contiendra au maximum 40 caractères et la ville 60 caractères. Réponses du type numérique. Les rubriques concernées sont le code postal et la date de naissance. Pour le code postal, le programme doit vérifier que chaque caractère est bien un chiffre et que le nombre correspondant est compris entre 1000 et 97999. La date de naissance sera saisie sous la forme JJ, MM, AAAA. Chaque partie devra être numérique, et le jour devra être compris dans l intervalle [1,31], le mois dans [1,12] et l année dans [1800,2012]. II.3. Affichage des caractéristiques de la personne. Quand l utilisateur accède à cette rubrique, le programme doit afficher les caractéristiques saisies. Si l une des caractéristiques n a pas été saisie, le programme doit afficher le message «NON SAISI». 3
III. Élaboration du programme. III.1. Fonctions. Écrire un programme en langage C gérant les fonctions suivantes : menu : affiche le menu, demande un choix de rubrique et appelle la fonction appropriée. saisie_nom : saisit un nom valide (i.e. alphabétique), en vérifiant son format par appel à la fonction format_alphabetique. format_alphabetique : teste si la chaîne de caractères passée en paramètre est de taille correcte et ne contient que des lettres. Retourne un résultat booléen. saisie_codepostal : saisit un code postal valide, en vérifiant son format par appel à la fonction format_numerique et sa validité par appel à la fonction codepostal_valide. format_numerique : teste si la chaîne de caractères passée en paramètre ne contient que des chiffres. Retourne un résultat booléen. codepostal_valide : teste si la chaîne de caractères passée en paramètre représente un code postal valide. Retourne un résultat booléen. saisie_datenaiss : saisit une date de naissance valide, en vérifiant le format de chaque partie (jour, mois, année) par appel à la fonction format_numerique et la validité globale par appel à la fonction date_valide. date_valide : teste si les chaînes de caractères passées en paramètre (jour, mois, année) représentent une date valide. Retourne un code d erreur (0 : date valide, 1 : jour non valide, 2 : mois non valide, 3 : année non valide). affiche_caracteristiques : affiche à l écran les caractéristiques saisies. III.2. Conseils et contraintes de programmation. Pour les saisies, utiliser la fonction gets(), sauf pour celle de la date de naissance où scanf() est plus appropriée. Toutes les variables doivent être locales aux fonctions. Les variables stockant les caractéristiques de la personne doivent être transmises aux fonctions citées en III.1. Réalisez ce TP étape par étape, en écrivant et validant une rubrique à fois. Commencez par l initialisation des chaînes de caractères et par l affichage des caractéristiques de la personne. 4
TP3 : Jeu de la vie I. Introduction. Le jeu de la vie a été inventé par J.H. Conway et présenté dans le journal Scientific American en octobre 1970. Il s agit du plus connu des automates cellulaires, un modèle où chaque état conduit mécaniquement à l état suivant à partir de règles d évolution. II. Description du fonctionnement. II.1. Représentation. L univers du jeu est représenté par un damier, dont chaque case ne peut être occupée que par une seule cellule. Le jeu simule la vie des cellules du damier (naissance, survie et mort). II.2. Règles d évolution (cf. figure 1). La simulation repose sur quatre règles simples d évolution entre deux générations : une cellule continue à vivre si elle a deux ou trois cellules voisines vivantes ; une cellule meurt d isolement si elle a moins de deux voisines vivantes ; une cellule meurt d étouffement si elle a plus de trois voisines vivantes ; une cellule naît dans une case vide si trois cases voisines exactement sont occupées. Toutes les cellules du damier évoluent simultanément à chaque saut de génération. II.3. Objectif du TP. L objectif du TP est de manipuler des tableaux en langage C, en traduisant les règles ci-dessus pour suivre la vie des cellules. III. Élaboration du programme. III.1. Fonctions. Votre programme devra comporter plusieurs fonctions : une fonction d initialisation d un damier ; une fonction d affichage d un damier. L affichage est une représentation alphanumérique du damier constituée d espaces pour les cases mortes et d astérisques (*) pour les cases vivantes ; une fonction retournant le nombre de voisines vivantes d une cellule ; une fonction de calcul de la génération suivante. III.2. Contraintes de programmation. Le damier sera représenté sous la forme d un tableau à UNE dimension. Le programme principal devra consister à saisir le nombre d états à simuler, à initialiser le damier, puis à générer et visualiser un état du damier toutes les secondes. 5
Génération 1 1 2 3 4 5 6 7 8 9 0 1 * 2 3 * 4 * * 5 * 6 * * 7 * 8 * 9 0 Génération 2 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * * 6 * * * 7 * * 8 9 0 Génération3 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * * 6 7 * * 8 9 0 Génération 4 (damier mort) 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 Génération 1 1 2 3 4 5 6 7 8 9 0 1 2 * * 3 * * * 4 * * 5 * * * * * * * 6 * * * * 7 * * * * * 8 9 * 0 * * Génération 2 1 2 3 4 5 6 7 8 9 0 1 2 * * 3 * * * 4 * * 5 * * * * * * * * 6 * * * * 7 * * * * * 8 9 * 0 * * Génération 3 1 2 3 4 5 6 7 8 9 0 1 2 * * 3 * * * 4 * * * 5 * * * * * * * * 6 * * * * 7 * * * * * 8 9 * 0 * * Génération 4 1 2 3 4 5 6 7 8 9 0 1 2 * * 3 * * * 4 * * * 5 * * * * * * * * * 6 * * * * 7 * * * * * 8 9 * 0 * * Génération 5 : identique à génération 1 Figure 1 : Évolution de l état d un automate cellulaire dans le «Jeu de la vie». L exemple de la colonne gauche meurt en 4 générations, celui de droite est un oscillateur de période 4. 6
TP4 : Gestion d une file de taille fixe I. Introduction. Une file (en anglais, queue) est une structure de donnée dont les s sortent dans l ordre dans lequel ils arrivent (principe du «premier entré, premier sorti», en anglais First In, First Out ou FIFO). Le comportement est analogue à une file d attente : les personnes arrivées les premières sont les premières à sortir de la file pour être servies. II. Description du fonctionnement. II.1. Représentation. Il existe plusieurs implémentations de files. Nous ne considérons ici que le cas de files de taille fixe, qui peuvent être représentées par des tableaux. Plus précisément, nous implémentons une file grâce à un tableau circulaire d entiers. Cette représentation nécessite deux indices de tableau notés t et q, qui mémorisent respectivement la tête et la queue de la file. Une case de la file est vide quand sa valeur est égale à 0. II.2. Règles d évolution. Le fonctionnement d une telle file est décrit ainsi (cf. figure 2) : l ajout d un se fait en tête de file ; la suppression d un se fait en queue de file ; lorsque la file est pleine, il est interdit d ajouter un ; lorsque la file est vide, il est interdit de supprimer un. III. Élaboration du programme. III.1. Fonctions. L utilisateur accède à un menu affichant les différentes fonctions suivantes qui lui sont disponibles : adjonction : ajoute un en tête de file, tout en assurant la mise à jour des indices de tête et de queue. Cette fonction vérifie que la file n est pas pleine avant d ajouter un ; suppression : supprime un en queue de file, tout en assurant la mise à jour des indices de tête et de queue. Cette fonction vérifie que la file n est pas vide avant de supprimer un ; lister : affiche le contenu de la file, en mettant en évidence la tête t et la queue q. III.2. Contraintes de programmation. Toutes les variables doivent être locales. Le programme doit notamment être testé dans les cas limites suivants : adjonction d un quand la file est pleine ; suppression d un quand la file est vide ; adjonction de la valeur réservée 0. 7
File initialement vide 2 ème 3 ème q, t 0 q 1 q 1 q 1 0 t 0 2 2 0 0 t 0 3 0 0 0 t 0 0 0 0 0 Suppression d un Suppression d un 0 0 0 t 0 q 2 q 2 0 0 3 3 q 3 q 3 t 0 4 4 4 0 t 0 t 0 5 6 6 t 0 7 Impossible q 3 q, t 3 (file pleine) : 4 4 la file est 5 5 inchangée. Figure 2 : Adjonction et suppression d s dans une file de taille fixe. 8