cours09 - sbalev/processing101 GitHub Wiki
L'itération est un ensemble de règles ou de pas qu'on applique de façon répétitive. C'est un concept fondamental dans la programmation qui, comme nous allons le découvrir bientôt, va rendre notre vie de codeurs délicieuse.
Dans un premier temps, pensez aux pattes. Beaucoup de pattes pour transformer votre créature en mille-pattes. Si on s'était arrêté à la première séance de ce cours, on aurait pu faire quelque chose comme dans l'exemple suivant.
Exemple 9.1. Plusieurs pattes
size(200, 200);
background(255);
stroke(0);
// Pattes
line( 50, 80, 50, 120);
line( 60, 80, 60, 120);
line( 70, 80, 70, 120);
line( 80, 80, 80, 120);
line( 90, 80, 90, 120);
line(100, 80, 100, 120);
line(110, 80, 110, 120);
line(120, 80, 120, 120);
line(130, 80, 130, 120);
line(140, 80, 140, 120);
line(150, 80, 150, 120);
Ce code dessine des pattes de x = 50 à x = 150 avec un écart de 10 pixels entre deux pattes consécutives. En utilisant des variables, on peut éliminer les valeurs codées en dur et améliorer le code.
Exemple 9.2. Pattes avec variables
int x = 50;
int y = 80;
int ecart = 10;
int longueur = 40;
size(200, 200);
background(255);
stroke(0);
// Pattes
line(x, y, x, y + longueur);
x += ecart;
line(x, y, x, y + longueur);
x += ecart;
line(x, y, x, y + longueur);
x += ecart;
line(x, y, x, y + longueur);
x += ecart;
line(x, y, x, y + longueur);
x += ecart;
line(x, y, x, y + longueur);
x += ecart;
line(x, y, x, y + longueur);
x += ecart;
line(x, y, x, y + longueur);
x += ecart;
line(x, y, x, y + longueur);
x += ecart;
line(x, y, x, y + longueur);
x += ecart;
line(x, y, x, y + longueur);
Pas si mal ! Maintenant on peut changer la position de la première patte, la longueur ou l'écart en faisant une seule modification. En plus, ce code était plus facile à produire en faisant copier-coller car les insructions pour dessiner chaque patte sont identiques. En revanche, on est passé d'une à deux instructions par patte. Si on veut faire un vrai mille-pattes, on aura 2000 instructions ! Pour éviter une tendinite, on a besoin de pouvoir dire à Processing quelque chose comme :
Dessine une ligne mille fois.
Notre problème est facilement résolu par des structures de contrôle appelées boucles. Processing (et Java) ont trois types de boucles : while
, for
et do-while
. En principe, on peut tout faire en utilisant uniquement while
. for
est juste un raccourci très pratique dans certaines situations. Quant au do-while
, il est rarement utilisé et nous l'ignorerons pour l'instant.
Source geektionerd
L'instruction while
ressemble à l'instruction if
. On évalue une expression booléenne et on exécute un bloc de code si celle-ci est vrai. Mais au lieu de passer à l'instruction suivante après l'exécution du bloc, on revient au test. Ainsi le bloc s'exécute tant que l'expression s'évalue à vrai.
Revenons à notre problème de pattes. En ajoutant deux variables xDebut
et xFin
et en utilisant while
, on peut réécrire l'exemple 9.2 ainsi.
Exemple 9.3. Pattes avec while
int xDebut = 50; // Où est-ce qu'on commence ?
int xFin = 150; // Où est-ce qu'on s'arrête ?
int x;
int y = 80;
int ecart = 10;
int longueur = 40;
size(200, 200);
background(255);
stroke(0);
// Pattes
x = xDebut;
while (x <= xFin) {
line(x, y, x, y + longueur);
x += ecart;
}
On peut traduire la boucle en français ainsi :
Tant que x ne dépasse pas 150, dessine une patte en x, puis ajoute 10 à x.
Ainsi on a réduit les 21 lignes de code en seulement 5 ! En plus, on peut chnager xDebut
, xFin
et ecart
pour dessiner autant de pattes qu'on veut avec les mêmes 5 lignes de code.
Laissons notre mille-patte tranquille quelques instants et occupons-nous d'une zèbre en nous posant trois questions importantes :
- Comment initialiser notre boucle ? Dans notre cas on veut mettre la première rayure tout en haut de la fenêtre.
int y = 0;
- Quelle est notre condition d'arrêt ? On veut dessiner des rayures jusqu'au bas de la fenêtre, on s'arête donc quand y dépasse la hauteur de la fenêtre. Autrement dit, on dessine tant que y est inférieur à la hauteur.
while (y < height) {
// on boucle
}
- Que fait-on à chaque itération ? Dans notre cas on dessine une rayure à la position y et on ajoute 20 à y.
rect(0, y, width, 10);
y += 20;
Et voici tout ça mis ensemble :
Exemple 9.4. Zèbre
size(200, 200);
background(255);
fill(0);
int y = 0;
while(y < height) {
rect(0, y, width, 10);
y += 20;
}
Exercice 9.1. Complétez le code pour reproduire les motifs suivants.
// cercles concentriques
size(200, 200);
background(255);
noStroke();
int w = ___;
while(___) {
fill(w);
ellipse(100, 100, w, w);
___20;
}
// diagonales
size(200, 200);
background(255);
int x = 0;
while (x < 200) {
line(___, ___, ___, ___);
line(___, ___, ___, ___);
x += 10;
}
// camembert
size(200, 200);
background(255);
noStroke();
colorMode(RGB, TWO_PI);
_______________________
_______________________
_______________________
_______________________
_______________________
_______________________
Vous commencez peut-être à vous rendre compte que les boucles sont très pratiques. Sachez néanmoins que dans le royaume des boucles il y a une province sombre peuplée de vilaines créatures connues comme boucles infinies. N'y mettez jamais le pied !
Source xkcd
Examinons à nouveau la boucle de l'exemple 9.3 :
x = xDebut;
while (x <= xFin) {
line(x, y, x, y + longueur);
x += ecart;
}
On peut voir que la boucle s'arrête lorsque x
dépasse xFin
. Cela arrivera tôt ou tard car à chaque itération x
devient de plus en plus grand (ecart
est positif). Ceci n'est pas un hasard, à chaque fois qu'on écrit une boucle, il faut s'assurer que sa condition d'arrêt sera vérifiée après un nombre fini d'itérations.
Juste pour voir ce qui se passe, essayez d'exécuter ce code en prenant soin de sauvegarder votre travail préalablement (on ne sait jamais ...).
Exemple 9.5. Sisyphe
// ATTENTION : Ceci est un mauvais exemple. Ne faites jamais ça !
int x = 0;
int stop = 10;
while(x < stop) {
println(x);
x++;
stop++;
}
Le résultat est sisyphéen : notre boucle va faire rouler son rocher sans jamais atteindre le sommet de la colline. Le nombres vont continuer à défiler même si vous fermez la fenêtre. Heureusement pour nous, Processing arrêtera tout lorsque l'on appuie sur le bouton Stop.
Un autre mauvais exemple :
int x = 1;
while (x != 10) {
println(x);
x += 2;
}
Ici x
va parcourir les valeurs 1, 3, 5, 7, 9, 11, ... et ne sera jamais 10. En règle générale, évitez de compter sur l'égalité de deux valeurs pour arrêter une boucle.
Les boucles infinies ne sont pas toujours aussi faciles à repérer. Essayons de rendre nos pattes interactives en contrôlant leur écart avec la souris.
Exemple 9.6. Encore une boucle infinie
// ATTENTION : Ceci est un mauvais exemple. Ne faites jamais ça !
int xDebut; // Où est-ce qu'on commence ?
int xFin; // Où est-ce qu'on s'arrête ?
int x;
int y = 80;
int ecart;
int longueur = 40;
void setup() {
size(200, 200);
xDebut = 0;
xFin = width;
}
void draw() {
background(255);
stroke(0);
// La position horizontale de la souris contrôle l'écart entre les pattes
ecart = mouseX / 2;
// Pattes
x = xDebut;
while (x <= xFin) {
line(x, y, x, y + longueur);
x += ecart;
}
}
En exécutant cet exemple, on constate que la fenêtre reste désespérément blanche et que le ventilateur se met à hurler. En effet, au premier passage par draw()
, mouseX
(et donc ecart
) vaut 0 et par conséquent x
ne change pas dans la boucle. On peut facilement éviter ce problème en s'assurant que ecart
soit toujours positif :
ecart = constrain(mouseX / 2, 1, width / 2);
On pourrait être tenté à résoudre le problème en se passant de la variable ecart
et en utilisant directement mouseX
dans la boucle :
while (x <= xFin) {
line(x, y, x, y + longueur);
x += mouseX / 2;
}
Si l'utilisateur bouge la souris, x
va commencer à croître et ça va débloquer la situation, non ? Bonne idée, mais malheureusement très fausse ! En effet, mouseX
et mouseY
sont mis à jour avant chaque passage par draw()
et ne changent pas pendant. On va donc rester piégé dans la boucle infinie même si l'utilisateur bouge la souris.
Exercice 9.2. Dessinez des pattes avec un écart variable :
Indication : Souvenez-vous de la vitesse et de l'accélération ? C'est le même principe.
Exercice 9.3 Dessinez le cardan d'une horloge ;
Indication: : sin()
, cos()
et %
sont vos amis.