Herhaling en willekeur

In dit hoofdstuk leer je werken met for loops en random waarden.


Herhaling

Loops gebruik je in je code om ervoor te zorgen dat je niet teveel werk doet. Je kunt natuurlijk 10 keer vrijwel dezelfde regel code typen onder elkaar, maar die code kun je meestal heel goed in een herhalingsopdracht plaatsen. In het voorbeeld hieronder worden 5 cirkels op een rij getekend:

Dit is op zich nog wel te doen, maar wat als ik 100 cirkels wil ipv. 5? Of als ik bijvoorbeeld de kleur per cirkel wil veranderen? Dan is het veel handiger om een loop te gebruiken. Op het eerste gezicht is misschien nog niet echt duidelijk hoe we dat kunnen doen. Hieronder zie je dezelfde code, maar dan iets anders geschreven:

Nu zie je dat iedere aanroep van de ellipse() functie eigenlijk exact hetzelfde doet, afgezien van de x-positie die elke keer 60 pixels naar rechts verspringt.

for loop

Er zijn verschillende manieren waarop je een loop kan maken in JavaScript. Degene die we als eerste gaan leren is de for loop. De for loop heeft een heel flexibele structuur die daardoor op meerdere manieren is te gebruiken, maar we beginnen met de standaardvorm en die ziet er zo uit:

for (let i = 0; i < 10; i++) {
    ... de code die hier staat wordt 10 keer herhaald ...
}

De code tussen haakjes achter for ziet er een beetje gek uit, wat gebeurt daar precies? Eerst wordt een variabele i aangemaakt - let i = 0, vervolgens zolang i kleiner is dan 10 - i < 10, hoog dan i op met 1 - i++. De i is hier dus gewoon een tellertje dat begint bij 0 en iedere keer in de loop optelt. En die variabele i kun je dus ook gebruiken om iets voor elkaar te krijgen in je loop, kijk maar naar het voorbeeld hieronder:

En met deze korte code van twee regels hebben we de vijf regels uit het eerdere voorbeeld vervangen. Niet slecht! Hier is nog een versie van de code die nu negen cirkels tekent in plaats van vijf (de waarden voor de xstep en de diameter van de cirkels zijn wat aangepast om het te laten passen):

Probeer eens te spelen met dit voorbeeld door de code te veranderen en probeer te bedenken wat je nog meer kan doen. De sketch hieronder brengt wat variatie in de grootte van de cirkels en heeft een fill() toegevoegd die ook gebruik maakt van de i variabele om de kleur van iedere vorm geleidelijk te veranderen en herhaalt zich wel 12 keer in plaats van 9:

Je kunt zo veel statements (regels) in een for loop stoppen als je wilt (en met "in een for loop stoppen" bedoel ik "tussen de accolades.") Elk statement zal keer op keer opnieuw weer worden uitgevoerd.

OEFENING: Neem een van de voorbeelden die een for loop gebruikt en schrijf het eens uit. Welke statements (regels) had je moeten schrijven als je geen for loop had gebruikt?

Nog dieper de for loop in

In de basis is de for loop gewoon een manier van tellen. Het makkelijkst om dit te laten zien is met de console.log(). Kopieer en plak de volgende code tussen de { en } na de setup() functie in een nieuwe sketch in de editor en klik op Play:

for (let i = 0; i < 10; i++) {
    console.log(i);
}

De console output zal er zo uit zien:

0
1
2
3
4
5
6
7
8
9

Zoals je kunt zien print deze code heel simpel de getallen van nul tot negen (dat zijn tien herhalingen, startend met nul).

De for loop kan ook gebruikt worden voor een iets geavanceerdere manier van tellen, gebruik het volgende code stukje:

for (let i = start; i < eind; i += stap) {
  ... your statements here ...
}

In het bovenstaande code stukje moet je de volgende veranderening aanbrengen:

  • start: Vervang dit woord voor het getal waar je wil beginnen met tellen.
  • eind: Vervang dit woord met het getal waar je loop moet stoppen.
  • stap: Vervang dit woord met hoeveel je getal moet toenemen met iedere stap.

Hier bijvoorbeeld, telt de loop van 100 (maar niet inclusief honderd) tot 300 in stappen van 40:

for (let i = 100; i < 300; i += 40) {
  console.log(i);
}

En deze laat alle even nummers zien vanaf 10 tot (en niet met) 50:

for (let i = 10; i < 50; i += 2) {
  console.log(i);
}

Je kunt de for loop op deze manier dus gebruiken om de stappen in de herhaling precies te bepalen zoals jij wilt. Bijvoorbeeld:

Random

In de voorbeelden hierboven is de herhaling volledig gecontroleerd, we bepalen exact de posities van de vormen. Het wordt leuker als niet precies vooraf bepaald wordt wat er moet gebeuren, dat maakt je programma onvoorspelbaarder en kan vaak verrassende resultaten opleveren.

p5.js heeft een functie met de naam random() dat een willekeurig (random) getal genereert tussen nul en een. Bekijk de referentiepagina voor meer informatie en alternatieve manieren om de functie aan te roepen: https://p5js.org/reference/#/p5/random. Het getal dat door een random functie wordt gegenereerd zal iedere keer dat de sketch wordt gebruikt anders zijn. En ook als deze in de draw() staat zal het getal iedere frame anders zijn.

random() genereert een getal van datatype float. Kopieer en plak de volgende code tussen de { en } in de setup() functie in een nieuwe sketch in de editor en klik op Play:

for (let i = 0; i < 10; i++) {
    console.log(random()*10);
}

De console output zal dan zoiets laten zien:

4.521091091574205
6.131852187904645
9.285887493521262
7.355797053323972
0.7867768679919429
5.122192107561676
2.6089046420572126
7.510976799220195
9.40859609432964
8.781951443718384

Zoals je kunt zien print deze code 10 keer een willekeurig getal tussen 0 en 10. Maar wat als je een integer tussen 0 en 10 wilt genereren (kan soms handig zijn)? Dan kun je de output van de functie typecasten, dwz. de waarde veranderen naar een ander datatype. Probeer onderstaande maar eens uit:

for (let i = 0; i < 10; i++) {
    console.log(int(random()*10));
}

Dan krijg je zoiets:

7
6
0
3
2
1
5
2
0
6

Je kunt de random() functie bijvoorbeeld gebruiken om vormen op willekeurige plekken in de sketch te laten tekenen:

En je ziet dat we random() ook gebruiken om een willekeurige grijstint voor de vulkleur in te stellen.

Als je de random() functie met één getal als parameter aanroept wordt een getal gegenereerd tussen nul en de waarde van de parameter. random()*255 doet dus precies hetzelfde als random(255).

Overigens kunnen we om de breedte en hoogte van de sketch te verkrijgen de ingebouwde variabelen width en height gebruiken, in dit geval 400 en 320.

Je kunt de random() functie ook met twee parameters gebruiken. In dat geval zal de functie een willekeurig getal geven dat tussen de waarde van de eerste en tweede parameter zit. Om een vorm te maken die "ronddoolt" over het scherm:

Als we random() combineren met een for loop kunnen we nog veel meer interessante dingen doen. In onderstaand voorbeeld controleren we de x-positie van de cirkels, maar gebruiken we willekeurige waarden voor de y-positie en de vulkleur.

Of we kunnen de random() functie gebruiken om willekeurig verschillende vormen te tekenen variërend in grootte, zie het volgende voorbeeld:

Probeer maar eens wat waarden aan te passen in bovenstaande voorbeelden om er een beetje gevoel voor te krijgen. Door op deze manier te programmeren geven we de controle over wat precies getekend wordt deels uit handen aan het programma. Bedenk wat je nog meer met random() zou kunnen doen.

Een andere functie voor willekeur is randomGaussian(). Deze functie heeft twee parameters voor het gemiddelde en de standaardafwijking (hoeveel hij van het gemiddelde mag afwijken). de functie kiest vaker waardes die dicht rond het gemiddelde liggen, en minder vaak waardes die meer van het gemiddelde afwijken.

De randomGaussian() functie kan ook met kleuren hele interessante resultaten opleveren.

Globale en lokale variabelen

In bovenstaande voorbeelden valt nog iets anders op, de variabelen zijn buiten de functies geplaatst. Dit noemen we globale variabelen. Als een variabele in een functie gedefiniëerd is noemen we dat een lokale variabele, en de variabele is dan alleen in die functie beschikbaar. Het voordeel van een globale variabele is dat deze overal beschikbaar is in je algoritme. Probeer in onderstaand voorbeeld maar eens de xpos en ypos variabelen in de setup() functie te plaatsen. Je zult zien dat je programma een error geeft, want de draw() functie kan de variabelen niet vinden, ze bestaan daar eenvoudigweg niet.