Inviato da entuland il
Nella pagina precedente abbiamo visto cosa significa rendere una procedura più intelligente e più flessibile. Nella parte finale ci siamo concentrati sul fatto di creare una procedura flessibile che sapesse disegnare poligoni regolari di diversi tipi, adesso vediamo di valutare e correggere i problemi di una procedura, se ce ne sono.
Cercare i problemi
Qui sotto puoi vedere di nuovo la procedura poligono che abbiamo creato nella pagina precedente:
per poligono :angoli :lato
ripeti :angoli [
avanti :lato
destra 360 / :angoli
]
fine
Come si cercano i problemi in una procedura? Bisogna provarla, verificare come si comporta in base agli argomenti che usiamo e confrontare questo comportamento con i risultati che ci aspettavamo.
Dopo avere fatto le prove possiamo pensare che questa procedura abbia due problemi:
- si comporta come se aggiungesse il valore 1 alla lunghezza dei lati (eseguendo il comando poligono 4 0, ad esempio, la tartaruga disegna un puntino, eseguendo il comando poligono 4 1 disegna un quadrato di lato 2 e così via)
- accetta qualsiasi valore come numero di angoli (chiamando poligono 1 100, ad esempio, disegna una linea e lascia la tartaruga in una posizione diversa da quella di partenza)
Quando una procedura "si comporta male" hai almeno due possibilità: evitare che vengano passati degli argomenti sbagliati alla procedura o fare in modo che la procedura valuti i suoi argomenti e prenda delle decisioni. Ma chi decide se e come deve essere corretta una procedura? Lo decidi tu.
In questa guida io ti spiego il mio punto di vista sulla programmazione, ti mostro quelli che secondo me possono essere dei problemi e ti faccio vedere le mie soluzioni, poi sta a te fare le prove, decidere se vuoi correggere i problemi - se pensi che siano dei problemi - e soprattutto decidere come correggerli.
Bene, per come la vedo io, questa procedura sarebbe migliore se sapesse valutare e correggere gli argomenti che riceve.
Prendere una decisione per correggere un problema
Per prima cosa, insegnamo alla procedura a verificare il numero di angoli e stampare un messaggio di errore se gli angoli sono meno di tre. In questo modo possiamo anche vedere dei nuovi comandi del LOGO:
per poligono :angoli :lato
se :angoli < 3 [
stampa [Non posso disegnare un poligono con meno di 3 angoli]
stop
]
ripeti :angoli [
avanti :lato
destra 360 / :angoli
]
fine
La parte che ho aggiunto è questa:
se :angoli < 3 [
stampa [Non posso disegnare un poligono con meno di 3 angoli]
stop
]
In queste quattro righe ci sono tre comandi che non ho ancora spiegato, vediamoli uno per uno.
Il comando se serve ad eseguire degli altri comandi solo in certe condizioni, questo tipo di comando è il cuore dell'intelligenza di un programma, quella che prende le decisioni.
La forma di questo comando è se :condizione :listacomandi.
I comandi contenuti nella lista dei comandi vengono eseguiti solo se la condizione è vera, altrimenti il programma salta quei comandi e continua dalla riga successiva.
La condizione è :angoli < 3. Il simbolo < significa minore di. Quando il linguaggio LOGO legge il codice :angoli < 3 prende il valore contenuto dentro :angoli, controlla se questo valore è minore di 3 e riporta VERO o FALSO in base a quel controllo.
La lista dei comandi è invece questa:
[
stampa [Non posso disegnare un poligono con meno di 3 angoli]
stop
]
Vediamo un po' meglio il significato delle parentesi quadre. Nel LOGO le parentesi quadre indicano l'inizio e la fine di una lista. Una lista nel LOGO è un gruppo di "cose", messe in un certo ordine, e queste cose possono essere praticamente di tutto. Possono essere delle parole, dei numeri, delle altre liste e così via.
Nell'ultimo blocco di codice qui sopra ci sono infatti due liste una dentro l'altra.
La prima lista, quella più grande, contiene le chiamate ai comandi stampa e stop.
La seconda lista è invece [Non posso disegnare un poligono con meno di 3 angoli], che viene passata come argomento al comando stampa.
Non ti preoccupare se non capisci ogni singolo dettaglio di come funzionano queste cose, la cosa importante è che capisci le idee con le quali stiamo lavorando. I dettagli di come si usano i vari comandi e i vari simboli li impari a poco a poco, guardando del codice che funziona e facendo tutte le prove che ti servono.
Il comando stampa prende il valore di qualsiasi argomento gli venga dato e lo scrive nella casella uscita - storico dei comandi. Fai delle prove eseguendo nella riga di comando dei comandi come quelli qui sotto:
stampa [Questa è una frase]
stampa 2 + 3
Il comando stop, infine, fa uscire direttamente dalla procedura senza eseguire nessun altro comando.
Quindi possiamo guardare questo blocco di codice...
se :angoli < 3 [
stampa [Non posso disegnare un poligono con meno di 3 angoli]
stop
]
...e leggerlo in questo modo "se il numero di angoli è minore di 3 allora stampa un messaggio e esci dalla procedura, altrimenti continua con i comandi successivi".
Molto bene, abbiamo risolto uno dei problemi. Adesso, se cerchiamo di creare un poligono con meno di tre angoli, ad esempio chiamando poligono 2 100, riceviamo un messaggio di errore e la tartaruga non fa niente.
Studiare meglio un problema
Come ho scritto all'inizio di questa pagina la nostra procedura sbaglia la misura dei poligoni che disegna, ma prima di tentare di correggere questo problema vediamo di capire bene di che problema si tratta.
Ricordi il menu zoom. Questo comando prende un numero come argomento e ti permette di ingrandire e rimpicciolire la tua vista dell'area di disegno.
? Il lavoro fatto dalle voci di menu e può essere fatto direttamente dal codice con il comandoFacciamo un esempio pratico. Esegui questi comandi uno dopo l'altro dalla riga di comando (se le ricordi, al posto dei comandi completi puoi usare anche le abbreviazioni):
puliscischermo
zoom 16
avanti 0
Se li hai eseguiti correttamente dovresti avere ottenuto qualcosa del genere:
Il comando zoom 16 ha ingrandito il disegno di sedici volte e ci permette di vedere un paio di cose:
- quando si aumenta lo zoom la tartaruga cambia di dimensione (il triangolo diventa più grande) ma i suoi bordi rimangono sempre sottili;
- il comando avanti 0 non fa spostare la tartaruga ma esegue comunque una operazione di disegno: colora il punto nel quale si trova la tartaruga;
- il quadrato nero che si vede attaccato alla base della tartaruga, anche se lo vediamo come un quadrato, per il computer è come se fosse un solo punto: i disegni fatti dal computer infatti si compongono di tanti piccoli punti chiamati pixel.
Fai anche quest'altra prova: pulisci di nuovo lo schermo ed esegui il comando avanti 1. Invece di un piccolo quadrato nero, vedrai un piccolo rettangolo nero:
Quel rettangolo nero in realtà è composto da due pixel, uno attaccato all'altro, ingranditi di sedici volte (sempre che tu non abbia cambiato lo zoom).
Se usiamo dei colori diversi questa cosa diventa più facile da vedere. Puoi cambiare il colore della penna in due modi: puoi aprire il menu ascolpenna, che significa assegna colore penna, e che si può abbreviare come ascp.
e usare la voce , oppure puoi usare il comandoProva ad eseguire questi comandi in sequenza:
puliscischermo
zoom 16
ascolpenna 0 ; assegna il colore nero alla penna
avanti 1 ; disegna DUE pixel di colore nero
ascolpenna 4 ; assegna il colore rosso alla penna
avanti 1 ; disegna DUE pixel di colore rosso, "mangiando" uno dei pixel neri
ascolpenna 2 ; assegna il colore verde alla penna
avanti 0 ; disegna UN pixel di colore verde, "mangiando" uno dei pixel rossi
Dovresti avere ottenuto qualcosa del genere:
Da questo esperimento possiamo vedere bene il comportamento del comando avanti. Forse ti chiedi se il comando avanti sta funzionando male, perché non ha senso far colorare qualcosa nell'area di disegno se la tartaruga non si muove... o forse dipende dal punto di vista, e se guardiamo il problema da un punto di vista diverso, il comportamento del comando avanti potrebbe avere un senso.
Prova a pensare ai disegni fatti con il computer, che sono composti da tanti piccoli quadretti, come se stessi davvero disegnando con un pennarello su di un foglio a quadretti. Dato che la cosa più piccola che puoi colorare su di uno schermo è il pixel, facciamo finta che quando disegni sul foglio a quadretti puoi usare solo dei quadretti interi.
Prendiamo un foglio a quadretti:
Poggiamo un grande pennarello rosso al centro di un quadretto:
Adesso solleviamo il pennarello e vediamo che il pennarello ha lasciato un pallino:
Quello qui sopra è il risultato del comando avanti 0. Dato che per il computer il quadretto è un pixel e non può disegnare nessuna cosa più piccola di un pixel, è come se quel quadretto fosse completamente colorato:
Adesso guarda questa animazione:
Le azioni che vedi qui sopra sono le stesse operazioni che vengono eseguite dal comando avanti 1: "poggia il pennarello al centro di un quadretto, avanza di un quadretto, alza il pennarello".
Il risultato che otteniamo sulla carta è un segno che copre quasi due quadretti:
Dato che il computer usa solo quadretti interi è come se avessimo ottenuto questo risultato:
Questi sono i numeri dei sedici colori che puoi usare dentro il LOGO:
- 0 - Nero
- 1 - Blu
- 2 - Verde
- 3 - Ciano
- 4 - Rosso
- 5 - Magenta
- 6 - Giallo
- 7 - Bianco
- 8 - Marrone
- 9 - Marrone chiaro
- 10 - Verde scuro
- 11 - Celeste
- 12 - Rosa
- 13 - Viola
- 14 - Arancione
- 15 - Grigio
Nel LOGO puoi usare tantissimi altri colori ma sono un po' scomodi da usare, perché bisogna prepararli. Pensa a questi sedici colori come a dei tubetti di tempera: hai sedici tubetti con dei colori già pronti da usare, mentre tutti gli altri vanno creati mischiando i colori di due o più tubetti. Quando usi i colori a tempera vengono usati principalmente il ciano, il magenta, il giallo, il bianco e il nero. Quando mischi i colori in un computer si usano invece il rosso, il verde e il blu. Si tratta di due sistemi diversi che vedremo in'un altra pagina, per il momento ti dovrai accontentare di questi sedici colori. Ricordati che per cambiare il colore della penna devi usare il comando ascolpenna, oppure la sua abbreviazione ascp, seguito da un numero da 0 a 15.
Ritorniamo alla nostra procedura poligono. Abbiamo visto il comportamento del comando avanti, quindi abbiamo capito perché la procedura poligono aggiunge il valore 1 alle misure dei lati. Facciamo finta che questa cosa non ci piaccia, e vediamo come possiamo correggerla.
Come prima cosa, dobbiamo fare in modo che la procedura non faccia niente quando gli viene passata una misura di lato uguale a zero. Come abbiamo già visto, per fare in modo che la procedura prenda delle decisioni dobbiamo usare il comando se. La condizione che vogliamo verificare è se il lato è uguale a zero, e le azioni che vogliamo eseguire sono quelle di stampare un messaggio e uscire dalla procedura.
Ecco come farei io:
per poligono :angoli :lato
se :angoli < 3 [
stampa [Non posso disegnare un poligono con meno di 3 angoli]
stop
]
se :lato = 0 [
stampa [Se il lato vale zero non ho niente da fare]
stop
]
ripeti :angoli [
avanti :lato
destra 360 / :angoli
]
fine
Quando ho aggiunto queste righe:
se :lato = 0 [
stampa [Se il lato vale zero non ho niente da fare]
stop
]
...ho fatto in modo che la procedura corregga il problema del lato da zero, ma tutti gli altri lati continuano a venire allungati di un pixel. Per correggere questa cosa basta togliere 1 alla variabile :lato quando la stiamo passando al comando avanti, quindi invece di chiamare avanti :lato chiameremo avanti :lato - 1.
Con quest'ultima correzione, la procedura completa diventa questa:
per poligono :angoli :lato
se :angoli < 3 [
stampa [Non posso disegnare un poligono con meno di 3 angoli]
stop
]
se :lato = 0 [
stampa [Se il lato vale zero non ho niente da fare]
stop
]
ripeti :angoli [
avanti :lato - 1
destra 360 / :angoli
]
fine
Adesso voglio andare avanti e vedere come possiamo riutilizzare una procedura, ma prima di continuare, fai delle prove e usa la nuova procedura poligono per verificare come si comporta. Verifica in particolare cosa succede quando passi un argomento negativo al parametro :lato, ad esempio chiamando poligono 4 -2 e poligono 4 -1. Se fai lo zoom ti viene più facile vedere come si comporta la tartaruga quando fa questi disegni così piccoli.
Nota: presta attenzione al fatto che in questo caso non c'è nessuno spazio tra il simbolo meno - e il numero che lo segue.
- Nella chiamata poligono 4 -1 ci sono due numeri, il numero "quattro" e il numero "meno uno", che vengono passati separatamente ai due parametri (il numero "quattro" viene passato come argomento al parametro :angoli, il numero "meno uno" viene passato come argomento al parametro :lato).
- Nella chiamata poligono 4 - 1, invece, c'è l'operazione "quattro meno uno" che da come risultato il numero "tre", il numero "tre" viene passato come argomento al parametro :angoli e non viene passato niente al parametro :lato (infatti se lo provi dovresti ricevere l'errore "argomenti insufficienti per poligono").
Le due chiamate che ho mostrato qui (poligono 4 -1 e poligono 4 - 1) sono molto diverse ma la causa è molto piccola: un solo spazio aggiunto nel punto sbagliato. Presta molta attenzione a questa cosa, un simbolo fuori posto (aggiunto o mancante) potrebbe causare un errore. I computer non sono bravi a capire quello che "volevi dire", hanno bisogno di ricevere dei comandi molto precisi.
Riutilizzare le procedure
Adesso che abbiamo corretto tutto quello che volevamo correggere nella procedura poligono, vediamo come possiamo riutilizzarla.
Tutte le volte che vogliamo disegnare un poligono possiamo utilizzare questa procedura direttamente, ma ci saranno dei poligoni che useremo più spesso, e per questi poligoni possiamo crearci delle scorciatoie.
Ad esempio, potremmo volere usare molto spesso i poligoni con tre e quattro angoli (triangoli e quadrati) e potrebbe essere quindi più comodo avere una procedura separata per ognuno di questi due poligoni.
Dobbiamo forse riscrivere le procedure triangolo e quadrato come abbiamo fatto nelle pagine precedenti, aggiungendo le correzioni che abbiamo fatto alla procedura poligono? Assolutamente no. Se le riscriviamo in questo modo stiamo duplicando il codice e la duplicazione del codice non è una cosa buona, perché ogni volta che troviamo un problema con quel codice lo dobbiamo correggere più volte in posti diversi e questo può creare nuovi problemi.
Questo qui sotto è il modo sbagliato di creare le procedure triangolo e quadrato affianco alla procedura poligono:
per poligono :angoli :lato
se :angoli < 3 [
stampa [Non posso disegnare un poligono con meno di 3 angoli]
stop
]
se :lato = 0 [
stampa [Se il lato vale zero non ho niente da fare]
stop
]
ripeti :angoli [
avanti :lato - 1
destra 360 / :angoli
]
fine
; modo sbagliato: duplicazione del codice
per quadrato :lato
se :lato = 0 [
stampa [Se il lato vale zero non ho niente da fare]
stop
]
ripeti 4 [
avanti :lato - 1
destra 90
]
fine
; modo sbagliato: duplicazione del codice
per triangolo :lato
se :lato = 0 [
stampa [Se il lato vale zero non ho niente da fare]
stop
]
ripeti 3 [
avanti :lato - 1
destra 120
]
fine
Come puoi vedere qui sopra abbiamo molti pezzi di codice che si assomigliano, e soprattutto abbiamo le stesse correzioni in posti diversi. Ad esempio, se cambiamo idea e vogliamo correggere il comando avanti :lato - 1 e farlo diventare di nuovo semplicemente avanti :lato, lo dobbiamo fare in tre punti diversi.
Questo invece è il modo giusto di creare le procedure triangolo e quadrato affianco alla procedura poligono:
per poligono :angoli :lato
se :angoli < 3 [
stampa [Non posso disegnare un poligono con meno di 3 angoli]
stop
]
se :lato = 0 [
stampa [Se il lato vale zero non ho niente da fare]
stop
]
ripeti :angoli [
avanti :lato - 1
destra 360 / :angoli
]
fine
; modo giusto: riutilizzo del codice
per quadrato :lato
poligono 4 :lato
fine
; modo giusto: riutilizzo del codice
per triangolo :lato
poligono 3 :lato
fine
Questo qui sopra è il modo giusto perché se vogliamo cambiare il comportamento di tutte e tre le procedure ci basta cambiare la procedura poligono, dato che le altre due sono solo delle scorciatoie per dei casi particolari.
Quando abbiamo preso la vecchia procedura triangolo e l'abbiamo trasformata nella procedura poligono siamo passati da più casi particolari (come quelli del triangolo e del quadrato) ad una idea generale (quella del poligono). Quella azione come abbiamo visto si chiama generalizzazione.
In questo caso stiamo facendo il lavoro contrario: stiamo prendendo una idea generale (quella del poligono) e tramite il riutilizzo stiamo passando a più casi particolari (come quelli del triangolo e del quadrato). Questa azione si chiama specializzazione.
La specializzazione, in una forma diversa, si trova anche nella vita di tutti i giorni. Un esempio potrebbe essere quello dei giochi di squadra come il calcio: in una squadra tutti sanno giocare, ma alcuni giocatori si specializzano nel giocare in attacco oppure in difesa. I giocatori di calcio sono delle persone e possono cambiare il loro posto, ad esempio un attaccante, in caso di bisogno, può giocare in difesa. Le procedure all'interno di un programma non possono fare lo stesso, ma come abbiamo già visto le persone sono molto più capaci, flessibili e intelligenti dei computer.
Per questa pagina ci possiamo fermare. Prima di finire voglio però mostrarti come puoi utilizzare le ultime tre procedure che abbiamo creato e mostrarti un altro comando con il quale fare i tuoi esperimenti:
per casa :lato
quadrato :lato
avanti :lato
destra 30
triangolo :lato
sinistra 30
indietro :lato
fine
per provapoligoni :numeropoligoni :lato
ripeti :numeropoligoni [
poligono iterazioni + 2 :lato
]
fine
Il nuovo comando è iterazioni, che significa ripetizioni. Come ho fatto in una delle pagine precedenti con il comando riporta, non ti dirò esattamente come funziona, prova a scoprirlo da solo facendo delle prove. Queste procedure potrebbero aiutarti a capirlo meglio:
per conteggio :massimo
ripeti :massimo [
stampa iterazioni
]
fine
per tabellina :numero
ripeti 10 [
stampa :numero * iterazioni
]
fine
; prova queste procedure usando i seguenti comandi
; dalla riga di comando:
tabellina 2
tabellina 3
conteggio 5
conteggio 10
Grazie per la tua attenzione, a presto e buon divertimento con il LOGO!