LIF1 : Algorithmique et programmation impérative, initiation
Transcription
LIF1 : Algorithmique et programmation impérative, initiation
Licence ST Université Claude Bernard – Lyon 1 LIF1 : Algorithmique et programmation impérative, initiation Support de Travaux Pratiques Elodie DESSEREE http://perso.univ-lyon1.fr/elodie.desseree/LIF1/index.php Planning LIF1 - Automne 2014-2015 S1 CM CM1 : Bases Algo 08/09/2014 CM2 : Bases C TD TP SOUTIEN TD1 : Bases Algo TD2 : Algo évolués S2 15/09/2014 S3 22/09/2014 CM3 : Fonctions / Procédures S4 S5 29/09/2014 CM4 : Paramètres 06/10/2014 CM5 : Tableaux TD3 : Fonctions / procédures TD4 : Passage de paramètres TP2 : Fonctions / Procédures S6 13/10/2014 TD5 : Tableaux 1D TP3 : Paramètres / Tableaux 1D S7 20/10/2014 CM6 : Chaines de caractères TD6 : Tableaux 2D S8 27/10/2014 S9 03/11/2014 S10 S11 S12 S13 10/11/2014 17/11/2014 CM7 : Structures 24/11/2014 01/12/2014 S14 08/12/2014 CM8 : Révisions S15 S16 S17 S18 15/12/2014 22/12/2014 29/12/2014 05/01/2015 TP1 : Bases C Soutien 1 TP4 : Tableaux 2D Pas d'enseignements : congés de Toussaint CC mi-parcours dans la TD Révision 1 (1h30) séquence d'enseignement TD7 : Chaines de caractères (1) Pas d'enseignements : 11 novembre TD8 : Chaines de caractères (2) TP5 : Chaines de caractères TD9 : Structures TP6 : Chaines de caractères TD10 : Démineur TP7 : Structures TD11 : Démineur (suite) + Fichiers TD Révision 2 (1h30) TP8 : Démineur VACANCES DE NOEL CONTRÔLE TERMINAL - 2h Soutien 2 Soutien 3 TP 1 : Prise en main de l’environnement / programmes simples Si aucune erreur de compilation n’est détectée, vous devriez avoir la possibilité d’exécuter votre programme. Cliquez sur Objectifs : prise en main de l’environnement CodeBlocks apprendre la syntaxe du langage C traduire des algorithmes Ce sujet est disponible sur le site de l’UE : http://perso.univ-lyon1.fr/elodie.desseree/LIF1/index.php rubrique Supports de TP. 1. Connexion sous Windows, Rappel : Pour l’ouverture d’une session Windows XP : • Gardez enfoncées les touches <CTRL> et <ALT> puis tapez sur <SUPPR>. • Dans la fenêtre de connexion, tapez votre nom d’utilisateur (n° d’étudiant dans lequel le premier chiffre est remplacé par une lettre : 1 par p, 2 par q, etc.), • puis votre mot de passe (n° BIP sur votre carte d’étudiant), • puis vérifiez que vous vous connectez sur le domaine « UNIV-LYON1 ». • Validez (<ENTRÉE>). 2. Créer votre dossier de travail Pour organiser votre de travail et retrouver facilement vos exercices : créez un dossier LIF1, un sous-dossier TP1 dans W: Vous procéderez de même pour chaque TP de ce semestre. 3. Lancement de CodeBlocks Ce logiciel est un logiciel libre (gratuit) que vous pourrez installer également chez vous pour terminer les TP. • Menu Démarrer CodeBlocks. Si le logiciel n’est pas installé sur votre machine, vous pouvez le télécharger ici : http://www.codeblocks.org/downloads/26 4. Votre Premier programme pas à pas Créez un nouveau fichier (Fichier New File …) Sélectionnez Empty C/C++ source puis C++ puis Next. Donnez un nom à ce fichier ayant pour extension .cpp puis cliquez sur Finish. Enregistrez votre source C/C++ dans votre répertoire de travail (cf. 2), avec un nom se terminant par .cpp (important), par exemple : hello.cpp Recopiez le morceau de code ci-dessous : #include <iostream> using namespace std; int main(void) { cout << "Hello !!!" << endl; return 0; } Compilez le programme : Menu Générer, puis Générer (CTRL +F9) ou cliquez sur le bouton . ou bien menu Exécuter, puis Exécuter (CTRL +F10). Sinon, vous devriez avoir une fenêtre avec le mot « hello », félicitations, votre premier programme fonctionne correctement ! 5. Rédiger un programme à partir d'un algorithme. Il est relativement simple de "passer" d'un algorithme détaillé à un programme source C/C++. Voici un résumé des points essentiels sous forme d'exemples et de fragments de source C/C++. 1. Déclarer une variable : Un entier correspond à int, réel à float, une valeur logique (vrai, faux) à bool, un caractère à char… exemple : x : réel devient en C float x; a : entier devient en C int a; remarque : n'oubliez pas le ; à la fin de la ligne. 2. Les instructions élémentaires : Affecter une valeur à une variable : a 10 a = 10; Condition / test / comparer deux valeurs : Si a < b opérations à exécuter dans ce cas Sinon opérations à exécuter dans l'autre cas (lorsque b <= a) finSi remarque : l'égalité entre deux valeurs ou deux variables se note = = en C/C++. if ( a == b ) /* si a est égal a b */ { instruction1; instruction2; } else /* a est différent de b */ { instruction1; instruction2; } Itérations / répéter / tant que : i0 tant que i <= N opérations à répéter i i +1 fin tant que c. Écrivez un programme permettant d’afficher un triangle de hauteur N ; N étant demandé à l’utilisateur et représentant à la fois le nombre maximum d’étoiles sur la dernière ligne et le nombre de lignes. Quelle est la hauteur du triangle ? 4 i= 0; while(i <= N) { instruction1; instruction2; i= i + 1; } Quelle est la hauteur du triangle ? 4 Résultat : **** *** ** * Si vous n’avez pas fini cette partie obligatoire du TP pendant la séance, terminez-le seul !!! for(i=1;i<N;i++) { instruction1; instruction2; } 8. Questions subsidiaires (pour les plus rapides) a. Écrivez un programme qui affiche une ligne de longueur N contentant 1 étoile, N-2 espaces et 1 étoile. Longueur de la ligne ? 6 6. Exercices pour commencer… Utilisez vos notes de TD afin de rédiger les programmes suivants : • Écrire un programme permettant de calculer la moyenne de 3 valeurs réelles • Écrire un programme permettant d’afficher de la plus petite de deux valeurs • Traduire en langage C l’exercice 6 du TD1. Programmer une calculatrice proposant les opérations classiques • Saisie d’une valeur entre deux bornes • Écrire un programme permettant d’afficher les tables de multiplication pour tous les entiers de 1 à 10. 7. Premiers pas, premières étoiles a. Écrivez un programme permettant d’afficher N étoiles sur une ligne ; N étant demandé à l’utilisateur. Résultat : * * (Note : il y a 4 espaces entre les deux étoiles ici) b. En utilisant ce que vous venez de faire, écrivez un programme affichant le contour d'un rectangle de taille N * M. Longueur du rectangle ? 6 Largeur du rectangle 4 Résultat : ****** * * * * ****** c. Écrivez un programme qui affiche une ligne de longueur n en alternant les espaces et les étoiles. Longueur de la ligne 6 Résultat : * * * Résultat : ***** b. Écrivez un programme permettant d’afficher un rectangle de N * M étoiles ; N et M étant demandés à l’utilisateur. Quelles sont les dimensions du rectangle : longueur ? 4 Largeur 3 * ** *** **** d. et maintenant le même triangle à l’envers !!! Itérations / boucle pour : Pour i allant de 1 à N par pas de 1 faire opérations à répéter fin pour Combien d’étoiles voulez-vous afficher ? 5 Résultat : Résultat : **** **** **** d. En réutilisant ce que vous avez fait, écrivez un programme qui affiche un damier de taille MxN. Taille du damier N ? 4 M? 6 Résultat : * * * * * * * * * * * * e. Faites en sorte que l'utilisateur puisse afficher un damier en choisissant non seulement sa taille mais aussi le caractère utilisé. Résultat : Quel est la caractère souhaité ? o taille du damier N ? 4 M? 6 o o o o o o o o o o o o f. Essayez d'écrire des programmes permettant d'afficher les figures suivantes... * ** *** **** ***** **** *** ** * * *** ***** ******* ***** *** * * * * ********* * * * 2. Suite de Fibonacci LIF 1 – TP 2 : Procédures et Fonctions Objectifs : Le but de ce TP est de revoir et manipuler toutes les notions que vous avez acquises jusqu'à maintenant. A la fin, vous devrez bien maîtriser : L'importance de la fonction main et la façon d'appeler des procédures et des fonctions. Les boucles simples (tant que, faire) Les boucles imbriquées La structure conditionnelle (si…alors…sinon) Les sujets et supports de cours sont disponibles sur le site du cours : http://perso.univ-lyon1.fr/elodie.desseree/LIF1/index.php rubrique Supports de TP. 1. Reprenez les exercices du TD. Utilisez vos notes des TD 2 et 3 afin de rédiger les programmes suivants : • Fonction permettant de retourner la moyenne de deux réels passés en paramètre. • Fonction permettant de calculer et de retourner la factorielle d’un nombre passé en paramètre. Utilisez ce sous-programme pour afficher les 15 premières valeurs des factorielles. Comparez les résultats de factorielle (13) et factorielle (14). Ces résultats vous semblent-ils cohérents et corrects ? Pourquoi ? Modifiez le type de retour de la fonction factorielle en double au lieu de int et observez les nouvelles valeurs obtenues. • Fonction permettant de calculer la somme des n premières puissances de 2 • Lire 20 nombres au clavier et afficher le carré des nombres pairs uniquement • Trouver une valeur choisie aléatoirement. L’exemple suivant permet de choisir aléatoirement une valeur comprise entre 0 et 29. #include <iostream> using namespace std; int main (void) { int valea; srand(time(NULL)); valea=rand()% 30; cout<<"la valeur aleatoire est : "<<valea<<endl; system("PAUSE"); return 0; } Attention : outre la traduction en langage C des algorithmes écrits en TD, vous devrez également modifier le code pour écrire des fonctions ou des procédures ainsi que le programme principal permettant de tester ces sous-programmes. Soit la suite de Fibonacci définie de la manière suivante : Si n<2 fibonacci(n) = 1 Si n>=2 fibonacci(n)= fibonacci (n-1) + fibonacci (n-2) Afficher le nième terme de la suite de Fibonacci (n étant passé en paramètre) 3. Triangle de Pascal Écrivez un programme qui affiche le triangle de Pascal jusqu'à la ligne n. Pour réaliser ce programme, écrivez dans un premier temps la fonction combinaison (qui utilisera factorielle): int combinaison(int n, int p) Rappel : La fonction du triangle de Pascal à réaliser à pour signature: void trianglePascal(int n) ; trianglePascal(5); 1 1 1 1 1 1 1 2 1 3 3 1 4 6 4 1 5 10 10 5 1 4. Dessiner un carré En utilisant l’algorithme écrit dans le TD 3 (exercice 7) ainsi que les programmes du TP1, écrivez un programme permettant de dessiner le contour d’un carré en choisissant le caractère du contour. Cette fois-ci, vous devrez utiliser une procédure comme le suggère l’exemple cidessous : afficherCarre(10, ‘*’); ********** * * * * * * * * * * * * * * * * ********** 5. Dessiner un cercle plein Écrivez une procédure qui affiche un cercle. procédure cercle(r : donnée Entier) // r est le rayon du cercle 6. Questions subsidiaires a) Renverse (Simple boucle mais non vu en TD) Cette procédure pourra utiliser une procédure annexe aff_ncar qui affichera n fois le caractère spécifié dans les paramètres. procedure aff_ncar(n : donnée Entier, car : donnée Caractère) Aide : pour bien comprendre ce que fait votre programme quand l'affichage n'est pas correct (donc pour déboguer votre programme) vous pouvez appeler la procédure aff_ncar avec le caractère '-' à la place des espaces. Écrivez un programme renverse.cpp qui demande un entier n et affiche n en inversant l'ordre des chiffres. Indication : n modulo 10 (n%10 en C) donne le dernier chiffre (celui de droite); La partie entière de n/10 donne tous les chiffres de gauche (sauf le dernier). Il suffit alors d'itérer. En C, si vous divisez deux entiers entre eux vous obtenez la partie entière de la division : int n,i; afficherCercle(40); n=125; i = n/10; /* i prend pour valeur 12 */ // Testez votre fonction sur de grands rayons b) Les frises (triple boucle cachée dans un appel de procédure) Écrivez une procédure qui affiche une frise : // A partir d'un demi-cercle, il est facile d'obtenir le cercle complet procedure afficherFrise(n,l,h : donnée Entier) // n est le nombre de fois que se repete le motif // l est la demi longueur d'un motif // h est la hauteur d'un motif R Nous cherchons AB et BC. A B C RC va correspondre à notre indice de boucle i. OB est le rayon du cercle AB+BC = rayon O OB² = OC² + BC² <=> BC=sqrt(OB²-OC²) Exemple : afficherFrise( 5, 6, 7); 2. Reprise des TD : passage de paramètres LIF 1 – TP 3 : Passage de paramètres / Tableaux 1D Objectifs : Mode de passage des paramètres : données, données/résultats (cas particulier des tableaux. Utilisation des tableaux : déclaration, initialisation, remplissage, calcul à partir de tableaux, … Programmez les exercices suivants vus en TD (ou CM) : a) Permutation circulaire b) Division Euclidienne c) Nombre de combinaisons (fonction ET procédure) d) Résolution d’une équation du second degré (dans CM 2) Écrivez à chaque fois le programme principal permettant de tester vos sous-programmes. Le sujet est disponible sur le site du cours : http://perso.univ-lyon1.fr/elodie.desseree/LIF1/index.php rubrique Supports de TP. 3. Entre passage de paramètres et tableaux… 1. Kezako (Compréhension : fonction/procédure, paramètres et appels): A partir de la fonction écrite en 2.c) écrivez un sous programme permettant de remplir un tableau contenant la nième ligne du triangle de Pascal. a) Que fait le programme ci-dessous ? Réfléchissez et écrivez le texte que vous pensez voir apparaître à l'exécution de ce programme : #include <iostream.h> #include <stdlib.h> void proc_mult(int a, int b, int& ab) { cout << "execution de la procedure proc_mult" << endl; 4. Les tableaux à une dimension a) Écrivez une procédure tabRemplir qui remplit un tableau de taille TAILLE en demandant à l'utilisateur les valeurs. On définira TAILLE comme une constante au début du programme : // En ALGO Constante : TAILLE : Entier = 5 Procédure tabRemplir(T : donnée-résultat Tab[TAILLE] d'Entier) ab = a*b; } int fonc_mult(int a, int b) { cout << "execution de la fonction fonc_mult" << endl; return a*b; // En C #include <iostream.h> const int TAILLE=5; void tabRemplir( ... } b) Écrivez une procédure tabAff qui affiche sur la sortie standard le contenu d'un tableau d'entiers : void kezako(int x, int y, int r1, int& r2) { proc_mult( x, y, r1); Proc tabAff(T : donnée tab[TAILLE]) // En ALGO r2 = fonc_mult(x,y); cout << "A la fin de kezako r1=" << r1 << " r2=" << r2 <<endl; } int main(void) { int a, y, res1, res2; a = 5; y = 4; res1 = 0; res2 = 1; c) En C, un tableau ne peut avoir une taille variable : sa taille doit être une constante. Pour pouvoir gérer un tableau de taille quelconque une manière de faire est de définir une grande valeur pour TAILLE et d'utiliser une valeur tailleT pour indiquer la taille réellement utilisée du tableau : cout << "Dans main avant kezako res1=" << res1 << " res2=" << res2 <<endl; kezako( a, y, res1, res2); cout << "Dans main apres kezako res1=" << res1 << " res2="<< res2 << endl; return EXIT_SUCCESS; // En ALGO Constante : TAILLE : Entier = 100 Proc tabAff(T : donnée Tab[TAILLE] d'Entier ; tailleT :donnée Entier) } Faites un copier/coller du programme Kezako afin de vérifier si votre idée est correcte. Sinon demandez une explication à votre encadrant de TP. // En C const int TAILLE=100; void tabAff(int T[TAILLE], int tailleT) { ... Modifiez les procédures des questions a) et b) pour prendre en compte cette amélioration. d) Écrivez une fonction tabSomme qui renvoie la somme de tous les entiers contenus dans un tableau T Fonct tabSomme(T : donnée Tab[TAILLE] d'Entier ; tailleT : donnée Entier) : Entier e) Écrivez une fonction tabRechPosMin qui recherche le plus petit entier d'un tableau T entre la case debut et la case fin. Cette fonction renvoie directement la position de ce minimum et renvoie par l'intermédiaire d'un paramètre donnée-résultat la valeur du minimum. // Renvoie la position du minimum Fonct tabRechPosMin( T : donnée tab[TAILLE] d'Entier; debut, fin : donnée Entier; min : donnée-résultat Entier) : Entier 5. Questions subsidiaires a- écrire un programme permettant de trier un tableau de 15 éléments en utilisant le principe du tri à bulles. Principe du tri à bulles : fonctionne par comparaisons successives de tous les éléments adjacents d’un tableau on échange les deux éléments comparés si le premier est supérieur au second on recommence l’opération tant que tous les éléments ne sont pas triés Exemple : f) Écrivez une procédure tabPermute qui permute deux valeurs d'indices a et b d'un tableau T Proc tabPermute(T : donnée-résultat tab[TAILLE] d'Entier; a,b : Entier) g) En utilisant les questions e) et f), écrivez une procédure TriMin qui trie les entiers contenus dans un tableau T. Indication : rechercher le minimum du tableau entre les cases 0 et tailleT-1, permuter ce minimum avec la case 0 du tableau puis recommencer avec le sous-tableau allant de la case 1 à la case tailleT-1 ... ainsi de suite jusqu'à ce que la zone de recherche du minimum soit de taille 1. h) Écrivez la fonction principale sous forme de menu proposant à l’utilisateur de tester chacun des sous-programmes écrits précédemment. b- transformez votre programme de manière à compter le nombre d’affectations effectuées pour trier ce tableau de 15 éléments. Essayez d’augmenter progressivement le nombre d’éléments dans le tableau à trier et concluez sur l’efficacité de cet algorithme de tri. c- Reprenez la question 4g) et ajoutez un paramètre à cette procédure pour pouvoir choisir entre un tri par ordre croissant et un tri par ordre décroissant, par exemple avec un caractère : 'c' pour croissant et 'd' pour décroissant. d- Écrivez une procédure qui manipule deux tableaux t1 et t2 (de même taille) et qui modifie t2 en ajoutant à chaque élément de t2 la valeur de l'élément correspondant dans t1. Par exemple, si t1 = [1 3 5 9] et t2 = [2 4 6 8], alors après l'appel de la procédure, t1 sera inchangé et on aura t2 = [3 7 11 17] e- Écrivez une procédure qui effectue la fusion de deux tableaux triés de tailles quelconques (toujours à l'aide du paramètre tailleT) Par exemple : Fusion de t1=[1 3 5 9] et t2=[4 7 11 17] donnera tr=[1 3 4 5 7 9 11 17] Que fait votre programme si la longueur de t1+t2 est plus grande que TAILLE? LIF 1 – TP 4 : Tableaux 2D Objectifs : Lorsque le débogueur est bloqué (sur un point d’arrêt ou consécutivement à l’emploi de la commande Executer jusqu’au curseur) on doit le débloquer par une des commandes : Manipuler des tableaux à deux dimensions Apprendre à repérer et corriger les erreurs dans un programme • • Le sujet est disponible sur le site du cours : http://perso.univ-lyon1.fr/elodie.desseree/LIF1/index.php rubrique Supports de TP. 1. Petit exercice pour commencer !!! a) Soit un tableau d’entiers à deux dimensions de taille maximum TAILLE_LIGNE et TAILLE_COLONNE. Écrivez une procédure qui, à partir du nombre de lignes et de colonnes données par l’utilisateur remplit les tailleL * tailleC cellules de ce tableau. b) Écrivez une procédure qui affiche (proprement) le contenu du tableau précédent. c) Écrivez enfin les fonctions de calcul de somme sur une ligne et sur une colonne vues dans le TD6. // En ALGO Constante : TAILLE_LIGNE : Entier = 100 TAILLE_COLONNE : Entier = 100 • Pas à Pas (Next Step) : exécuter une instruction, en considérant qu’un appel de fonction est une instruction atomique qu’il n’y a pas lieu de détailler, Avancer (Step Into) : avancer d’une instruction, en s’arrêtant, le cas échéant, à l’intérieur des fonctions appelées, Continuer : relancer l’exécution du programme, jusqu’au prochain point d’arrêt ou, s’il n’y en a plus, jusqu’à la fin. Examiner les variables. Pour faire afficher une variable dans le volet Debug à gauche de l’écran il suffit cliquer sur le bouton Ajout variable ou bien de double-cliquer sur la variable. En fait, passer (lentement, soyez patients) le curseur sur la variable suffit la plupart du temps pour l’ajouter au volet Debug. La variable et sa valeur sont ensuite constamment affichées et on peut en observer l’évolution pendant que le programme est exécuté. Reprenez le programme Kézako du TP 4 (avant les modifications) et testez le débogueur dessus. Essayer notamment d’afficher le contenu des variables r1, r2, res1, res2, … Modifiez le code comme vous l’aviez fait dans le TP3 puis relancez le debogueur. #include <iostream> #include <stdlib.h> using namespace std ; void proc_mult(int a, int b, int& ab) Proc tabAff(T : donnée Tab[TAILLE_LIGNE][TAILLE_COLONNE] d'Entier; tailleL,tailleC : donnée Entier) { // En C const int TAILLE_LIGNE=100; const int TAILLE_COLONNE=100; } cout << "execution de la procedure proc_mult" << endl; ab = a*b; int fonc_mult(int a, int b) { cout << "execution de la fonction fonc_mult" << endl; void tabAff(int T[TAILLE_LIGNE][TAILLE_COLONNE], int tailleL, int tailleC) {... return a*b; } void kezako(int x, int y, int r1, int& r2) 2. Utilisation du débogueur { proc_mult( x, y, r1); Dans cet exercice vous allez apprendre à utiliser le débogueur sur un exemple simple. r2 = fonc_mult(x,y); cout << "A la fin de kezako r1=" << r1 << " r2=" << r2 <<endl; Il a deux manières principales de lancer le débogueur : • • placer un point d’arrêt (breakpoint) puis actionner la commande Debugger placer le curseur au début d’une instruction puis actionner la commande Executer jusqu’au curseur } int main(void) { int a, y, res1, res2; a = 5; y = 4; res2 = 1; <<endl; kezako( a, y, res1, res2); cout << "Dans main apres kezako res1=" << res1 << " res2="<< res2 << endl; system("PAUSE") ; return EXIT_SUCCESS; Un programme ne peut être arrêté que sur des instructions, évitez de mettre des points d’arrêt sur des lignes constituées de déclarations (des déclarations il ne reste aucune trace après la compilation). res1 = 0; cout << "Dans main avant kezako res1=" << res1 << " res2=" << res2 La manière la plus simple de placer un point d’arrêt consiste à cliquer dans la gouttière (la marge de gauche). Une marque dans la gouttière indique le point d’arrêt, ainsi qu’un surlignage de la ligne concernée. D’autre part, une flèche dans la gouttière montre constamment la ligne sur laquelle l’exécution est arrêtée. } 3. Des caractères dans des tableaux !!! Dans cette partie nous allons programmer le jeu du morpion. Pour cela, vous avez besoin d’une grille 3*3 et de 2 joueurs ayant des pions différents (les croix et les ronds). X X O O X X X O O Grille avec gagnant X O X O X O O X X Grille sans gagnant A tour de rôle, chaque joueur positionne un de ses pions sur la grille. Le jeu se finit quand un joueur a réalisé une ligne, une colonne ou une diagonale avec ses pions (c'est le gagnant) ou quand la grille est pleine (pas de gagnant). Commencez d'abord par les deux premières fonctions et testez. Puis continuez avec la fonction metUnPionSurLaGrille et testez. Et enfin, terminez avec la fonction testeFinJeu qui est un peu plus complexe. Écrivez ensuite le programme principal permettant de dérouler la partie. En voici son algorithme : Algorithme principal : Initialisation de la grille à vide Tant que (pas de gagnant ou pas grille pleine) Afficher grille Mettre un pion sur la grille 4. Partie Facultative La grille est représentée par un tableau à 2 dimensions de caractères dont chaque case contiendra soit ‘_’, soit ‘O’, soit ’X’. Pour réaliser l’implémentation de ce jeu, écrivez les sous-programmes suivants : void initialiseGrille(char grille[3][3]) /* Initialise la grille du morpion à vide (caractère ‘_’)*/ void afficheGrille(char grille[3][3]) /* Affiche la grille du morpion _ indique case vide, O pion joueur 1 et X pion joueur 2 */ void metUnPionSurLaGrille(char grille[3][3], char &prochain_joueur) /* Saisie les coordonnées du nouveau pion à mettre sur la grille Si les coordonnées sont en dehors de la grille ou si la case possède déjà un pion, la saisie est refusée, un message d'erreur est affiché, et le joueur doit rejouer */ Boolean testeFinJeu(char grille[3][3], char prochain_joueur) /* Teste si l'un des joueurs a gagné (ligne, colonne ou diagonale remplie de pions semblables). Dans ce cas, affiche un message pour indiquer le joueur qui a gagné. S'il n'y a pas de gagnant, teste que la grille n'est pas pleine. Si elle est pleine, affiche un message indiquant qu'aucun des joueurs a gagné Retourne TRUE si la grille est pleine ou si un joueur a gagné FALSE sinon */ Reprenez le programme du morpion que vous venez d’écrire et essayez de le transformer en puissance 4 !!! LIF 1 – TP 5 : Chaînes de caractères Objectifs : // En C int main() { char txt[CHMAX]; chLire(txt); cout<<txt; return 0; } Manipuler les chaînes de caractères Le sujet est disponible sur le site du cours : http://perso.univ-lyon1.fr/elodie.desseree/LIF1/index.php rubrique Supports de TP. 1. Rappels Manipuler les tableaux de caractères. Rappel : une chaîne de caractères en C est représentée sous forme d'un tableau de caractères. Le caractère spécial '\0' repère la fin de la chaîne. Ceci permet de ne pas utiliser forcement tout le tableau. Par exemple, un tableau de 20 caractères peut contenir la chaîne "maison" bien que celle-ci ne comporte pas 20 caractères : 'm' 'a' 'i' 's' 'o' 'n' '\0' 't' 'r' 'u' 'c' 'q' 'u' 'i' 't' 'r' 'a' 'i' 'n' 'e' Les fonctions et procédures manipulant des tableaux de caractères respectent toutes cette convention! Les vôtres aussi! Attention : Pour stocker une chaîne de longueur N, il faut un tableau de longueur N+1 à cause du '\0' terminal. "maison" correspond à un tableau de caractères de 7 cases : les 6 lettres + le '\0' 'c' signifie le caractère c (=1 caractère) alors que "c" signifie le tableau de caractères (= 2 caractères, le 'c' et le '\0'). Il est possible de comparer deux caractères avec == mais cette opération n'est pas valide avec les tableaux de caractères (car cette opération n'est pas valide sur les tableaux de toutes sortes). Si 'c'=='f' alors ... // OK Si "maison"=="voiture" alors... // Interdit!! Si "c"=="f" alors ... // Interdit!! 2. Fonctions classiques sur les chaînes a) Définissez en C une constante CHMAX contenant la taille maximal des tableaux de caractères manipulés. Il sera alors possible de stocker des chaînes de longueur CHMAX-1 à cause du '\0' terminal. // En algo Constantes : CHMAX : Entier = 100 // En C const int CHMAX = 100; b) Écrivez la procédure chLire qui demande à l'utilisateur le nombre de caractères N que va comporter la chaîne de caractères puis qui demande à l'utilisateur les N lettres de celle-ci. Cette procédure ajoutera automatiquement le caractère '\0' en fin de chaîne dans le tableau. // En algo Procédure chLire(ch : donnée-résultat Tab[CHMAX] de caractère) Pour vérifier que votre fonction chLire fonctionne correctement vous pouvez afficher votre chaîne de caractères avec cout. cout affiche tous les caractères du tableau jusqu'à ce qu'il rencontre le '\0' indiquant la fin du mot. Remarque : l'instruction chLire(txt) est assez proche de l'instruction cin>>txt. Seulement, cin>>txt ne demande pas à l'avance le nombre de lettres à saisir, En effet, la fonction cin considère que la chaîne est terminée lorsqu'elle rencontre un espace ' ' ou un retour à la ligne '\n'. Avec chLire il est donc possible de saisir une chaîne comportant des espaces comme "la pomme est verte" alors que ceci n'est pas possible directement avec cin>>txt : cin ne lira que "la". Le reste du texte " pomme est verte" sera gardé en mémoire de l'ordinateur et alimentera un prochain cin. b) Écrivez la fonction chLongueur qui détermine la longueur d'un mot stocké dans un tableau de caractères (sans compter le '\0' terminal). Par exemple, sur le tableau "maison" définit en 1. la fonctions renverra 6. // En algo Fonction chLongueur(ch : donnée Tab[CHMAX] de caractère) : Entier c) Écrivez la procédure chMiroir qui construit le miroir d'une chaîne de caractères. Attention : cette procédure n'affiche pas le résultat à l'écran. Par exemple, "maison" donnera "nosiam". // En algo Procédure chMiroir(ch : donnée tab[CHMAX] de caractère; chR : donnée-résultat tab[CHMAX] de caractère) d) Écrivez la fonction chConcat qui concatène deux tableaux de caractères. Le résultat sera stocké dans le 1er tableau de caractères. Par exemple, la concaténation des deux chaînes "rouge " et "vert" donnera "rouge vert". // En algo Procédure chConcat(ch1 : donnée-résultat tab[CHMAX] de caractère; ch2 : donnée tab[CHMAX] de caractère) e) Écrivez la fonction chCompare qui renvoie vrai si deux chaînes de caractères sont identiques et faux sinon. // En algo Fonction chCompare(ch1, ch2 : donnée tab[CHMAX] de caractère) : booléen Remarque : il est maintenant possible d'écrire Si chCompare(ch1,ch2) alors ... sinon ... Rappel, ceci est interdit : Si ch1==ch2 alors ... 3. Fonctions plus élaborées a) En utilisant chMiroir et chCompare écrivez maintenant très rapidement (en 2 lignes) la fonction chEstPalindrome qui renvoie vrai si les deux chaînes sont des palindromes et faux sinon. b) Écrivez une fonction permettant de compter le nombre d’occurrences d’un caractère donné dans une chaîne de caractères. c) Écrivez une fonction booléenne permettant de tester si une chaîne de caractères passée en paramètre est entièrement constituée de majuscules ou non. d) Après avoir vérifié que la chaîne passée en paramètre ne comportait que des majuscules, transformez-la en minuscules. e) Enlevez toutes les voyelles d'une chaîne donnée en paramètre. 4. Partie facultative Écrivez la fonction chVerlan qui construit la chaîne ou tous les mots sont inversés (miroir) mais ou l'ordre des mots reste identique. Par exemple, la chaîne "la pomme est verte" donnera "al emmop tse etrev". // En algo chVerlan(ch : donnée tab[CHMAX] de caractère; chR : donnée-résultat tab[CHMAX] de caractère) S’il vous reste encore du temps, programmez le jeu du pendu vu dans le CM6 ! 2. Tri de chaînes de caractères LIF 1 – TP 6 : Tableau de Chaînes de caractères et Tri Objectifs : utiliser les chaînes de caractères dans des tableaux programmer un tri simple : le tri par insertion Il s’agit ici de faire un tri par insertion afin de simuler le comportement d’un dictionnaire. Vous allez saisir tous les mots les uns après les autres et les insérer au dictionnaire (un tableau) en conservant l’ordre alphabétique. Exemple : Premier mot : train train Le sujet est disponible sur le site du cours : http://perso.univ-lyon1.fr/elodie.desseree/LIF1/index.php rubrique Supports de TP. 1. Reprise du TD8 Deuxième mot : voiture train voiture Troisième mot : avion avion train voiture Programmez le jeu de mémo proposé dans le TD8. La correction de ce TD n’est volontairement pas disponible sur le site. Rappels : Le jeu "mémo" est un jeu de mémoire qui consiste à retrouver les paires d’images identiques dans une grille d’images retournées. Ici, les images seront représentées par le mot qu’elles signifient. La grille sera un tableau 2 dimensions. 1 2 3 4 1 2 3 4 Lion Lion Poule Vache Chat Chien Oie Tigre Chat Vache Canard Canard Poule Oie Tigre Chien a) Soit TAILLE_GRILLE une constante paire définie en début de programme. Écrire la déclaration du tableau de taille TAILLE_GRILLE*TAILLE_GRILLE contenant les chaînes de caractères. TAILLE_GRILLE est pair pour que le nombre de cases dans la grille soit pair aussi. b) Écrire une procédure d’initialisation de la grille de jeu avec des "*" c) Écrire une procédure de remplissage de la grille. Cette procédure devra demander à l’utilisateur (TAILLE_GRILLE)² / 2 chaînes de caractères qui seront insérées aléatoirement dans la grille de jeu. Attention de bien vérifier que la grille est vide à l’endroit sélectionné avant d’insérer le mot. d) Écrire une procédure demandant au joueur de choisir deux cases et d’afficher le contenu de ces deux cases. Pour cela les coordonnées des deux cases devront être passées en paramètres du sous-programme afin d’effectuer des saisies inutiles. e) Écrire une fonction de vérification du choix de l’utilisateur. Si les deux cases choisies sont identiques la fonction renverra 0 sinon elle renverra 1. f) Simuler le jeu à deux joueurs jusqu’à ce que toutes les paires aient été trouvées. Pour cela vous devrez écrire une procédure permettant d’assurer l’alternance entre les deux joueurs. Le programme principal devra quant à lui faire jouer alternativement les deux joueurs et comptabiliser le score de chacun. En fin de partie il affichera le numéro du joueur gagnant. Quatrième mot : bateau avion bateau train voiture Pour réaliser ce programme vous devrez écrire les sous programmes suivants : a- initialisation du tableau b- affichage du tableau c- recherche de l’indice auquel le mot doit être inséré d- décalage de tous les mots suivant l’indice d’une case vers la droite e- insertion du mot dans le tableau f- le programme principale devra proposé à l’utilisateur de saisir des mots tant qu’il le souhaite. 3. Questions subsidiaires Reprenez l’exercice 1 du TP en vérifiant à chaque saisie que les valeurs données par l’utilisateur sont bien dans la grille. Puis vérifiez que la case qui souhaite découvrir n’a pas déjà été LIF 1 – TP 7 : Structures Procédure imDessineRect(im : donnée-résultat Image; c : donnée Caractère; xmin, ymin, xmax, ymax : donnée Entier) Le sujet est disponible sur le site du cours : http://perso.univ-lyon1.fr/elodie.desseree/LIF1/index.php rubrique Supports de TP. Remarque : L'image n'est pas initialisée entre chaque dessin. Deux figures tracées à la suite dans une image vont se superposer. Objectifs : Manipuler les structures. Une structure est un type qui permet de regrouper différents champs dans une seule entité b) OPTION : Écrivez la procédure imDessineCercle qui dessine un cercle plein dans l'image. Cette procédure n'affiche pas l'image! Remarque : Contrairement aux tableaux, une structure n'est pas passée automatiquement en donnée-résultat. Pour passer une structure en donnée-résultat il faut le spécifier explicitement dans le prototype de la procédure (ou fonction), avec le symbole "&" après le type // En algorithmique void truc(struct camion Dcam, struct camion& DRcam) // Dcam est passé en donnée alors que DRcam est passé en donnée-résultat void truc(int DRi[10], struct camion DRcam[10]) // DRi est passé en donnée-résultat (car c'est un tableau) et Drcam aussi (car c'est un tableau) 1. Reprise du TD Reprenez et implémentez les fonctionnalités du TD9 sur les structures. 2. Représentation des images à l’aide d’une structure a) Définissez en langage C la structure Image représentant une image de caractères. Voici sa définition en langage algorithmique : //En algorithmique Constantes : DIMMAX : Entier = 100 Structure Image dimx, dimy : Entier // les dimensions de l'image : dimx<=DIMMAX im : tableau[DIMMAX][DIMMAX] de caractères Fin Structure b) Quelle doit être la signature de la procédure permettant d'initialiser une image im avec le caractère c ? Écrivez cette procédure. c) Écrivez la procédure imAff qui efface l'écran et affiche l'image : // En algorithmique procédure imAff(im : donnée Image) Attention : il faut afficher l'image de haut en bas car l'écran se remplit de haut en bas! Rappel : pour effacer l'écran l'instruction est system("cls"); 3.Partie facultative : Dessin (boucle avec bornes évoluées) a) Écrivez la procédure imDessineRect qui dessine un rectangle rempli avec le caractère c dans l'image. Cette procédure n'affiche pas l'image ! // En algorithmique Procédure imDessineCercle(im : donnée-résultat Image; c : donnée Caractère; x,y,r : donnée Entier) Version simple de l'algorithme : parcourez toutes les case de l'image, si la case considérée à une distance au centre du cercle inférieure au rayon, la case est dans le cercle. c) Insérez les procédures de tracé de ligne suivante dans votre programme (si vous avez respecté les consignes, ceci devrait marcher sans rien changer au reste de votre programme à part l'algorithme principal) : // En C #include <math.h> // Pour sqrt(); void imSet(struct image &im, int x, int y, char c) { im.im[x][y] = c; } void imDessineLigne(struct image &im, char c, int xi,int yi,int xf,int yf) { int x,y ; float a,b ; a =(float) (yf-yi)/(xf-xi) ; b = yi - a * xi ; for ( x = xi ; x <= xf ; x++ ) { y = ((int) (a * x + b )); // calcul l'ordonnee du point (conversion du float en int) imSet(im,x,y,c); // allume le pixel (x,y) ; } } void imDessineLigneBresenham(struct image &im, char c, int xi,int yi,int xf,int yf) { int dx,dy,cumul,x,y ; x = xi ; y = yi ; dx = xf - xi ; dy = yf - yi ; im.im[x][y] = c; // allume le pixel (x,y) ; cumul = dx / 2 ; for ( x = xi+1 ; x <= xf ; x++ ) { cumul += dy ; if (cumul >= dx) { cumul -= dx ; y += 1 ; } imSet(im,x,y,c); // allume le pixel (x,y) ; } } Remarque : Que se passe-t-il si vous dessinez une figure qui dépasse de l'image «à gauche»? et «à droite»? Comment pourriez-vous éviter facilement ces cas critiques? Aide : regardez autour de la fonction imSet utilisée pour le dessin d'une ligne. 2- Création de la grille de jeu LIF1 – TP 8 : Exemple de conception Le sujet est disponible sur le site du cours : http://perso.univ-lyon1.fr/elodie.desseree/LIF1/index.php rubrique Supports de TP. Objectifs : TP de révision de toutes les notions abordées dans l’UE. Conception d’un jeu. 1. Le démineur Programmez la version du démineur telle qu’elle vous a été proposée dans le TD10. 2. La bataille navale (partie facultative) Il s’agit de réaliser un jeu de bataille navale. Règles du jeu : La bataille navale est un jeu de société dans lequel deux joueurs doivent placer des bateaux sur une grille tenue secrète et tenter de se les 'torpiller' mutuellement. Dans cet exercice, on vous demandera dans un premier temps de positionner les bateaux, puis d’essayer de les retrouver dans la grille du jeu. La grille de jeu une grille 10*10 numérotée de 1 à 10 horizontalement et de A à J verticalement. La flotte du joueur est composée de la manière suivante : • 1 porte-avions de 5 cases : bateau 1 • 1 croiseur de 4 cases : bateau 2 • 1 contre-torpilleur de 3 cases : bateau 3 • 1 sous-marin de 3 cases : bateau 4 • 1 torpilleur de 2 cases : bateau 5 Les bateaux peuvent se toucher par le bout ou le côté mais pas se croiser. En cas d'erreur dans la construction d'un bateau, le jeu recommence. 1. créer la flotte, c'est à dire placer les bateaux sur la grille du jeu 2. jouer : a. saisir la case à sonder b. si la case sondée appartient à un des bateaux de la flotte touché, supprimer la case du bateau si le bateau ne contient plus de cases, supprimer le bateau de la flotte s'il n'y a plus de bateau dans la flotte, la partie est gagnée. La première question à laquelle il faut répondre est : "comment représenter les bateaux ?". Une fois que la représentation sera choisie, il ne restera plus qu'à écrire les différentes manipulations nécessaires à la programmation du jeu. Les deux plus grosses parties du jeu sont la création de la grille et la recherche du bateau touché. Nous allons décrire ces parties de manière plus précise dans la suite du sujet. 1- Représentation des bateaux Le choix d'une représentation est toujours délicat, il faut considérer les opérations ou les manipulations à réaliser sur la représentation afin de choisir la plus adaptée. Nous allons ici choisir de décrire un bateau par une origine, une orientation et une longueur. Écrire la ou les structures permettant de décrire un bateau. La grille de jeu est un tableau 10*10 sur laquelle les différents bateaux sont positionnés. Les bateaux peuvent être horizontaux ou verticaux mais ne doivent pas se croiser. Le positionnement sera dans un premier temps effectué par le joueur qui donnera pour chaque type de bateau son orientation et sa case d’origine. La grille de jeu contiendra plusieurs valeurs - 0 : signifiera qu’il n’y a pas de bateau - 1 à 5 : numéro du bateau - 8 : case déjà sondée, bateau touché Outre la grille de jeu qui contiendra toutes les informations relatives au positionnement des bateaux et aux cases déjà sondées, nous aurons besoin d’afficher à chaque étape au joueur une autre grille appelée grille_joueur (partielle celle-ci) qui ne donnera que les informations de contenu sur les cases sondées. Écrire les structures de données contenant la grille du jeu et la grille affichée au joueur ; Attention : les éléments de grille_jeu et de grille_joueur ne seront pas de même type !!! Écrire une procédure d’initialisation de la grille de jeu avec des ‘0’ Écrire une procédure d’initialisation de la grille du joueur avec des ‘–‘ Écrire une procédure d’affichage de la grille de jeu Écrire une procédure d’affichage de la grille du joueur Il faut ensuite placer les bateaux sur la grille de jeu en choisissant leur orientation et origine et en vérifiant à chaque fois que les bateaux ne se croisent pas et que l’on ne sort pas de la grille. Écrire une fonction creer_bateau qui demandera à l’utilisateur la case origine et l’orientation du bateau à créer. Cette fonction renverra le bateau ainsi créé. Écrire une fonction bateau_verifie qui vérifiera avant de créer le bateau que les informations données par le joueur sont correctes (pas d’intersection de bateaux ni de sortie de grille). Cette fonction renverra 1 si l’une des cases est déjà occupée par un autre bateau, 2 si le bateau sort de la grille et 0 si le bateau peut être créé. Écrire une procédure place_bateau qui remplira les cases de la grille de jeu avec le numéro du bateau. Écrire une procédure rempli_grille qui positionnera tous les bateaux sur la grille de jeu. 3- Le jeu Résumons les différentes étapes du jeu : 1. saisir la case à sonder 2. si la case sondée appartient à un des bateaux de la flotte o touché, supprimer la case du bateau o si le bateau ne contient plus de cases, supprimer le bateau de la flotte o s'il n'y a plus de bateau dans la flotte, la partie est gagnée. Écrire une procédure jouer qui demandera à l’utilisateur les coordonnées de la case à sonder sous la forme ligne (de A à J) et colonne (de 1 à 10). Écrire une procédure verifie_grille qui testera la case choisie par l’utilisateur. Écrire enfin la fonction principale qui permettra jouer à la bataille navale.