Valentin Dupas

💡 If this is the first course you read from me, please read this small thing : about my courses

Multitudes

For

for() est un mot-clef qui permet de définir un bloc de code que l'on va répéter plusieurs fois.

Il se présente comme ceci:

for loops

  • Initialisation de la boucle: une instruction qui s'exécute une fois, avant de rentrer dans la boucle.
  • Condition capturante : une condition qui est verifiée à chaque tour de boucle, on continue de faire des tours tant que la condition est vraie.
  • Instruction à exécuter après chaque tour : généralement là pour faire progresser quelque chose qui nous permettera d'invalider la condition capturante.

Du coup, si j'écris ...

// pour une variable i valant 0
// tant que i est inférieure ou égale à 10
// en augmentant i de un à chaque tour...
for (let i = 0; i <= 10; i = i + 1) {
  console.log(i); // on affiche i
}

C'est comme si j'écrivais ...

console.log(0);
console.log(1);
console.log(2);
console.log(3);
console.log(4);
console.log(5);
console.log(6);
console.log(7);
console.log(8);
console.log(9);
console.log(10);

Ce qui est plutôt sympa parce que si maintenant j'ai besoin de faire ça de 0 à 150 plutôt que de 0 à 10, je peux juste changer le nombre dans la condition du for().

for (let i = 0; i <= 150; i = i + 1) {
  console.log(i);
}
plutôt que d'écrire ça ...
console.log(0);
console.log(1);
console.log(2);
console.log(3);
console.log(4);
console.log(5);
console.log(6);
console.log(7);
console.log(8);
console.log(9);
console.log(10);
console.log(11);
console.log(12);
console.log(13);
console.log(14);
console.log(15);
console.log(16);
console.log(17);
console.log(18);
console.log(19);
console.log(20);
console.log(21);
console.log(22);
console.log(23);
console.log(24);
console.log(25);
console.log(26);
console.log(27);
console.log(28);
console.log(29);
console.log(30);
console.log(31);
console.log(32);
console.log(33);
console.log(34);
console.log(35);
console.log(36);
console.log(37);
console.log(38);
console.log(39);
console.log(40);
console.log(41);
console.log(42);
console.log(43);
console.log(44);
console.log(45);
console.log(46);
console.log(47);
console.log(48);
console.log(49);
console.log(50);
console.log(51);
console.log(52);
console.log(53);
console.log(54);
console.log(55);
console.log(56);
console.log(57);
console.log(58);
console.log(59);
console.log(60);
console.log(61);
console.log(62);
console.log(63);
console.log(64);
console.log(65);
console.log(66);
console.log(67);
console.log(68);
console.log(69);
console.log(70);
console.log(71);
console.log(74);
console.log(75);
console.log(76);
console.log(77);
console.log(78);
console.log(79);
console.log(80);
console.log(81);
console.log(82);
console.log(84);
console.log(85);
console.log(86);
console.log(87);
console.log(88);
console.log(89);
console.log(90);
console.log(91);
console.log(92);
console.log(93);
console.log(94);
console.log(95);
console.log(96);
console.log(97);
console.log(98);
console.log(99);
console.log(100);
console.log(101);
console.log(102);
console.log(103);
console.log(104);
console.log(105);
console.log(106);
console.log(107);
console.log(108);
console.log(109);
console.log(110);
console.log(111);
console.log(112);
console.log(113);
console.log(114);
console.log(115);
console.log(116);
console.log(117);
console.log(118);
console.log(119);
console.log(120);
console.log(121);
console.log(122);
console.log(123);
console.log(124);
console.log(125);
console.log(126);
console.log(127);
console.log(128);
console.log(129);
console.log(130);
console.log(131);
console.log(132);
console.log(133);
console.log(134);
console.log(135);
console.log(136);
console.log(137);
console.log(138);
console.log(139);
console.log(140);
console.log(141);
console.log(142);
console.log(143);
console.log(144);
console.log(145);
console.log(146);
console.log(147);
console.log(148);
console.log(149);
console.log(150);

Outre le fait que c'est plus simple de changer une boucle, c'est d'autant plus important pour faire des manipulations répetitives, parce que vous n'avez pas remarqués qu'il manquait console.log(83) dans le bloc ci-dessus.

"Pourquoi i?" "C'est quoi i?"

i est le possible raccourcis de deux mot anglais:

  • index que l'on pourrait traduire par "entrée" comme dans la phrase "abaca est la première entrée du dictionnaire".
  • iteration qui est le même mot en francais (à un accent près). Itérer est l'action de répeter le même procédé plusieurs fois. Une itération étant une répétetition.

Mais i est seulement un nom, et en pratique cette variable contient le numéro de l'entrée à laquelle nous sommes dans la boucle. Ou en tout cas c'est quasiment toujours le cas. Rien nous force à ce que ce soi comme ça mais ne pas le faire reviens à intentionnellement rendre son code illisible, et personne devrait faire ça.

Si vraiment le nom i vous perturbe vous pouvez utiliser autre chose comme :

for (let round = 0; round <= 10; round = round + 1) {
  // gna gna gna, le truc qu'on fait plein de fois
}

Mais sachez quand même que c'est le nom que presque tout le monde utilisera en dehors de vous. Donc il faudra au moins être capable de le lire.

Exercice

Dessinez une ligne de 10 carrés allant du bord gauche de l'écran au bord droit.

Solution
function draw() {
  for (let i = 0; i < width; i = i + width / 10) {
    rect(i, 0, 30, 30);
  }
}

Array

On va mettres la boucle for() de coté pour y revenir très vite.

Il existe un type de variable qui peut contenir plusieur valeurs.

const myNumber = 5;
const myBool = true;
const myArray = [6, false, 31, 14, true];

On reconnait bien le type des deux premières variables, un nombre et un booléen.

Pour ce qui est du troisième on notera qu'il y a bien plusieurs valeurs et qu'elles sont emballées dans une paire de crochets []. On remarquera aussi que toutes les valeurs à l'intérieur de l'array ne sont pas nécessairement du même type, ceci dit c'est juste pour la démonstration, je vous encourage fortement à n'avoir qu'un seul type de valeur par array.

Pour lire une valeur de l'array il faut écrire le nom comme vous le feriez avec une variable simple suivi d'une paire de crochets avec l'adresse de la valeur qui vous intéresse.

const myArray = [6, false, 31, 14, true];

console.log(myArray[0]); // 6
console.log(myArray[1]); // false
console.log(myArray[2]); // 31
console.log(myArray[3]); // 14
console.log(myArray[4]); // true

Remarquez que la première addresse est 0, comme ceci :

array_addresses.png

Et donc vous devriez voir le truc venir, ça va bien avec la boucle for(). Je pourrais remplacer le petit bout de code ci-dessus par ceci :

const myArray = [6, false, 31, 14, true];

for (let i = 0; i < 5; i = i + 1) {
  console.log(myArray[i]);
}

et même mieux, on peut utiliser myArray.length qui est un nombre représentant la quantité d'éléments contenus par l'array myArray. Ce qui veux dire que je n'ai pas besoin de compter moi même le nombre de trucs dans mon array mais aussi que ma boucle for() s'adaptera toute seule si je l'écris comme ceci :

const myArray = [6, false, 31, 14, true];

//                  vvv  ici! vvv
for (let i = 0; i < myArray.length; i = i + 1) {
  console.log(myArray[i]);
}

Exercice

Pour finir de vous convaincre de la démarche, copiez cet array de notes et écrivez du code qui affiche la moyenne de toutes les notes dans la console du navigateur.

const notes = [
  3, 8, 18, 4, 6, 18, 3, 11, 14, 12, 18, 17, 15, 12, 17, 6, 17, 4, 7, 18, 3, 18,
  3, 11, 3, 11, 3, 11, 8, 15, 10, 10, 13, 3, 9, 18, 4, 15, 5, 16, 14, 16, 9, 3,
  13, 16, 18, 3, 4, 14, 4, 4, 14, 13, 15, 5, 18, 17, 7, 14, 6, 15, 16, 11, 13,
  3, 3, 10, 8, 18, 7, 17, 4, 18, 14, 5, 4, 6, 10, 3, 13, 8, 16, 3, 16, 3, 4, 18,
  4, 18, 17, 11, 4, 12, 7, 5, 10, 13, 17, 9, 5, 9, 6, 3, 6, 17, 14, 6, 14, 16,
  18, 3, 18, 17, 18, 3, 15, 5, 3, 3, 18, 18, 18, 18, 18, 15, 18, 17, 11, 5, 12,
  6, 8, 3, 18, 9, 3, 16, 3, 16, 3, 8, 18, 7, 7, 18, 3, 9, 8, 12,
];
Solution
const notes = [
  3, 8, 18, 4, 6, 18, 3, 11, 14, 12, 18, 17, 15, 12, 17, 6, 17, 4, 7, 18, 3, 18,
  3, 11, 3, 11, 3, 11, 8, 15, 10, 10, 13, 3, 9, 18, 4, 15, 5, 16, 14, 16, 9, 3,
  13, 16, 18, 3, 4, 14, 4, 4, 14, 13, 15, 5, 18, 17, 7, 14, 6, 15, 16, 11, 13,
  3, 3, 10, 8, 18, 7, 17, 4, 18, 14, 5, 4, 6, 10, 3, 13, 8, 16, 3, 16, 3, 4, 18,
  4, 18, 17, 11, 4, 12, 7, 5, 10, 13, 17, 9, 5, 9, 6, 3, 6, 17, 14, 6, 14, 16,
  18, 3, 18, 17, 18, 3, 15, 5, 3, 3, 18, 18, 18, 18, 18, 15, 18, 17, 11, 5, 12,
  6, 8, 3, 18, 9, 3, 16, 3, 16, 3, 8, 18, 7, 7, 18, 3, 9, 8, 12,
];

let sum = 0;

for (let i = 0; i < notes.length; i = i + 1) {
  sum = sum + notes[i];
}

console.log(sum / notes.length);

function draw() {
  // on a rien à dessiner pour ce coup-ci
}

Object

Les objets sont un autre type de valeur complexe. Comme les arrays ils peuvent contenir plusieur vauleurs, mais un peu différement.

On l'écrit comme ceci :

const person = { age: 57, height: 181, alive: true };

Comme avec les arrays, on voit qu'on peut inclure différent types de valeurs. Mais avec un objet, chaque valeur a un nom et donc je peux acceder à l'age de ma person pour l'afficher dans la console comme ceci :

console.log(person.age);

C'est assez pratique pour grouper des variables qui vont conceptuellement ensemble, comme on l'a fait dans le chapitre précédent avec notre petit jeu. On avait un paquet de variables comme ceci :

const playerWidth = 50;
const playerHeight = 50;
const enemyWidth = 50;
const enemyHeight = 50;

let score = 0;
let speedY = 0;
let canJump = true;
let playerX = 150;
let playerYOffset = 0;
let enemyX;

Qu'on pourrait réécrire comme ceci pour mieux représenter les contraintes de notre programme

const player = {
  width: 50,
  height: 50,
  speedY: 0,
  canJump: true,
  x: 150,
  yOffset: 0,
  score: 0,
};

const ennemy = {
  x: -50,
  width: 50,
  height: 50,
};

On notera rapidement que j'ai dû trouver une valeur pour ennemy.x, en la mettant en négatif je m'assure qu'il soit hors-champ à gauche.

"Monde"

Les objets ça ne paye pas de mine comme ça, mais qu'est-ce qui'il se passe si je vous dis qu'un array peut contenir des objets?

Ça me dit qu'on peut avoir plein de "choses" dans mon code, et donc avoir cette animation infinie...

... avec juste ces quelques lignes

// un array de 5 trucs, ayant un `x`, une `speed` et une `size`
const elements = [
  { x: -500, y: 0, speed: 0, size: 50 },
  { x: -500, y: 0, speed: 0, size: 50 },
  { x: -500, y: 0, speed: 0, size: 50 },
  { x: -500, y: 0, speed: 0, size: 50 },
  { x: -500, y: 0, speed: 0, size: 50 },
];

function draw() {
  // on repeint tout l'espace en blanc
  background(255);

  // remplissage rgba donc en rouge semi-transparent
  fill(255, 0, 0, 50);

  // pour i égal à 0
  // tant que i est plus petit que le nombre de trucs
  // i augmentant de 1 à chaque tour
  for (let i = 0; i < elements.length; i = i + 1) {
    // si l'élément numéro i est hors-champ à gauche
    if (elements[i].x < -1 * elements[i].size) {
      // on change sa coordonée x
      // pour qu'il soit hors-champ à droite
      elements[i].x = width;

      // et on utilise la fonction random de p5...
      // ... pour que sa coordonnées en y
      // soit quelque part entre 0 et la hauteur de l'espace
      elements[i].y = random(0, height);
      // ... pour que sa vitesse soit entre 1 et 20
      elements[i].speed = random(1, 20);
      // ... pour que sa taille soit entre 10 et 70
      elements[i].size = random(10, 70);
    }

    // on retire (donc on déplace vers la gauche) de sa position en x
    elements[i].x = elements[i].x - elements[i].speed;

    // et puis au final on le dessine en utilisant ses coordonées et sa taille
    rect(elements[i].x, elements[i].y, elements[i].size, elements[i].size);
  }
}

Ça à l'air énorme, mais la moitié c'est des commentaires, si on les enlève on arrive à seulement 26 lignes.

Et en sachant qu'on peut ajouter un élément à un array en assignant une nouvelle valeur à une adresse qui n'existe pas encore, comme ceci

const exampleArray = [89, 698, 138];
exampleArray[3] = 17;
console.log(exampleArray); // [89,698,138,17]

... alors il suffit de changer ça

const elements = [
  { x: -500, y: 0, speed: 0, size: 50 },
  { x: -500, y: 0, speed: 0, size: 50 },
  { x: -500, y: 0, speed: 0, size: 50 },
  { x: -500, y: 0, speed: 0, size: 50 },
  { x: -500, y: 0, speed: 0, size: 50 },
];

par ceci

let elements = [];

for (let i = 0; i < 300; i = i + 1) {
  elements[elements.length] = { x: -500, y: 0, speed: 0, size: 50 };
}

Pour avoir ce résultat

Problème

Reproduisez ce petit jeu dans lequel il faut éclater tous les "ballons"

En sachant que dist() est une fonction de p5 qui permet de calculer la distance entre deux points, comme ceci

// la distance entre le point {x:5,y:5} et le point {x:10,y:10}
console.log(dist(5, 5, 10, 10)); // 7.0710678118654755

Ce qui est pratique si on devait calculer la distance entre un point et mouseX,mouseY.

Étapes :

1- Dessinez un cercle qui change de place tous les 60 images/frames

Solution
// variable qui va nous servir à mesurer le "temps"
let countdown = 60;

const balloon = { x: -500, y: 0, radius: 75 };

function draw() {
  background(255);

  // on décompte d'un pour chaque draw()
  countdown = countdown - 1;

  // et si le compte tombe à 0 ou moins
  if (countdown <= 0) {
    // on remet le compteur au "début"
    countdown = 60;

    // et on change les coordonées du ballon
    balloon.x = random(0, width);
    balloon.y = random(0, height);
  }

  // on dessine le ballon avec ses coordonées et son rayon
  circle(balloon.x, balloon.y, balloon.radius * 2);
}

2- Ne dessinez pas le cercle si la souris l'a survolé le temps d'une image

Solution
let countdown = 60;

// on ajoute une valeur pour savoir si le ballon est "alive"
const balloon = { x: -500, y: 0, radius: 75, alive: true };

function draw() {
  background(255);

  countdown = countdown - 1;

  if (countdown <= 0) {
    countdown = 60;

    balloon.x = random(0, width);
    balloon.y = random(0, height);
  }

  // si la distance entre le centre et la souris est plus petite que le rayon
  if (dist(balloon.x, balloon.y, mouseX, mouseY) < balloon.radius) {
    // il n'est plus vivant
    balloon.alive = false;
  }

  // si il est vivant on le dessine
  if (balloon.alive) {
    circle(balloon.x, balloon.y, balloon.radius * 2);
  }
}

3- Dessinez-en une dizaine

Solution
let countdown = 60;

// on change notre `balloon` en `balloons`
// qui est un array de plusieurs ballons
const balloons = [
  { x: -500, y: 0, alive: true, size: 150 },
  { x: -500, y: 0, alive: true, size: 150 },
  { x: -500, y: 0, alive: true, size: 150 },
  { x: -500, y: 0, alive: true, size: 150 },
  { x: -500, y: 0, alive: true, size: 150 },
  { x: -500, y: 0, alive: true, size: 150 },
  { x: -500, y: 0, alive: true, size: 150 },
  { x: -500, y: 0, alive: true, size: 150 },
  { x: -500, y: 0, alive: true, size: 150 },
  { x: -500, y: 0, alive: true, size: 150 },
];

function draw() {
  background(255);

  countdown = countdown - 1;

  if (countdown <= 0) {
    countdown = 60;

    // on fait comme avant mais avec une boucle
    // pour passer sur tous les ballons
    for (let i = 0; i < balloons.length; i = i + 1) {
      balloons[i].x = random(0, width);
      balloons[i].y = random(0, height);
    }
  }

  // pareil, on passe sur tous les ballons grâce à une boucle
  for (let i = 0; i < balloons.length; i = i + 1) {
    if (
      dist(balloons[i].x, balloons[i].y, mouseX, mouseY) <= balloons[i].radius
    ) {
      balloons[i].alive = false;
    }

    if (balloons[i].alive) {
      circle(balloons[i].x, balloons[i].y, balloons[i].size);
    }
  }
}