Objectifs: Le but de ce TD est de vous faire expérimenter les constructions de base du langage JavaScript (types simples, déclarations de variables, instructions de contrôle, itérations) qui sont très proches syntaxiquement de celles utilisées par le langage C. Les programmes que vous aurez à écrire ne font appel qu'aux constructions de base du langage JavaScript (Core JavaScript) mis à part pour la lecture de valeurs au clavier. C'est pourquoi afin de simplifier leur écriture et leur exécution, vous utiliserez l'environnement Node.js qui vous affranchira de l'intégration de vos scripts dans du code HTML et de l'utilisation d'un navigateur.

Les exercices proposés dans ce TP sont indépendants et sont organisés selon 4 thèmes thèmes : expressions , instructions conditionnelles, itérations, fonctions. Une 5ème partie propose un ensemble d'exercices facultatifs que vous pourrez réaliser pour vous entrainer.

Ressources utiles

Prenez dès maintenant de bonnes habitudes de codage JavaScript. Il vous est demandé de respecter impérativement les 3 règles ci-dessus.

  1. tout programme source JavaScript doit avoir comme suffixe .js.
  2. Les noms de variables et de fonctions sont définis par un identificateur débutant par une minuscule (camelCase).
  3. Les programmes doivent être correctement indentés. (Utilisez l'outil d'identation automatique de VSCode !)

0. Préparation de l'environnement de développement

1. Créer et exécuter un programme JavaScript

Pour la réalisation de ce TP vous avez besoin d'un éditeur de texte et d'un environnement Javascript (Node.js). Pour exécuter un programme JavaScript contenu dans un fichier monProgramme.js il suffit d'ouvrir un terminal dans le répertoire contenant ce fichier et d'éxécuter la commande

node monProgramme.js

Cependant il est possible de tout faire depuis l'IDE VScode comme le montre les figures ci-dessous

Création d'un fichier JavaScript avec VSCode

VScode utilise IntelliSense pour l'édition du code et offre de nombreuses possibilités d'autocomplétion du code comme indiqu sur la figure ci dessous.

Autocomplétion du code JavasScript dans VSCode

Une fois votre code écrit et enregistré vous pouvez directement l'exécuter en ouvrant un terminal dans VSCode et en invoquant l'interpréeteur de Node.js

Exécution d'un fichier JavaScript avec Node.js depuis VSCode

2. Lire des données au clavier avec readline-sync

console.log est une fonction standard de JavaScript qui permet d'afficher du texte sur la console de votre environnement d'exécution JavaScript (que ce soit un navigateur ou Node.js). Par contre, Core Javascript tel qu'il est défini par le standard ECMAScript ne définit pas de moyen de saisir des données à partir du clavier. La manière de procéder va dépendre de votre environnement d'éxécution. En ce qui concerne Node.js, nous allons utiliser un module complémentaire (readline-sync) qu'il va falloir installer à l'aide de npm, le gestionnaire de paquets officiel de Node.js (voir Node.js NPM).

Installation et utilisation du module readline-sync pour les lectures au clavier

Une fois readline-sync installé, pour pouvoir l'utiliser dans vos programmes il vous faudra procéder en deux temps

  1. importer le module à l'aide d'une instruction require que vous placerez au debut de votre programme
    const readline = require('readline-sync');
  2. ensuite pour invoquer l'une des fonction du module il suffit de préfixer l'appel par readline.. Par exemple :
    let prenom = readline.question("entrez votre prénom ");
    permet d'invoquer la fonction question qui affiche un message sur la console et attend un réponse de l'utilisateur. Une fois que l'utilisateur a entré sa réponse la valeur de celle-ci est renvoyée et ici est stockée dans la variable prenom.

    readline-sync propose différentes fonctions (méthodes) selon la nature de la valeur que vous voulez saisir.

    • question() qui renvoie une chaîne de caractères (valeur de type string)
    • questionInt() qui renvoie une valeur entière (valeur de type number)
    • questionFloat() qui renvoie une valeur réelle (valeur de type number)

    Se référer à la documentation de readline-sync pour voir le detail des ces fonctions et leurs différents paramètres d'appel.

Thème 1 : Expressions

Exercice 1 : Conversion de températures

En utilisant la formule \(tempC = (5/9)(tempF-32)\) écrire en langage JavaScript un programme degres.js qui lit une température exprimée en degrés Fahrenheit et affiche sa valeur en degrés centigrades ou degrés Celsius.

Exemples d'exécution du programme (en vert les valeurs introduites par l'utilisateur) :

P:\PLAI\TP5>node degres.js
donnez une temperature en Fahrenheit : O.O
cette temperature equivaut a -17.8 degres Celsius
P:\PLAI\TP5>node degres.js
donnez une temperature en Fahrenheit : 60.0
cette temperature equivaut a 15.6 degre Celsius
P:\PLAI\TP5>

Par défaut, lorsqu'un nombre flottant est affiché sur la console, tous les chiffres qu'il contient après le séparateur décimal apparaissent. Ainsi le code

let x = 17/7;
console.log("x = " + x);

donne l'affichage suivant

x = 2.4285714285714284

Il est néanmoins possible de formatter les nombres pour fixer le nombre de chiffres à conserver après le point décimal à l'aide de la méthode toFixed (voir w3schools ou MDN)

Exercice 2 : Conversion de durées

Ecrire un programme hjms.js en langage JavaScript qui pour un nombre de secondes donné calcule et affiche son équivalent en nombre de jours, d'heures, de minutes et de secondes.

exemples d'exécution du programme :

P:\PLAI\TP5>node hjms 
donnez une durée en secondes : 235789
cette durée equivaut à 2 jours 17 heures 29 minutes 49 secondes  
P:\PLAI\TP5>node hjms 
donnez une durée en secondes : 567231 
cette durée équivaut à 6 jours 13 heures 33 minutes et 51 secondes 
P:\PLAI\TP5>

L'opérateur % (modulo) permet d'obtenir le reste de la division entière de deux nombres. Par exemple

console.log("17 % 7 --> " + 17 % 7);
console.log("17 / 7 --> " + 17/7);

donne l'affichage suivant

17 % 7 --> 3
17 / 7 --> 2.4285714285714284

Pour obtenir la division entière de 17 par 7 (qui vaut 2) il faut passer par la méthode Math.floor (voir w3schools ou MDN)

Thème 2 : Instructions conditionnelles

Exercice 1 : Améliorer le programme de conversion de durées

Si ce n'est déjà fait, améliorez votre programme hjms.js de sorte que lorsqu'une valeur (nombre de jours, d'heures , de minutes ou de secondes) est nulle elle n'apparaisse pas dans l'affichage, et que si elle vaut 1 l'unité soit affichée au singulier (sans s) comme dans l'exemple ci-dessous.

P:\PLAI\TP5>node hjms 
donnez une durée en secondes : 3621 
Cette durée equivaut à 1 heure 21 secondes 
P:\PLAI\TP5>

Exercice 2 : Classer 3 nombres

Ecrire un programme troisNombres.js qui lit 3 nombres au clavier et les affiche sur la console dans l'ordre croissant (du plus petit au plus grand).

P:\PLAI\TP5>node troisNombres
1er nombre : 14
2ème nombre : 10
3ème nombre : 17
les nombres dans l'ordre croissant : 10 14 17
P:\PLAI\TP5>

Thème 3 : itérations

Exercice 1 : Affichage de motifs - escaliers

Ecrire un programme qui affiche un motif triangulaire dont la taille est fixée par une valeur lue au clavier.

Exemple de trace d'exécution:

P:\PLAI\TP5>node  triangle1
donnez taille du motif : 7
*
**
***
****
*****
******
*******
P:\PLAI\TP5>

a) écrire un programme triangle1.js affichant ce motif en utilisant uniquement des instructions tant que (while()).

b) écrire un programme triangle2.js affichant ce motif en utilisant uniquement des instructions pour (for).

Exercice 2 : Affichage de motifs - pyramides

Même exercice que le précédent mais le motif affiché n'est plus un triangle mais une pyramide (voir ci-dessous) et le choix des instructions pour le réaliser est laissé à votre jugement.

Exemple de trace d'exécution (en vert les valeurs introduites par l'utilisateur):

P:\PLAI\TP5>node pyramide
donnez taille du motif : 7
      *
     ***
    *****
   *******
  *********
 *********** 
*************
P:\PLAI\TP5>

Thème 4 : fonctions

Exercice 1 : Moyenne olympique

Sans utiliser de tableau écrire un programme moyenneOlympique.js qui lit au clavier une suite de nombres réels positifs ou nuls (correspondant à des notes comprises entre 0 et 10), terminée par la valeur -1, et calcule la moyenne olympique de ces valeurs, c'est à dire la moyenne des notes sans prendre en compte la note la plus élevée ni la note la moins élevée (c'est ce qui se passe dans les compétitions de gymnastique ou de patinage artistique pour limiter les abus dans la notation).

Exemple de trace d'exécution (en vert les valeurs introduites par l'utilisateur):

P:\PLAI\TP5>node moyenneOlympique.js
Donner un note entre 0 et 10 (-1 pour terminer la saisie) : 7.89
Donner un note entre 0 et 10 (-1 pour terminer la saisie) : 8.76
Donner un note entre 0 et 10 (-1 pour terminer la saisie) : 8.45
Donner un note entre 0 et 10 (-1 pour terminer la saisie) : 9.10
Donner un note entre 0 et 10 (-1 pour terminer la saisie) : 7.75
Donner un note entre 0 et 10 (-1 pour terminer la saisie) : 9.30
Donner un note entre 0 et 10 (-1 pour terminer la saisie) : 7.50
Donner un note entre 0 et 10 (-1 pour terminer la saisie) : -1

Nombre de notes saisies 7
La note la plus élevée (9.3)et la note plus basse (7.5) ont été retirées
La moyenne olympique est : 8.39
P:\PLAI\TP5>

Pour la lecture de la séquence de notes, vous écrirez une fonction lireNote qui vérifie que les données saisies sont correctes. Les traitements effectués par cette fonctions sont les suivants:

  1. afficher le message d'invite (prompt) indiquant l'intervalle de validité des notes et la valeur de fin de séquence.
  2. lecture d'une valeur
  3. vérification que cette valeur est bien dans l'intervalle de valeurs autorisées ou est égale à la valeur de fin de séquence. Si c'est le cas la valeur lue est retournée, sinon un message d'erreur est affiché est une nouvelle valeur est demandée à l'utilisateur.

Exercice 2: Introduction aux modules

Dans les programmes degres.js et hjms.js, vus lors de l'exercice 1, il n'est possible de faire qu'une seule saisie. Si l'utilisateur veut effectuer plusieurs conversions, il doit relancer l'exécution du programme. On souhaite modifier le comportement de ces programmes de manière à ce que l'utilisateur puisse renouveler le traitement jusqu'à ce qu'il dise explicitement qu'il désire terminer l'exécution. Le déroulement de l'exécution de ces programmes serait alors le suivant :

P:\PLAI\TP5>node degres2.js
donnez une température en degrés Fahrenheit : 32
la température en degrés Celsius est 0.00
voulez-vous recommencer ?  (O/N): O
donnez une température en degrés Fahrenheit : 45
la température en degrés Celsius est 7.22
voulez-vous recommencer ?  (O/N): 33
désolé nous n'avons pas compris votre réponse 
voulez-vous recommencer ?  (O/N): o
donnez une température en degrés Fahrenheit : 23
la température en degrés Celsius est -5.00
voulez-vous recommencer ?  (O/N): n
Au revoir !

P:\PLAI\TP5>node hjms
entrez une durée (en sec.) : 345678
Cette durée equivaut à 4 jours 1 minute 18 secondes 
encore ?  (O/N): o
entrez une durée (en sec.) : 3567912
Cette durée equivaut à 41 jours 7 heures 5 minutes 12 secondes 
encore ?  (O/N): p
désolé nous n'avons pas compris votre réponse 
encore ?  (O/N): n
P:\PLAI\TP5>

a) Pour cela vous allez écrire une fonction encore qui affiche un message demandant à l'utilisateur si il veut poursuivre ou non le traitement et qui selon la valeur saisie retourne un booléen (true si il veut poursuivre, false sinon). .

Dans un premier temps écrivez et testez cette fonction dans le programme degres.js.

b) Ensuite pour pouvoir utiliser cette fonction dans d'autres programmes (par exemple hjms.js) il vaut mieux l'isoler dans un module que vous pourrez importer à la manière du module readline-async utilisé pour les lectures au clavier. Pour cela procédez comme suit :

  1. créez un fichier utils.js
  2. effacez la function encore du fichier degres.js et récopiez son code dans utils.js
  3. modifiez la signature de la fonction en utilisant une directive exports et une fonction anonyme comme indiqué ci dessous
    // pour utiliser le module readline
    const readline = require('readline-sync');
    
    exports.encore = function(message) {
       .... les instructions de la fonction
    }
  4. pour utiliser la fonction dans un autre de vos programmes, utilisez une instruction require comme pour readline-async pour déclarer le module
    const utils = require('./utils.js');
    ...
    utils.encore("encore ? ");  // pour appler la fonction
    

Modifiez les programmes degres.js et hjms.js pour permettre à l'utilisateur d'effectuer autant de traitements qu'il le souhaite.

5: Autres exercices

Exercice 1 : Tester si un nombre est premier

Un nombre est n premier si il a seulement deux diviseurs : 1 et n.

Ecrire un programme Premier.js qui permet de tester si un nombre introduit par l'utilisateur est premier ou non.

Exemple de trace d'exécution (en vert les valeurs introduites par l'utilisateur):

P:\PLAI\TP5>node Premier
donnez un entier positif  : 7
7 est un nombre premier

Voulez-vous essayer un autre nombre O/N ? o

donnez un entier positif  : 25
25 n'est pas un nombre premier, il est divisible par 5

Voulez-vous essayer un autre nombre O/N ? n
Au revoir
P:\PLAI\TP5>

Exercice 2 : Suite de Fibonacci

La suite de Fibonacci est définie par la formule de récurrence suivante: u0 = 0 u1 = 1 un = un-1 + un-2 (n >= 3).

a) Ecrire un programme Fibo1.js qui permet de calculer le nième terme de la suite de Fibonacci, n étant fixé par l'utilisateur.

b) Ecrire un programme Fibo2.js qui permet d'obtenir la valeur et le rang du premier terme de cette suite supérieure à une valeur donnée par l'utilisateur.

Exercice 3 : Prix d'un lot

a) Le jeu consiste à découvrir par essais successifs le prix d'un lot . Pour chaque essai, le joueur reçoit un message : "Trop grand", "Trop petit" ou "BRAVO ! Vous avez trouvé en K essais". Le jeu est fini quand le joueur a trouvé le prix du lot.

On propose d'écrire un programme JavaScript PrixLot1.js qui joue le rôle de meneur de jeu ; l'exécution de ce programme vous fera tenir le rôle du joueur. Le programme Prixlot1doit définir le prix du lot en tirant un entier aléatoire entre 1 et 1000 et dialoguer avec le joueur pendant le jeu.

Pour choisir un nombre au hasard on utilisera la méthode random de la classe Math qui retourne un réel (double) tiré au hasard et de manière uniforme dans l'intervalle [0 1].

exemple :

double x; x = Math.random();

exemple d'exécution du programme PrixLot1

P:\PLAI\TP5>node PrixLot1
Le but est de chercher un prix entre 0 et 1000
Tapez un prix : 566 
Trop grand
Tapez un prix : 400 
Trop grand
Tapez un prix : 150 
Trop petit
Tapez un prix : 200
Trop petit
Tapez un prix : 214
BRAVO ! Vous avez gagné en 5 essais
P:\PLAI\TP5>

b) Copier dans le fichier PrixLot2.js le fichier PrixLot1.js, et modifier PrixLot2.js de manière à pouvoir :

  • enchaîner plusieurs jeux consécutifs lors d'une même exécution du programme (à la fin de chaque jeu, il est demandé au joueur de préciser s'il veut s'arrêter ou rejouer)

  • limiter le nombre d'essais du joueur lors d'une partie (au début de chaque partie, le programme demandera le nombre maximum d'essais autorisés).

Exemple d'exécution du porgramme PrixLot2

P:\PLAI\TP5>node PrixLot2 
Le but est de chercher un prix entre 0 et 1000
1ère partie. Nombre maximum d'essais : 4
Tapez un prix : 678
Trop petit
Tapez un prix : 920
Trop grand
Tapez un prix : 860
Trop petit 
Tapez un prix : 910
Trop petit
PERDU ! Vous avez épuisé le nombre d'essais autorisés
Le prix était : 917
                                
Voulez-vous rejouer O/N ? o
2ème partie. Nombre maximm d'essais : 8
Tapez un prix : 678
Trop grand
Tapez un prix : 333
Trop grand
Tapez un prix : 300
Trop petit
Tapez un prix : 320
Trop petit
Tapez un prix : 324
BRAVO !
Vous avez gagné en 5 essais

Voulez-vous rejouer O/N ? n
P:\PLAI\TP5>

c) En jouant avec le programme précédent, essayer de trouver une stratégie systématique et efficace. Ecrire un programme PrixLot3.js qui fait jouer l'ordinateur à votre place suivant la tactique que vous venez de définir ; les deux rôles de meneur de jeu et de joueur sont donc à la charge du programme, le joueur "ignorant" évidemment le prix connu du meneur de jeu, mais "sachant" si son essai est plus grand ou plus petit que le prix.

Le programme PrixLot3 effectue 20 parties ; il affiche pour chaque partie le prix tiré au sort et le nombre d'essais successifs qui ont été nécessaires pour le trouver avec la tactique programmée.

Pouvez-vous prévoir, pour la tactique que vous avez choisie, l'ordre de grandeur des nombres d'essais ? Compléter le programme PrixLot3 en lui faisant calculer la moyenne des 20 nombres d'essais obtenus pour les 20 parties.

Exercice 4 : Valeur approchée de la racine carrée d'un nombre réel positif

On considère un nombre réel positif A ; on sait que la suite (un) n=0,1,2,... définie par la donnée d'un réel u0 positif et par la relation de récurrence un = (un-1 + A / un-1) * 0,5 (pour n > 0) converge vers la racine carrée de A . On suppose le nombre A compris entre 1 et 100, et on prend u0 = A / 2.

Pour obtenir une valeur approchée de racine carrée de A, on cherche le premier terme un tel que | un2 - A | < E-5 . Le nombre trouvé est une valeur approchée de racine carrée de A ( en effet | un2 - A | < E-5 implique que | un- rac(A) | < E-5 / ( un+ rac(A) où rac(A) correspond à la racine carrée de A).

a) Ecrire un programme JavaScript Raca1.js qui permet

  1. de lire le nombre A,

  2. de calculer et d'afficher les approximations intermédiaires et la valeur approchée de la racine carrée de A définie ci-dessus.

Exemple de l'état de l'écran obtenu par exécution du programme Raca1 :

Entrer un nombre A entre 1 et 100: 19.23 
Approximations successives :
u0 = 9.615
u1 = 5.8075
u2 = 4.559367735686612
u3 = 4.388528900180239
u4 = 4.385203650605606 
Valeur approchée de la racine carrée  = 4.385202389856321
Indications pour écrire le programme :
  • définir une constante : static final double EPS = 1E-5;
  • utiliser une boucle tant que :
    while (. . . . . . . >= EPS) {
          . . . . . . . . . 
      }

b) à partir du programme Raca1.js écrire un programme Raca2.js qui vérifie que le nombre introduit au clavier est bien un nombre positif supérieur à 1, et dans le cas contraire affiche un message d'erreur et redemande une nouvelle valeur à l'utilisateur.