(toiminnot)

hwechtla-tl: Teema 6: kaikkein tärkein aihe

Kierre.png

Mikä on WikiWiki?
nettipäiväkirja
koko wiki (etsi)
viime muutokset


Tämänkertainen teema on tärkein, sillä melkein kaikki muut perustuvat sille jollakin tapaa. Periaatteessa opettelemme, miten ohjelmia yleistetään niin, että niistä tulee monikäyttöisempiä, ja yhdistellään niin, että selviämme vähemmällä kirjoitusvaivalla. Käytännössä opettelemme tekemään komentoja, joille voi antaa syötettä. Lisäksi opimme siinä sivussa muokkaamaan ja muuttelemaan aiemmin tekemiämme ohjelmia.

Tässä teemassa opetettujen asioiden koko hyödyllisyys paljastuu vasta pikku hiljaa myöhempien teemojen myötä. Voimme kuitenkin jo tässä vaiheessa tehdä paljon hauskoja ja ihan hyödyllisiäkin asioita.

Harjoitus 6a: ohjelmien tarkastelu ja muokkaus

Tarvitsemme tässä teemassa joitain valmiiksi tehtyjä ohjelmia. Voit käyttää jotain aiemmin tallettamaasi tai kirjoittaa muutaman ohjelman (kuten neliö ja ympyrä) ensin. Itse aion käyttää teeman 3 määrittelyitä lähtökohtana:

? lataa "harkat3

Teitpä uudet ohjelmat tai latasitpa vanhoja, sinulla pitäisi nyt olla joitain määrittelyitä olemassa. Ne saa listatuksi "ohjelmat"-komennolla. Minulla lista on tällainen:

? ohjelmat
miten kaario
miten kaariv
miten lehti
miten neliö
miten nuoli
miten orvokki
miten pää
miten raaja
miten seppele
miten silmät
miten sormet
miten ukkeli
miten vartalo
miten ympyrä

Yhdestä ohjelmasta saa tietää määrittelyn komennolla "näytä". Kuten lataa- ja tallenna-komennoissa, näytä-komennon syöte alkaa lainausmerkillä. Miksi, muuten? Ilman lainausmerkkiä kirjoitetut sanat ovat komentoja ja jos kirjoitat neliö, logo tekee sen (siis neliön). Lainausmerkin kanssa kirjoitetut taas ovat nimiä tai sanoja ja jos kirjoitat "neliö, Logo tekee jotain sille (siis neliölle). Tässä tapauksessa Logo tekee neliölle sen, että näyttää sen määritelmän.

? näytä "neliö
miten neliö
toi 4 [et 100 oi 90]
valmis

Jos haluamme muokata tätä määritelmää, voimme käyttää komentoa "muokkaa" tai sen lyhennettä "muo". Kokeile:

? muo "neliö

Voit nyt tehdä neliöön haluamiasi muutoksia (sinulla pitäisi olla näytölläsi nyt jonkinlainen muokkausohjelma, jossa voit muutella määritelmää). Lopuksi sulje muokkausohjelma ja tallenna muutokset. Muuta neliön määritelmä vaikkapa seuraavanlaiseksi:

miten avoin_neliö
toi 4 [et 100 oi 88]
valmis

Jos et muuta komennon nimeä, uusi määritelmä korvaa vanhan; jos muutat komennon nimeä (kuten yllä neliö muutettiin muotoon avoin_neliö), vanha määritelmä säilyy ja syntyy myös uusi. Käytä ensimmäistä tapaa, kun haluat korjata ohjelmiasi, ja toista tapaa, jos haluat tehdä uusia komentoja vanhojen pohjalta.

Muokattua ohjelmaa kannattaa tietysti kokeilla:

? näytä "avoin_neliö
miten avoin_neliö
toi 4 [et 100 oi 88]
valmis

? avoin_neliö

Katsele ja muokkaa nyt joitain omia ohjelmiasi.

Harjoitus 6b: maisk glumps mumps

Nyt tulee tämän teeman sydän. Tähän mennessä määrittelemämme ohjelmat ovat olleet oikeasti käteviä, mutta aina vähän mielivaltaisia. Esimerkiksi määrittelemämme neliö, ympyrä ja kaaret ovat juuri tietynlaisia: aina saman kokoisia, muotoisia ja pituisia. Olisi huiman kätevää, jos pystyisimme tekemään samalla komennolla vähän useammanlaisia neliöitä. Ja sitä varten tarvitsemme komentoja, joille voi antaa syötettä, koska syötteellä voi kertoa neliölle, millaisen neliön siitä haluaa, samaan tapaan kuin kerromme "eteen"-komennolle, kuinka paljon haluamme mennä eteenpäin. Nyt alamme tehdä näitä ruokittavia komentoja.

Neliöllä on aivan ilmeinen ominaisuus, jonka kannattaa olla muutettavissa, nimittäin koko. Haluamme muuttaa neliön sellaiseksi, että sille voi kertoa neliön sivun pituuden, niin että "neliö 100" tekee yhden kokoisen neliön, "neliö 50" puolet pienemmän ja "neliö 10" pikkuriikkisen neliön.

Alamme taas muokata neliötä. Tästä lähdetään:

? muo "neliö

Ja näytölläsi pitäisi olla:

miten neliö
toi 4 [et 100 oi 90]
valmis

Muuta määritelmä tällaiseksi:

miten neliö :koko
toi 4 [et 100 oi 90]
valmis

Neliölle tulevat syötteet luetellaan miten-komennossa komennon nimen jälkeen. Neliö-sanan perään lisätty ":koko" tarkoittaa siis, että neliö-komento ottaa yhden syötteen, jonka nimi on ":koko". Kaikkien syötteiden nimet alkavat kaksoispisteellä. Kaksoispiste tarkoittaa: "tämä ei ole mikään tietty luku, vaan pelkkä paikanpitäjä, jonka tilalle tulee myöhemmin jokin oikea luku". Tällaista paikanpitäjää sanotaan muuttujaksi siksi, että sen tilalle voi tulla erilaisia lukuja.

Voit nyt tallentaa uuden määritelmän. Kokeillaan sitä:

? neliö
neliö haluaa enemmän syötteitä
? neliö 10
? oi 10
? neliö 20

Muutos on siinä mielessä onnistunut, että neliö haluaa syötteitä, mutta harmillista kyllä neliö ei vielä käytä syötettään mihinkään (vaan siitä tulee aina samanlainen neliö). Korjataan tilanne:

? muo "neliö

Muuta nyt määritelmä tähän muotoon (eli muuta et-komennon syöte niin, ettei se ole enää "100" vaan ":koko"):

miten neliö :koko
toi 4 [et :koko oi 90]
valmis

Tallenna, sulje ja kokeile.

? uusi
? neliö 100
? neliö 50
? neliö 20

Jee, se toimii!

Miksi se toimii?

Kuten sanoin, ":koko" tarkoittaa jotain lukua, joka kerrotaan myöhemmin. Kun sanon "neliö 20", Logo ajattelee: "Ahaa, :koko on nyt 20." Kun Logo tekee neliötä, se tietää, että :koko on 20, joten on kuin olisimme kirjoittaneet:

toi 4 [et 20 oi 90]

Kun taas sanon "neliö 50", :koko onkin 50, joten Logo tekee neliön kuin olisimme kirjoittaneet:

toi 4 [et 50 oi 90]

Kätevää, eikö?

Komennosta voi korvata ihan minkä tahansa luvun (ja paljon muutakin, kuten myöhemmin näemme) muuttujalla, joka annetaan komennolle syötteeksi. Muutetaan esimerkiksi avoin_neliö näin:

? muo "avoin_neliö

miten avoin_neliö :kulma
toi 4 [et 100 oi :kulma]
valmis

Nyt komennolla saa eri tavalla hajalla olevia neliöitä:

? uusi
? avoin_neliö 88
? keskelle
? avoin_neliö 80
? keskelle
? avoin_neliö 97

Tällaista uutta komentoa on tietysti hauskaa testata eri syötteillä. Joskus kannattaa jättää Logon tehtäväksi tuottaa erilaisia syötteitä (tietokoneethan ovat hyviä toistamisessa):

? uusi
? toi 10 [neliö kerta*10]
? toi 10 [neliö kerta*10 oi 20]

Kokeile nyt tehdä muokkaamalla tai suoraan määrittelemällä esimerkiksi ympyrä tai kolmio, joka osaa ottaa syötettä, ja testaa uusi komentosi.

Harjoitus 6c: (mitta)suhteiden säilyttämistä

Usein meillä on määrittelyitä, joissa on useampia toisiinsa sovitettuja lukuja. Ajatellaan esimerkiksi, että haluamme tehdä vinoneliön. Sen määritelmä voisi olla tällainen:

? miten vinoneliö
> toista 2 [et 50 oi 60 et 50 oi 120]
> valmis

Vinoneliö koostuu neljästä käännöksestä, joiden summan tulee olla 360 astetta (muuten lennokki ei palaudu alkuasentoon eikä kuvio voi olla vinoneliö). Niinpä käännökset "oi 60" ja "oi 120" riippuvat toisistaan siten, että niiden summan pitää olla 180 astetta. Kun vinoneliöön lisätään käännöskulman antava syöte, pitää myös säilyttää tämä johdonmukainen riippuvuus (tähän on monta tapaa, tässä yksi):

? muo "vinoneliö

miten vinoneliö :kulma
toista 2 [et 50 oi :kulma et 50 oi 180-:kulma]
valmis

Nyt määrittelyyn on kirjoitettu auki se logiikka, josta astekulmat 60 ja 120 syntyivät: mikä tahansa määrä ensin käännytäänkin, pitää seuraavaksi kääntyä 180 miinus tuo määrä, koska muuten käännöksistä ei tule yhteensä 180 astetta. Muuttujaa :kulma käytetään kaksi kertaa siten, että sen aiheuttamat käännökset sovitetaan yhteen. Määritelmällä pystyy tekemään eri verran vinoja neliöitä ("liuu"-komento on yksinkertainen yhdistelmä oi-, hyps- ja va-komentoja):

? uusi
? toista 10 [vinoneliö kerta*10 liuu 30]

Kun jollekin kuviolle halutaan lisätä syötteeksi koko, törmätään usein hyvin samanlaiseen ongelmaan. Usein kuvio sisältää monia eri pituuksia, jotka seuraavat erilaisilla kaavoilla toisistaan. Tarkastellaan vaikkapa "nuoli"-määrittelyä:

? näytä "nuoli
miten nuoli
et 100
va 135
et 50
va 135
et 71
va 135
et 50
valmis

Mistä pituudet 100, 50, 71 ja 50 oikein tulevat? Ne on määritelty toistensa perusteella niin, että nuolen mittasuhteet näyttävät järkeviltä. Erityisesti luvut 50, 71 ja 50 (sekä käännösmäärä 135 astetta) on laskettu siten, että nuoli sulkeutuu nätisti. (Nuolen kärki on neliön puolikas, joten halkaisijan pituus on laskettu Pythagoraan kaavalla. Jos et tunne sitä, älä välitä, sillä vielä ei tarvitsekaan.)

Jos haluamme säilyttää nuolen mittasuhteet, kaikkia pituuksia pitää muuttaa samassa suhteessa. Voimme esimerkiksi valita "peruspituudeksi" 100 ja laskea kaikki muut pituudet sen perusteella (50 on 100/2 ja 71 on 100*0.71):

? muo "nuoli

miten nuoli :koko
et :koko
va 135
et :koko / 2
va 135
et :koko * 0.71
va 135
et :koko / 2
valmis

Tämä ainakin selvästi toimii:

? toista 10 [nuoli kerta*10]

Toisaalta määrittelyssä ollut luku 100 (nuolen pituus) ei riipu niin olennaisesti muista luvuista, jotka määrittävät nuolen pään kokoa. Ehkä haluaisimmekin jättää jommankumman erilleen, joko näin:

miten nuoli :leveys
et 100
va 135
et :leveys / 2
va 135
et :leveys * 0.71
va 135
et :leveys / 2
valmis

Tai sitten näin:

miten nuoli :pituus
et :pituus
va 135
et 50
va 135
et 71
va 135
et 50
valmis

Jos haluaa lisätä jollekin kuviolle koko-syötteen suoraviivaisesti, kaikkein helpoin tapa on kuitenkin vain raa'asti kertoa kaikki pituudet koko-muuttujalla. Nimittäin kun kaikki pituudet kerrotaan samalla numerolla, pituuksien suhteet säilyvät, jolloin kuvion muoto säilyy.

Tehdään vaikkapa tällainen A-kirjain:

? miten akirjain
> oi 30
> et 100
> oi 120
> et 100
> oi 180
> et 50
> va 60
> et 50
> valmis

Nyt, jos haluamme tehdä vaihtelevan kokoisia A-kirjaimia, helpoin tapa on muokata ohjelmaa näin:

? muo "akirjain

miten akirjain :koko
oi 30
et 100 * :koko
oi 120
et 100 * :koko
oi 180
et 50 * :koko
va 60
et 50 * :koko
valmis

Nyt "akirjain 1" tuottaa normaalikokoisen A-kirjaimen, "akirjain 2" kaksi kertaa isomman ja "akirjain 1/4" neljä kertaa pienemmän.

Muuta nyt joitain ohjelmiasi sellaisiksi, että niille annetaan mittoja syötteeksi.

Harjoitus 6d: monta syötettä

Ehkä kaikkein "oikein" ratkaisu on lisätä nuolelle sekä leveys että pituus erikseen syötteiksi, koska silloin nuoli-ohjelmalla voi tehdä kaikenlaisia nuolia.

? muo "nuoli

miten nuoli :pituus :leveys
et :pituus
va 135
et :leveys / 2
va 135
et :leveys * 0.71
va 135
et :leveys / 2
valmis

Miten-riville voi siis lisätä kuinka monta syötettä haluaa. Jos nyt esimerkiksi annamme komennon "nuoli 100 50", niin :pituus on nuolta piirrettäessä 100 ja :leveys on 50. Jos taas sanomme "nuoli 30 35", niin :pituus on 30 ja :leveys 35. Logo sitten asettelee nämä luvut paikoilleen.

Nyt ainakin saamme aikaan vaikka minkälaisia nuolia. Seuraavassa nuoli-komento ottaa siis kaksi syötettä, joista toinen on "130-kerta" ja toinen on "kerta/2":

? piiloon
? toista 100 [uusi va kerta nuoli 130-kerta kerta/2 odota 1]

Malliesimerkki ohjelmasta, joka vaatii monta syötettä, on kaari. Kaarilla on sekä pituus että astekulma, jonka ne kääntyvät. Tarkastellaan kaario:n määritelmää:

? näytä "kaario
miten kaario
toi 90 [et 1 oi 1]
valmis

Tässä kaaren pituus on 90 askelta, sillä lennokki menee eteenpäin yhden askeleen kerrallaan 90 kertaa. Samoin kaaren käännös on 90 astetta, koska siinä käännytään yksi aste kerrallaan 90 kertaa.

Lisätään kaariolle ensin vaikkapa :pituus-syöte:

? muo "kaario

miten kaario :pituus
toi :pituus [et 1 oi 1]
valmis

Hienoa, nyt saamme haluamamme mittaisia kaaria:

? toista 10 [kaario 10*kerta va 30]

Mutta nyt :pituus vaikuttaa myös siihen, kuinka paljon kaari kääntyy. Jotta vaikutus saataisiin kumotuksi, kääntymismäärä käskyssä "oi 1" pitää olla jokin luku jaettuna toistokertojen määrällä. Silloin käännymme yhteensä saman verran riippumatta siitä, kuinka monta kertaa menemme eteenpäin.

? muo "kaario

miten kaario :pituus
toi :pituus [et 1 oi 90/:pituus]
valmis

Mahtavaa, nyt pystymme tekemään aina 90 astetta kääntyviä kaaria riippumatta siitä, kuinka pitkiä ne ovat!

? uusi
? toista 10 [kaario 10*kerta oi 90]

Lopuksi voimme tietysti korvata kiinteän 90 asteen käännöksen jollain muulla luvulla, joka annetaan syötteeksi:

? muo "kaario

miten kaario :pituus :kulma
toi :pituus [et 1 oi :kulma/:pituus]
valmis

Nyt voimme muutella sekä kaaren pituutta kääntymismäärästä riippumatta että kääntymismäärää pituudesta riippumatta.

? toista 200 [uusi kaario kerta 200 * sin 5 * kerta odota 1]

Kokeile nyt tehdä esimerkiksi nuoli, jossa pystyy muuttamaan sekä nuolen kokoa että nuolen pään terävyyttä.

Harjoitus 6e: tiedon välittämistä eteenpäin

TODO


Pikalinkit:


kommentoi (viimeksi muutettu 02.05.2014 16:31)