III. TP 3 : Algorithmes et Jeux▲
Objectifs :
- Création d'algorithmes à l'aide de boucles
- Savoir développer des jeux simples
III-A. Algorithmes▲
III-A-1. Définition de Wikipédia▲
« Un algorithme est une suite finie et non ambiguë d'opérations ou d'instructions permettant de résoudre un problème ou d'obtenir un résultat. »
Une recette de cuisine peut être réduite à un algorithme, si on peut réduire sa spécification aux éléments constitutifs :
- des entrées (les ingrédients, le matériel utilisé) ;
- des instructions élémentaires simples, dont l'exécution amène au résultat voulu ;
- un résultat : le plat préparé.
Un casse-tête, tel le Rubik's Cube, peut être résolu de façon systématique par un algorithme qui mécanise sa résolution.
Illustration : algorithme de résolution de Rubik's Cube.
III-A-2. Autre définition, plus concrète, de Gérard Berry▲
« Un algorithme, c'est tout simplement une façon de décrire dans ses moindres détails comment procéder pour faire quelque chose. […] Le but est d'évacuer la pensée du calcul, afin de le rendre exécutable par une machine numérique (ordinateur…). On ne travaille donc qu'avec un reflet numérique du système réel avec qui l'algorithme interagit. »
III-B. Boucles for en JavaScript▲
III-B-1. Qu'est-ce qu'une boucle ?▲
Une boucle permet de répéter plusieurs fois une séquence d'instructions.
Pour afficher les nombres de 1
à 3
dans la console JavaScript, on pourrait utiliser les instructions suivantes :
2.
3.
console.log
(
1
);
console.log
(
2
);
console.log
(
3
);
Et ça fonctionne très bien !
Par contre, le code deviendrait très fastidieux à écrire (et à lire) dans le cas où on voudrait afficher les nombres de 1
à 10000
!
Pour ce genre de répétition, le mot-clé for permet de définir une seule fois les instructions qui doivent être répétées, puis de spécifier combien de fois on souhaite qu'elles soient répétées.
Pour afficher les nombres de 1
à 10000
, il suffit donc d'écrire le code suivant :
On pourrait traduire ce code de la manière suivante :
Pour chaque valeur de monNombre, croissant de 1
à 10000
(compris), afficher la valeur de monNombre dans la console.
III-B-2. À quoi servent les boucles ?▲
Les boucles sont donc très utiles pour éviter les redondances dans un programme (ex. : jouer cinq fois le même son, mettre tous les champs d'un formulaire en majuscules…), mais elles sont surtout indispensables dans de nombreuses applications courantes :
- les jeux tour-par-tour consistent en une boucle qui se termine lorsqu'un joueur remporte la partie ;
- les jeux d'action utilisent une boucle permettant de mettre à jour l'affichage (frame par frame, pour utiliser la terminologie exacte) en fonction des actions du/des joueur(s) ;
- ainsi que les algorithmes de tri et de manipulation de données utilisés dans 99 % des logiciels.
JavaScript fournit quatre mots-clés pour définir des boucles : do, while, until et for. La forme de boucle la plus courante est for, car c'est la plus générique / adaptable. Nous allons donc seulement travailler avec des boucles for dans le cadre de ce cours.
III-B-3. Anatomie d'une boucle for en JavaScript▲
Reprenons l'exemple de boucle que nous avons vu plus haut :
Cette boucle est définie par :
- l'usage du mot-clé for;
- une liste d'instructions (saisie entre accolades
{}
) à répéter tant que la condition est vraie : console.log
(
monNombre );
(dans notre exemple, il n'y a qu'une seule instruction, mais on peut en mettre une infinité) ; - une condition (expression conditionnelle, comme dans une condition if) : monNombre
<=
10000
; - une instruction d'itération qui sera exécutée après chaque itération de la boucle : monNombre
++
(qui, ici, incrémente la valeur de monNombre, c'est-à-dire augmente sa valeur de1
) ; - et une instruction d'initialisation qui ne sera exécutée qu'une seule fois : var monNombre
=
1
(ici, on créée une variable monNombre et on lui affecte la valeur initiale1
).
On appelle itération chaque répétition de la boucle.
Pour synthétiser, voici la syntaxe à utiliser pour définir une boucle for en JavaScript :
2.
3.
for(
/* initialisation */
;
/* condition */
;
/* incrémentation */
) {
/* instructions à répéter */
}
À noter que, dans la plupart des cas, les boucles sont utilisées pour itérer :
- sur un intervalle (dans notre exemple : nombres entiers entre
1
et10000
), - ou sur une énumération de valeurs (ex. : un tableau/Array, comme on le verra plus tard).
III-B-4. Traçage de l'exécution d'une boucle for▲
Afin de mieux comprendre le fonctionnement de la boucle for et de la manière de saisir ces trois paramètres, nous allons interpréter une boucle comme le fait un navigateur web (ou tout autre interpréteur JavaScript).
Prenons la boucle for suivante :
Voici la manière dont elle va être interprétée et exécutée par la machine :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
console.log
(
'on va boucler'
);
// => affiche : on va boucler
// interprétation de la boucle => on commence par l'initialisation
var i =
0
;
// initialisation de la boucle, en affectant 0 à la variable i
// --- première itération de la boucle ---
i <
4
?
// condition vraie, car i vaut 0
console.log
(
'i'
,
i,
i <
4
);
// => affiche : i 0 true
i++;
// incrémentation => i vaut maintenant 1
// --- seconde itération de la boucle ---
i <
4
?
// condition vraie, car 1 < 4
console.log
(
'i'
,
i,
i <
4
);
// => affiche : i 1 true
i++;
// incrémentation => i vaut maintenant 2
// --- troisième itération de la boucle ---
i <
4
?
// condition vraie, car 2 < 4
console.log
(
'i'
,
i,
i <
4
);
// => affiche : i 2 true
i++;
// incrémentation => i vaut maintenant 3
// --- quatrième itération de la boucle ---
i <
4
?
// condition vraie, car 3 < 4
console.log
(
'i'
,
i,
i <
4
);
// => affiche : i 3 true
i++;
// incrémentation => i vaut maintenant 4
// --- cinquième itération de la boucle ---
i <
4
?
// condition fausse, car i==4 => fin de boucle
// boucle terminée => on interprète les instructions suivantes.
console.log
(
'on a fini de boucler'
);
// => affiche : on a fini de boucler
Il est très pratique de décomposer une boucle de cette manière lorsqu'elle ne se comporte pas comme voulu. (débogage)
III-B-5. Interrompre l'exécution d'une boucle : break▲
Dans certains cas, il est pratique d'interrompre l'exécution d'une boucle, pendant l'exécution d'une de ses itérations (telle que définie entre les accolades de définition de la boucle).
Cependant, l'usage de break est non recommandé, car il rend la logique plus complexe à comprendre en lisant le code. Il est généralement possible et plus élégant d'intégrer la condition de sortie dans la condition de la boucle.
Ici, on a intégré la condition à l'aide de l'opérateur logique &&
, donc la boucle continuera d'itérer tant que i <
10
ET que commande !==
'quitter'
.
III-B-6. Application : FizzBuzz▲
III-B-6-a. Algorithme à implémenter▲
À implémenter étape par étape :
- Écrire un programme qui affiche les nombres de
1
à199
(compris) dans la console. - Pour les multiples de
3
, afficher Fizz au lieu du nombre. - Pour les multiples de
5
, afficher Buzz au lieu du nombre. - Pour les nombres multiples de
3
et5
, afficher uniquement FizzBuzz.
Pour ne pas s'embrouiller, il est recommandé de :
- commencer par écrire la logique d'une seule itération, avant de la faire se répéter à l'aide d'une boucle ;
- écrire sous forme de pseudocode (en langue française), avant de l'implémenter en JavaScript.
III-B-6-b. Trace d'exécution de l'algorithme▲
On devrait obtenir les lignes suivantes dans la console :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
… et ainsi de suite, jusqu'à 199
.
III-B-6-c. Comment savoir si un nombre est multiple d'un autre ?▲
Pour savoir si un nombre est multiple de 3
et/ou de 5
, nous allons utiliser deux fonctions fournies ci-dessous :
Après avoir copié-collé la définition de ces deux fonctions dans la console JavaScript, vous pouvez les utiliser de la manière suivante :
2.
3.
4.
estMultipleDeTrois
(
2
);
// => retourne false, car 2 n'est pas multiple de 3
estMultipleDeTrois
(
6
);
// => retourne true, car 6 est un multiple de 3
estMultipleDeCinq
(
6
);
// => retourne false, car 6 n'est pas un multiple de 5
estMultipleDeCinq
(
15
);
// => retourne true, car 15 est un multiple de 5
Vous pouvez alors appeler ces fonctions dans les parenthèses de vos conditions if, car comme une expression de comparaison de valeurs, un appel de fonction retourne une valeur qui est vraie (true) ou fausse (false).
Exemple :
Solution
III-B-7. Application : Devine le nombre▲
III-B-7-a. Fonctionnement du jeu à implémenter▲
- En début de partie, l'ordinateur va choisir un nombre aléatoire entre
0
et100
. - Le joueur a droit à
10
tentatives pour deviner ce nombre. - À chaque tentative :
- La partie continue jusqu'à ce que le joueur gagne ou épuise ses
10
tentatives.
- si le nombre saisi est inférieur à celui de l'ordinateur, afficher Plus grand ;
- si le nombre saisi est supérieur à celui de l'ordinateur, afficher Plus petit ;
- si le joueur a réussi à deviner le bon nombre, afficher Bravo !
Pour implémenter ce jeu :
- vous allez avoir besoin d'interagir avec l'utilisateur, et donc d'utiliser les mots-clés
prompt
etalert
; - il est recommandé de commencer par écrire le code d'une seule itération (sans utiliser de boucle), et de le tester en donnant des valeurs arbitraires à vos variables, pour simuler chaque cas.
III-B-7-b. Exemple de déroulement d'une partie▲
2.
3.
4.
5.
6.
Nombre saisi par le joueur : 10
Réponse de l'ordinateur : Plus grand
Nombre saisi par le joueur : 20
Réponse de l'ordinateur : Plus petit
Nombre saisi par le joueur : 16
Réponse de l'ordinateur : Bravo !
III-B-7-c. Comment obtenir un nombre aléatoire▲
Pour obtenir un nombre aléatoire entier entre 0 et 100 :
Math.round
(
Math.random
(
) *
100
)
Libre à vous de stocker cette valeur dans une variable, si vous avez besoin de la comparer à d'autres valeurs, par exemple.