Strutture di controllo iterative
Controllo del flusso delle istruzioni
Ogni algoritmo può essere definito usando e combinando tre strutture di base.
Sequenza
semplice successione di istruzioni
(ottenuta con: ordine delle istruzioni)
Decisione
esecuzione al verificarsi di una condizione
(ottenuta con: if, switch o ?:)
Ripetizione
esecuzione ciclica di una o più istruzioni
(ottenuta con: for o while)
La struttura for
for (inizializza; condizione; aggiorna)
{
istruzioni da ripetere
}
una o più operazioni iniziali eseguite una sola volta
il for inizia o ripete le istruzioni se la condizione è true, altrimenti finisce
operazioni eseguite dopo ogni ciclo prima di una nuova verifica della condizione
Le parentesi graffe possono essere tolte se viene usata un'unica istruzione... ma si consiglia di tenerle.
Ordine di esecuzione delle parti del for
for (inizializza; condizione; aggiorna) {
istruzioni
}
- inizializza
- condizione (==true)
- istruzioni
- aggiorna
- condizione (==true)
- istruzioni
...
- aggiorna
- condizione (==false)
- uscita dal for
Se la condizione è false al 1° controllo, non viene eseguita nessuna istruzione.
Dalla sequenza al for

Immagine generata con una sequenza di istruzioni:
function setup() {
background( 200 );
var x = 10;
rect( x,20, 20,60 );
x = x+30;
rect( x,20, 20,60 );
x = x+30;
rect( x,20, 20,60 );
// x = x+30;
// x < 100 == false
}
La stessa immagine generata con un for:
function setup() {
background( 200 );
for (var x = 10; x < 100; x = x+30) {
rect( x,20, 20,60 );
}
}
si può scrivere anche: x += 30.
Provare ad allargare il canvas (ad es., con createCanvas(400,100); prima di background(200)) e aumentare il numero di rettangoli intervenendo sui parametri del for.
Provare ad allargare il canvas e aumentare le spaziature fra i rettangoli intervenendo sui parametri del for.
Interruzione forzata del for: break
function setup() {
background( 200 );
for (var x = 5; x < 100; x = x+20) {
if (x == 65) {
break;
}
rect( x,20, 10,60 );
}
}
interrompe il for ed evita l'esecuzione dei cicli successivi.

Salto di un ciclo: continue
function setup() {
background( 200 );
for (var x = 5; x < 100; x = x+20) {
if (x == 65) {
continue;
}
rect( x,20, 10,60 );
}
}
interrompe il ciclo corrente e passa a quello successivo.

Uso di for annidati
function setup() {
background( 200 );
for (var x = 5; x < 86; x = x+20) {
for (var y = 5; y < 66; y = y+20) {
rect( x,y, 10,10 );
}
}
}
esegue 5 cicli con x che va da 5 a 85.
esegue 4 cicli (con y che va da 5 a 65) per 5 volte (una per ogni variazione di x).

Provare a modificare il codice in modo da far disegnare anche l'ultima riga di quadratini.
Array e iterazioni sui dati
Gli array
Struttura dati che permette di memorizzare e gestire sequenze di valori.

Vengono identificati da un nome (come le variabili) e il riferimento ai singoli elementi avviene attraverso un indice numerico.
Creazione degli array
var gradi = []; // array vuoto
gradi[0] = 24; // imposta 1° elemento
gradi[1] = 16; // imposta 2° elemento
gradi[2] = 27; // imposta 3° elemento
nome dell'array.
indice dell'elemento, a partire da 0 (zero).

Se i valori sono noti fin dall'inizio, il codice può essere scritto anche così:
var gradi = [ 24, 16, 27 ];
valori iniziali separati da virgole.
Lettura e uso degli elementi di un array
function setup() {
var gradi = [ 24, 16, 27 ];
text( gradi[0], 10, 20 );
text( gradi[1], 10, 35 );
text( gradi[2], 10, 50 );
}
indice dell'elemento di cui leggere il valore.

Lo stesso codice si puo riscrivere con un for:
function setup() {
var gradi = [ 24, 16, 27 ];
for (var i=0; i<gradi.length; ++i) {
text( gradi[i], 10, 20+i*15 );
}
}
proprietà degli array che restituisce il numero di elementi; nell'esempio, gradi.length corrisponde a 3.
l'operatore ++ somma 1 al valore della variabile; ++i corrisponde quindi a i=i+1.
calcola i valori della coordinata y:
- 20 (20+0*15)
- 35 (20+1*15)
- 50 (20+2*15).
Aggiunta di elementi a un array
function setup() {
var gradi = [ 24, 16, 27 ];
gradi.unshift(10); // inserisci all'inizio
gradi.push(30); // aggiungi in coda
for (var i=0; i<gradi.length; ++i) {
text( gradi[i], 10, 20+i*15 );
}
}
metodo degli array che permette di inserire un elemento iniziale facendo slittare automaticamente tutti gli altri.
metodo degli array che permette di aggiungere un elemento dopo tutti gli altri.

Eliminazione di elementi a un array
function setup() {
var gradi = [ 24, 16, 27 ];
gradi.splice( 1, 1 ); // togli 2° elemento
gradi.pop(); // togli ultimo elemento
for (var i=0; i<gradi.length; ++i) {
text( gradi[i], 10, 20+i*15 );
}
}
il primo parametro indica l'indice dell'elemento da eliminare, il secondo indica il numero di elementi da eliminare.
metodo degli array che permette di eliminare l'ultimo elemento.

Il metodo splice() permette anche di inserire elementi in una determinata posizione facendo slittare quelli successivi.
Gli array JavaScript hanno anche altri metodi che permettono di fare operazioni più complesse: w3schools.com/js/
Iterazioni cromatiche
Generazione di una sequenza casuale di colori
function setup() {
// disegna barre colorate
noStroke();
for (var x = 0; x < width; x += 5) {
fill( random(255), random(255), random(255) );
rect( x,0, 5,100 );
}
}
l'operatore += permette di sommare il valore a destra a quello della variabile a sinistra, nel caso specifico corrisponde a x=x+5.
Creazione e uso di una palette predefinita
function setup() {
// definisci la palette
var palette = [
color(255,0,0), color(255,255,0),
color(0,255,0), color(0,255,255),
color(0,0,255), color(255,0,255)
];
// disegna barre colorate
noStroke();
for (var x = 0; x < width; x += 5) {
var c = x/width * palette.length;
fill( palette[ int(c) ] );
rect( x,0, 5,100 );
}
}
color() è una funzioni di p5.js che permette di compattare le informazioni di un colore in un unico intero utilizzabile nelle istruzioni di impostazione del colore.
x/width restituisce un valore con decimali che va da 0 (0/100) a 0.99 (99/100); moltiplicato per il numero di elementi dell'array (palette.length) permette di ottenere l'intera sequenza degli indici della palette; i valori possono essere ricavati anche con:c = map( x, 0,width,
gli indici degli array devono essere sempre numeri interi.

Creazione e uso di una palette con gradienti
function setup() {
colorMode( HSL, 360,100,100 );
// crea la palette
var palette = [];
for (var n = 0; n < 20; ++n) {
palette[n] = color( 30, 100, n*5 );
}
// disegna barre colorate
noStroke();
for (var x = 0; x < width; x += 5) {
var c = x/width * palette.length;
fill( palette[ int(c) ] );
rect( x,0, 5,100 );
}
}
uso della modalità cromatica HSL per rendere più semplice impostare una variazione di luminosità di qualsiasi colore.
colore sempre arancione (30), al massimo della saturazione (100) e con un valore di luminosità variabile da 0 (0*5) a 95 (19*5).

Provare a modificare la sfumatura intervenendo sui parametri della funzione color() e usando la variabile n.
Scelta a caso da una palette
function setup() {
colorMode( HSL, 360,100,100 );
// crea la palette
var palette = [];
for (var n = 0; n < 20; ++n) {
palette[n] = color( 30, 100, n*5 );
}
// disegna barre colorate
noStroke();
for (var x = 0; x < width; x += 5) {
var c = random( palette.length );
fill( palette[ int(c) ] );
rect( x,0, 5,100 );
}
}
valore a caso nell'intervallo dei valori di indice validi.
Iterazioni vettoriali
Creazione poligoni irregolari
function setup() {
background( 200 );
var vertici = 4;
beginShape();
for (var i=0; i<vertici; ++i) {
var x = random( width );
var y = random( height );
vertex( x, y );
}
endShape( CLOSE );
}
la variabile vertici definisce il numero di vertici da calcolare e da usare per disegnare il poligono.
il parametro CLOSE permette di chiudere il poligono senza indicare di nuovo il primo vertice.

Creazione poligoni regolari: metodo
I poligoni regolari vengono disegnati calcolando la successione dei vertici sulla circonferenza in cui il poligono è inscritto.

Partendo da un angolo iniziale e un raggio noti, il problema è ricavare la successione degli angoli e quindi le coordinate dei vertici sulla circonferenza.
Radianti, coseni e seni

Ipotizzando un segmento:
- lungo 1
- con un'estremità in 0,0
- con inclinazione pari a rad
il coseno di rad corrisponde alla coordinata x della seconda estremità
il seno di rad corrisponde alla coordinata y della seconda estremità
Funzioni cos() e sin()
x = cos( rad );
y = sin( rad );
Entrambe le funzioni restituiscono valori che vanno da -1 a 1.
Per modificare la posizione e il raggio della circonferenza di riferimento è sufficiente moltiplicare il nuovo raggio ai valori ottenuti e sommare le coordinate del nuovo centro:
x = 300 + cos( rad ) * 200;
y = 100 + sin( rad ) * 200;
sposta il centro alle coordinate 300,100.
porta il raggio a 200 pixel.
Sketch interattivo: openprocessing.org/sketch/145782
Creazione poligoni regolari: algoritmo
function setup() {
background( 200 );
var vertici = 5;
beginShape();
for (var i=0; i<vertici; ++i) {
var angolo = i * TWO_PI/vertici;
var x = 50 + cos( angolo )*40;
var y = 50 + sin( angolo )*40;
vertex( x, y );
}
endShape( CLOSE );
}
ricava l'angolo fra un vertice e l'altro; potrebbe essere calcolato una sola volta, prima del for, e memorizzato in una variabile da usare al posto della divisione.
coordinate riferite a una circonferenza posizionata al centro del canvas (50,50) e con un raggio di 40 pixel.

Per ruotare il vertice iniziale di 90° in senso antiorario, si può usare:angolo = i*TWO_PI/vertici;
Variazioni dei poligoni regolari: stella
function setup() {
background( 200 );
var vertici = 16;
beginShape();
for (var i=0; i<vertici; ++i) {
var angolo = i * TWO_PI/vertici;
var raggio = (i%2 == 0)? 40 : 10;
var x = 50 + cos(angolo) * raggio;
var y = 50 + sin(angolo) * raggio;
vertex( x, y );
}
endShape( CLOSE );
}
la condizione i%2 == 0 è vera se i è pari (resto di i/2 uguale a 0(); se la condizione è vera raggio diventa 40, altrimenti diventa 10.

Iterazioni di pattern
Traslazione delle coordinate
translate( 20,10 );
rect( 0,0, 60,60 );
modifica le coordinate di riferimento in modo che l'origine si trovi alle coordinate 20,10.

Variazione di scala delle coordinate
scale( 1.5, 0.5 );
rect( 0,0, 60,60 );
modifica le coordinate di riferimento in modo che l'asse orizzontale sia allungato al 150% (1.5) e quello verticale sia ridotto al 50% (0.5).

Rotazione delle coordinate
rotate( TWO_PI/12 );
rect( 0,0, 60,60 );
modifica le coordinate di riferimento in modo che siano ruotate di 30° in senso orario (TWO_PI/12).

Somma e reset delle trasformazioni
function setup() {
background( 200 );
translate(20,10);
rect(0,0, 50,50);
translate(20,10);
rect(0,0, 50,50);
resetMatrix();
rect(0,0, 50,50);
}
il secondo translate() si somma a quelli precedenti; in questo caso l'origine delle coordinate risulterà spostato di 40 pixel (20+20) verso destra e di 20 (10+10) verso il basso.
l'istruzione riporta le coordinate alla situazione iniziale.

Provare a sostituire uno o entrambi i translate() con le istruzioni scale() o rotate()
Ripetizione di trasformazioni
function setup() {
createCanvas( 400, 300 );
background( 200 );
for (var i=0; i<200; ++i)
{
translate( 2, 8 );
rotate( -0.02 );
scale( 0.986 );
rect( 0,0, 120,120 );
}
}

Trasformazioni con for annidati
function setup() {
createCanvas( 300, 300 );
background( 200 );
rectMode( CENTER );
var angolo = 0;
for (var y=0; y<=height; y+=20) {
for (var x=0; x<=width; x+=20) {
angolo += 0.006;
resetMatrix();
translate( x,y );
rotate( angolo );
rect( 0,0, 20,20 );
}
}
}
Pattern casuali con for annidati
function setup() {
background( 200 );
for (var y=0; y<height; y+=10) {
for (var x=0; x<width; x+=10) {
if (random(100) < 50) {
line( x,y+5, x+5,y ); // disegna /
line( x+5,y+10, x+10,y+5 ); // disegna /
} else {
line( x+5,y, x+10,y+5 ); // disegna \
line( x,y+5, x+5,y+10 ); // disegna \
}
}
}
}