INF361 - TD 1: Premiers programmes

Auteurs : P. Chassignet (original), F. Morain

Pour commencer ce TD, vous devez avoir construit un projet, configuré pour l’utilisation de la classe TC, comme indiqué dans les activités préliminaires. Si ce n’est pas le cas, il faut commencer par cela.

C’est parti !

Rappel, toutes les classes que vous écrirez seront dans le paquetage par défaut (default package).

Déposer son travail

À partir de maintenant et au cours de chaque TD, vous devrez déposer votre travail au fur et à mesure. N’attendez pas la fin pour tout déposer, nous devons suivre votre avancement.

Une fois déposé, votre programme va faire l’objet d’une validation automatique. Attention, si la validation dit “OK”, cela ne veut pas dire que votre programme est parfait, mais simplement qu’il a passé avec succès quelques tests qui détectent les erreurs les plus grossières.

Remarque: Il n’y a pas d’exercice 1 cette semaine, il a été remplacé par les différents exercices préliminaires. Il s’agit maintenant d’exercices qui demandent un peu plus de réflexion. On va devoir en effet déclarer des variables, faire des affectations, écrire des expressions de calculs, des conditions et des boucles.

Expressions et fonctions

Exercice 2

Récupérez le programme Heures en cliquant ce lien.

Vous devez compléter la fonction chaineDe en réalisant le calcul des valeurs des heures, minutes et secondes.

Par exemple, si la valeur qui est passée en paramètre (le nombre total de secondes) est 4000, comme 4000 secondes = 1 h, 6 mn et 40 s, vous devez calculer ces trois valeurs 1, 6 et 40 et les ranger dans les variables correspondantes. L’instruction return de chaineDe assemble ces valeurs pour former la chaîne qui est renvoyée comme valeur de la fonction. Ainsi, pour le paramètre 4000, la fonction chaineDe va renvoyer la chaîne 1 : 6 : 40.

Indications : Si a et b sont deux int positifs, l’expression a / b calcule le quotient (entier) de a par b et l’expression a % b calcule le reste (entier) de la division de a par b.

La fonction main affiche la valeur de retour de chaineDe pour quelques exemples. Vous devez obtenir la sortie suivante :

0 : 0 : 0
0 : 0 : 1
0 : 0 : 59
0 : 1 : 0
0 : 1 : 59
0 : 2 : 0
0 : 59 : 59
1 : 0 : 0
1 : 0 : 1
1 : 6 : 40
23 : 59 : 59

Déposez ici votre programme Heures.java (assurez vous de bien sélectionner le programme Heures.java qui se trouve dans le répertoire des sources de VSCode, et pas la version initiale qui pourrait se trouver par exemple dans le répertoire de téléchargement).

Exercice 3

De manière similaire à la classe TC, on installe le paquetage MacLib. Le programme de test associé permet de vérifier la bonne installation.

Récupérez ensuite la classe DessinHorloge. Vous ne devez pas modifier cette classe mais seulement utiliser ses fonctions tracerHeures, tracerMinutes et tracerSecondes. Vous devez donc lire leur documentation pour leur passer les bons paramètres.

Récupérez ensuite le programme Horloges.

Vous devez compléter la fonction tracerAiguilles pour réaliser l’affichage graphique de l’heure. Cette fonction ne doit pas afficher de texte sur la console. Il faut calculer la position angulaire de chaque aiguille et passer cette valeur en paramètre à la fonction tracer... correspondante. Toute la difficulté de cet exercice réside dans un calcul rigoureux qui utilise correctement les particularités de l’arithmétique en Java lorsque l’on combine des entiers et des flottants.

Le saviez vous ? Dans une horloge, les aiguilles des minutes et des heures avancent d’un petit cran à chaque seconde. Il s’agit de reproduire ce mécanisme.

Le résultat attendu est le suivant (vérifiez bien la position de vos aiguilles) :

On voit notamment sur l’exemple de gauche que la position attendue de l’aiguille des heures n’est pas la verticale (angle 0) mais qu’elle s’est déplacée de l’angle correspondant à la fraction d’heure que représentent 33 minutes et 20 secondes. De même, l’aiguille des minutes n’est pas exactement à la position qui correspond à 33, mais elle est un peu décalée du fait des 20 secondes.

Déposez ici votre programme Horloges.java.

Exercice 4

Ajoutez à la classe Heures une fonction public static int lireEntier(String invite) qui doit :

  1. afficher le texte donné par le paramètre invite sur la console, en utilisant TC.print,
  2. lire une valeur entière entrée au clavier, en utilisant TC.lireInt();
  3. renvoyer cette valeur comme résultat de la fonction.

Vous devez tester. Par exemple, en mettant ces instructions :

    String message = "combien de secondes ? ";
    int secondes_1 = lireEntier(message);
    TC.println(chaineDe(secondes_1));
    int secondes_2 = lireEntier(message);
    TC.println(chaineDe(secondes_2));
    TC.print("total = ");
    TC.println(chaineDe(secondes_1+secondes_2));

dans la fonction main de la classe Heures, on doit obtenir :

combien de secondes ? 2000
0 : 33 : 20
combien de secondes ? 6000
1 : 40 : 0
total = 2 : 13 : 20

où c’est l’utilisateur qui a choisi d’entrer au clavier les valeurs 2000 et 6000 à la fin de la première et de la troisième ligne. Notez que l’espace après le ? est celui qui est inclus dans le message d’invite. Notez aussi qu’il n’y a pas de retour à la ligne à la fin de ce message. Lorsque l’exécution de TC.lireInt() commence, le curseur est donc placé en bout de ligne, après l’espace qui suit le ? et l’exécution de TC.lireInt() se fige dans l’attente d’une entrée au clavier. Le 2000 qui s’affiche est un écho de l’entrée au clavier et cet écho inclut le retour à la ligne qui valide cette entrée. C’est pourquoi TC.println(chaineDe(...)); commence à écrire au début de la nouvelle ligne. Le retour à la ligne inhérent à la définition de println se fait à la fin de son écriture.

Déposez ici Heures.java.

Exercice 5

On veut maintenant pouvoir lire une durée sous la forme de trois entiers qui donnent respectivement les heures, les minutes et les secondes. Ajoutez à la classe Heures une fonction public static int lireHMS(String invite) qui affiche le texte donné par le paramètre invite en utilisant les fonctions de la classe TC, lit 3 entiers et renvoie le nombre total de secondes correspondant.

Indication : L’utilisateur peut placer les 3 nombres sur une même ligne et le programme les récupérera au cours de 3 appels à TC.lireInt(). Par exemple, une exécution de ces deux instructions :

    int secondes = lireHMS("entrer heures minutes secondes : ");
    TC.println(secondes);

pourra donner :

entrer heures minutes secondes : 0 33 20
2000

Dans cet exemple, quand l’utilisateur aura entré 0 33 20, le premier appel à lireInt va “consommer” le 0 et il n’ira pas au delà du blanc qui suit, le deuxième appel à lireInt va, sans attendre, “consommer” le 33 qui est déjà disponible, etc. Finalement, la fonction lireHMS renverra la valeur 2000,
c’est le nombre de secondes qui correspond à 33 minutes et 20 secondes. Dans le test ci-dessus, cette valeur est ensuite affichée par l’instruction TC.println(secondes);. Sans changer le code de lireHMS, on pourrait aussi entrer les données de la manière suivante et obtenir le même résultat :

entrer heures minutes secondes : 0
33
20
2000

Vous devez tester. Modifiez la fonction main de la classe Heures pour permettre une exécution de ce type :

entrer heures minutes secondes : 0 33 20
entrer heures minutes secondes : 1 40 0
total = 2 : 13 : 20

Il s’agit de faire la somme de deux durées qui sont entrées sous la forme de 3 entiers (heures, minutes et secondes). En utilisant les fonctions déjà écrites, une simple addition suffit.

Déposez ici Heures.java.

Représentation binaire

Exercice 6

On veut calculer la décomposition binaire b3b2b1b0 des entiers de 0 à 15. Complétez le programme Binaire pour réaliser cette décomposition et afficher le résultat :

0000 = 0
0001 = 1
0010 = 2
0011 = 3
0100 = 4
...
1111 = 15

Indication : Ces calculs peuvent se faire simplement en utilisant le quotient et le reste de divisions euclidiennes. Il y a aussi une solution plus “geek” consistant à utiliser les opérateurs de décalage et de masquage bit-à-bit définis sur les entiers.

Déposez ici Binaire.java.

Logique, conditionnelles et boucles

Exercice 7

Le codage hexadécimal permet de représenter les nombres de 0 à 15, soit un groupe de 4 bits, par un seul chiffre noté de 0 à 9 puis de A à F. On s’intéresse ici à la programmation d’un afficheur à 7 segments pour les chiffres hexadécimaux, comme illustré dans la figure ci-dessous.

On vous donne la classe Afficheur7Segments (à ne pas modifier) qui réalise les graphiques, et la classe AffichageHexadecimal à compléter pour obtenir l’affichage attendu. Pour chaque affichage d’un chiffre hexadécimal, la fonction public static boolean allumeSegment(int segment, int chiffre) est appelée pour chaque segment afin de déterminer s’il doit être allumé ou non. Les segments sont numérotés de 0 à 6 selon la convention suivante :

Vous devez compléter la fonction allumeSegment; la valeur de retour sera true quand, pour afficher le chiffre considéré, le segment doit être allumé (en vert) et false dans le cas contraire (le segment est alors en noir).

Indication : On pourra par exemple enchaîner des instructions conditionnelles du genre :

    if ( segment == 1 ) {
      return chiffre <= 4 || 7 <= chiffre && chiffre <= 10 || chiffre == 13;
    }

Rappel : en Java, l’opérateur booléen et se note && et il a une priorité supérieure à l’opérateur booléen ou qui se note ||. Notez qu’il est possible de placer des return dans les instructions conditionnelles, ce qui permet de séparer les cas.

Déposez ici AffichageHexadecimal.java.

Exercice 8

Une année est dite bissextile si elle comporte un 29 février. C’est le cas de toutes les années divisibles par 4, à l’exception de celles divisibles par 100, qui ne sont bissextiles que si elles sont également divisibles par 400.

Écrivez une classe Bissextile avec une fonction estBissextile qui prend en paramètre un nombre entier qui est l’année à tester, et qui renvoie true si cette année est bissextile et false sinon.

Ajoutez une fonction public static void affichage(int annee) qui prend en paramètre l’année à tester et qui affiche un message indiquant en clair si l’année est bissextile ou non.

La fonction main de votre programme sera, par exemple :

  public static void main(String[] args) {
    affichage(1900);
    affichage(1901);
    affichage(1904);
    affichage(2000);
    affichage(2024);
  }

Pour cet exemple, l’exécution donne :

1900 n'est pas bissextile.
1901 n'est pas bissextile.
1904 est bissextile.
2000 est bissextile.
2024 est bissextile.

Vous devez respecter exactement le format d’affichage attendu, avec un seul espace de séparation entre les mots et pas d’espace en fin de ligne. Toutes les lignes sont terminées par un point et un retour à la ligne, y compris la dernière.

Indication : Il est rentable de réfléchir quelques minutes à l’imbrication des conditionnelles avant de se lancer dans la programmation. Veillez à tester toutes les branches de votre programme.

Déposez ici Bissextile.java.

Exercice 9

On veut maintenant pouvoir utiliser les fonctions écrites à l’exercice précédent sur autant d’années que l’on veut, sans devoir modifier le programme à chaque fois. On va considérer que l’utilisateur entre au clavier autant d’années positives qu’il veut, et que lorsqu’il souhaite arrêter le programme, il entre alors une valeur strictement négative. Dans ce cas, le programme affiche Au revoir. et s’arrête.

Par exemple, une exécution donne quelque chose comme :

Entrer une valeur : 1900
1900 n'est pas bissextile.
Entrer une valeur : 2000
2000 est bissextile.
Entrer une valeur : -1
Au revoir.

Écrivez un nouveau programme BoucleBissextile avec une fonction main qui utilise les fonctions de la classe Bissextile. Les opérations d’écriture se feront en utilisant les fonctions TC.print(…) et TC.println(…) à votre convenance. Il ne faut pas utiliser les fonctions similaires System.out.print(…) et System.out.println(…). Vous devez respecter exactement le texte et format d’affichage attendu, avec un seul espace de séparation entre les mots et pas d’espace en fin de ligne (mais notez que l’espace après le : doit être écrit par le programme). Toutes les lignes, y compris la dernière, sont terminées par un retour à la ligne.

Indication : Vous devez structurer votre programme à l’aide d’une boucle while (annee >= 0) { ... } en déclarant correctement la variable annee, en l’affectant au bon moment par des appels à TC.lireInt() et en complétant le corps de la boucle avec des appels aux fonctions de Bissextile.

Déposez ici BoucleBissextile.java.

Nombres non entiers

Exercice 10

Écrivez un programme (dans Racines.java) qui calcule et qui affiche les racines réelles d’un polynôme ax2 + bx + c. On distinguera les différents cas selon le nombre de racines. On pourra supposer que a est non nul.

Les valeurs de a, b et c seront de type double et seront introduites par TC.lireDouble().

Écrivez toutes les fonctions qui vous semblent utiles. Cet exercice ne fait pas l’objet d’une correction automatique et vous pouvez structurer votre programme comme bon vous semble.

Voici quelques exemples pour tester, vous pouvez aussi en améliorer la présentation :

Entrer a b c : 1 1 1
Discriminant = -3.0
Pas de racine
Entrer a b c : 1 -2 1
Discriminant = 0.0
Racine double : 1.0
Entrer a b c : 3 2 -1
Discriminant = 16.0
Deux racines : -1.0 et 0.3333333333333333
Entrer a b c : 0.3 0.2 -0.1
Discriminant = 0.16
Deux racines : -1.0000000000000002 et 0.33333333333333337
Entrer a b c : 0.03 0.02 -0.01
Discriminant = 0.0015999999999999999
Deux racines : -1.0 et 0.33333333333333337

Une explication des résultats obtenus sur les deux derniers exemples (en comparaison aux racines mathématiques  − 1 et 1/3) est que les fractions décimales n’ont pas de représentation binaire exacte. Ces résultats peuvent varier légèrement selon la manière de les calculer.

Déposez ici votre programme (il n’y a pas de validation automatique et il sera examiné par vos enseignants).