torstai 17. joulukuuta 2015

Racket Turtle - jatkot Kaukajärvellä

Kaukajärven ohjelmointikurssilaiset (8lk) tekivät kurssin päätteeksi Racket Turtlen - jatkotason tehtäviä. Ensin mietimme miten saisimme Turtlen tekemään perusspiraalin:

Tämä oli helppo tehtävä: jokaisella kierroksella pitäisi vain kulkea hieman pidempi matka. Tätä varten teimme funktion, joka osaa tehdä yhden MUUTTUVAN pituisen sivun:

(define (sivu matka)
    (list (forward matka)
           (turn-left 90)))

Seuraavaksi mietimme miten saisimme annettua tuolle funktiolle listan kasvavia matkan arvoja. Tutkimme interaktioikkunassa miten range - funktio toimii:

(range 0 100 5)

ja totesimme, että sen avulla saisimme tarvittavat matkan arvot. Vielä tarvittiin funktio joka syöttää nämä sivu-funktiolle ja olisimme valmiit:

(map sivu (range 0 100 5))

Tälle annettiin definellä nimi ja piirrettiin se:

(define spiraali (map sivu (range 0 100 5)))
(draw spiraali)

 Jotta spiraalia saataisiin enemmän ei ollut vaikea keksiä, että range:a piti lisätä.

Perusspiraalia lähdettiin sitten muuttaamaan, lisäämällä värejä (esim. antamalla värilista), sekä muuttamalla kulma joksikin muuksi kuin 90 astetta.

Kun kokeilut olivat tuottaneet hienoja kuvia ne tallennettiin taas Padlet - seinälle.

Toisella tunnilla opettelimme vielä leimasimen käytön ja lisäsimme hieman tähtiä spiraalien sekaan. Tällaisia hienoja kuvia syntyi tällä kaksoistunnilla:
Racket Turtle - taidetta à la Kauksu

Funktiotunti Tesomalla (jatko)

Jatkoimme 8lk kanssa polynomifunktioihin tutustumista. Kerroin, että polynomifunktioilla voidaan mallintaa vaikka lasten pituuskasvua ja muita oikean elämän ilmiöitä. Selitin, että erilaiset funktiot käyttäytyvät eri tavalla riippuen siitä ilmiöstä jota ne mallintavat. Sitten lähdimme tutustumaan erilaisiin polynomeihin.

Koska oppilaat eivät olleet vielä käyneet polynomeja matematiikan tunnilla niin selitin lyhyesti mikä on polynomi, termi, kerroin, muuttuja, vakio, ensimmäisen ja toiseen asteen polynomi. Sitten teimme funktiot seuraaville polynomeille (yksi funktio kerrallaan):

Koodina nämä näyttäisivät tältä:

(define (p1 x)
    (* 2 x))

(define (p2 x)
    (+ (* -2 x) 3))

(define (p3 x)
    (+ (- (expt x 2)) -3))

Jokaisen funktion koodaamisen jälkeen testasimme sitä interaktioikkunassa:

> (p1 4)
> (p2 10)
> (p3 3)

Ja testaamisen jälkeen teimme piirsimme niiden kuvaajat plot2D - kirjaston avulla (require teachpacks/plot2D):

 (plot2D (list (func p1 0 10)
               (func p2 0 10)
               (func p3 0 10)))


Tässä tuli testattua nyt sekin, että koodaamalla voi opiskella myös hyvin perinteisesti matematiikkaa. Toki mitään WOW-efektiä tässä ei tietenkään synny, ei opettajan eikä oppilaankaan taholta, kuvaajia kun voi piirtää monella muullakin ohjelmalla. Toki tässä on se hyöty, että ei tarvitse opetella montaa ohjelmaa kun samalla ohjelmalla voi hoitaa kaiken (ohjelmointi, kuvaajat jne.)

Vielä kun jostain löytäisi ne polynomifunktiot, jotka mallintavat niitä oikeita pituuskäyriä niin olisi saanut tämänkin asian lähemmäksi todellisuutta...

Ylöjärven animaatiot (jatko)

Viimeisellä kouluviikolla jatkoimme animaatioiden kanssa Ylöjärven yhtenäiskoulussa. Palautimme mieleen asioita kahden viikon takaa: muuttuja, funktio, ehtolause, vertailuoperaatio sekä animaatiomoottori (animate).
Uutena asiana otimme cond-valintalauseen, että saimme animaation tekemään useampaa kuin kahta juttua. Jatkoimme viimekertaisen ympyräanimaation kehittelyä jokainen omaan suuntaansa.

Aloitimme oman animaation tekemisen ensin vaihtamalla ympyrän johonkin muuhun kuvaan esim. tähteen (star, radial-star) ja vaihtamalla sille värin. Sitten muutimme koodin niin, että if:in tilalle vaihdettiin cond.

(define (oma-kuva t)
   (cond [(< t 250)
          (star t "solid" "purple")]
         [else
          (circle t "solid" "red")]))

Kaksi viikkoa oli aika pitkä aika muistaa se, että jos jätti tuon t:n pois ja kirjoitti vaikka 40 niin tähden koko ei muuttunut. Tässä tuli hyvin kerrattua jälleen kerran muuttujan käsite. Animaatiossa se vieläpä konkretisoituu niin hyvin, jos muuttuja ei ole käytössä niin kuva ei todellakaan muutu!

Cond-lause ei sinänsä tuottanut ongelmia mutta ehtojen säätäminen oli uusi asia, joka vaati miettimistä. Esim. moni kopioi ensimmäisen ehdon eikä vaihtanut lukuja, ja sitten ihmetteli miksi kolmas kuva ei koskaan tule esiin... No, miksiköhän ei?

(define (oma-kuva t)
   (cond [(< t 250)
          (star t "solid" "purple")]
         [(< t 250)
          (star t "solid" "yellow")]
         [else
          (circle t "solid" "red")]))

Toinen pohdinnan paikka tuli eteen siinä, kun animaatio piteni, jossain vaiheessa viimeiset kuvat putosivat pois. Tässä vaiheessa olisi pitänyt muistaa, että rajoitimme animaation t:n tietylle välillä. Jos olemme rajoittaneet t:n välille 0-199, tietenkään kuva jonka pitäisi tulla esiin kun t on 300-400 ei ikinä ilmesty. Tämän sai korjattua muokkaamalla modulo:a.

(define (kuva t)
  (place-image (oma-kuva (modulo t 400)) 

               250 250 
               (empty-scene 500 500)))

Viimekerralla tehty "kuha-kääntyy" funktio otetiin nyt käyttöön, kuvat laitettiin pyörimään, vaihtamaan väriä, suurenemaan ja pienenemään. Osa vaihtoi myös place-imageen x:n tilalle muuttujan, jolloin kuva lähti kulkemaan vasemmalta oikealla. Ja modulon avula se saatiin toistamaan samaan (nyt rajoittava arvo saatiin empty-scene:n leveydestä). Muutama oppilas lisäsi myös tekstiä  animaatioonsa.

Tässä yksi animaatio, jossa kuva pyörii, liikkuu eteenpäin ja mukana on myös teksti:



tiistai 8. joulukuuta 2015

Muuttuja, lauseke ja funktio - tunti Tesomalla

Tesoman 8.luokan matematiikan ryhmä aloitti tutustumisen Racket-ohjelmointiin tänään. Esimmäiseksi tutustuimme siihen, että on olemassa lukuja ja merkkijonoja. Testasimme niitä interaktioikkunassa. Muuttujan käsitteeseen törmäsimme kun keksimme kirjoittaa merkkijonon ilman "hipsuja" ja DrRacket ilmoitti "this variable is not defined".

Seuraavaksi määrittelimme muuttujia (sekä merkkijonoja, että lukuja) määrittelyikkunassa definen avulla, ja testasimme miksi luvussa ei saa olla hipsuja (sillä ei voi laskea).

(define a 5)
(define b 10)

Nyt kokeilimme laskea näiden muuttujien avulla esilaisia lausekkeita: yhteen-, vähennys-, kerto- ja jakolaskua (interaktioikkunassa):

> (+ a b)
> (- a b)
> (* a b)
> (/ a b)

Kokeilimme myös desimaalilukuja, negatiivisia lukuja sekä potenssiin korottamista expt:in avulla:

> (expt a b)

Sitten tutustuimme funktion käsitteeseen: sen avulla voidaan kirjoittaa laskusääntö, että jokin toiminto saadaan automatisoitua (esim. lentokoneen autopilotti). Piirsin taululle seuraavan kuvan:


Oppilaat saivat keksiä muuttujan nimen ja funktion säännön itse
Tämän koodasimme sitten funktioksi:

(define (plus3 a)
  (+ a 3))

Lisäsimme vielä lopuksi sille selityksen kommenttiriville:

; plus3 : Luku -> Luku

Lopuksi testasimme mitä tapahtuu kun funktiota kutsutaan eri arvoilla. Osa tajusi heti mitä seuraava rivi palauttaa:

> (plus3 100)

Tämän jälkeen ehdotin, että oppilaat olisivat tehneet jonkun oman funktion, mutta aika loppui kesken (ja olihan tässäkin jo hirveästi asiaa yhdelle oppitunnille). Seuraavalla kerralla jatkamme polynomifunktioiden kirjoittamista ja niiden kuvaajien piirtämistä DrRacket:illä.

Turtle-testausta Kaukajärvellä

Viime perjantaina joukko 8.luokan oppilaita ohjelmoi Racket Turtlea tekemään erilaisia geometrisia kuvioita. Ensimmäiseksi latasimme DrRacket:in Package Managerin avulla "teachpacks" paketin, jossa myös Racket Turtle - kirjasto on. Sitten latasimme Koodausta kouluun materiaalin sivuilta valmiin koodin, joka piirtää neliön. Tutkimme koodia yhdessä hidastetun piirtotoiminnon (step-by-step) avulla ja kun Turtlen ohjaamislogiikka oli selvillä oppilaat saivat tehtäväksi muuttaa koodi piirtämään kolmion. Osa sai kolmion valmiiksi nopeasti ja he siirtyivät kuusikulmioon ja neljäkkääseen. Kun kaikki olivat saaneet kolmion valmiiksi, näytin miten kuusikulmion sai tehtyä kätevämmin repeat - komennon avulla.

(define sivu
   (list (forward 100)
          (turn-left 60)))

(define kuusikulmio
    (repeat 6 sivu))

(draw kuusikulmio) 

Näytin vielä miten repeat:in avulla voi toistaa myös aikaisemmin piirretyn kuvion:

(define neliöt
    (repeat 4 neliö))

Kun repeat oli hanskassa ryhdyimme leikkimään sen avulla, ja toistimme jo valmiiksi saatuja peruskuvioita: neliötä, kolmiota, kuusikulmiota tai neljäkästä. Jotta kaikki kuviot eivät olisi vain sinisiä opettelimme vaihtamaan myös väriä change-color:in avulla. Osa oppilaista opetteli myös pen-up, pen-down ja go-to komennot, jotta sai kuvansa nätisti keskelle piirtoaluetta. Lopuksi oppilaat saivat ladata itse piirtämänsä Turtle-kuvan Padlet-seinälle kaikkien ihailtavaksi. Tällaisia niistä sitten tuli:

Kauksun Turtle-Padlet
Tämä ryhmä oli jo aikaisemmin tutustunut DrRacket:iin piirtämällä peruskuvioita sekä yhdistettyjä kuvia ja näiden Turtle kuvien tekemiseen meni yksi kaksoistunti. 

keskiviikko 2. joulukuuta 2015

Kämmenniemen koulun 9. luokan piilokuvatestausta

Ennen näitä tunteja Kämmenniemen koulun 9. luokka oli koodannut tänä syksynä Racket:illä jo vaikka mitä: peruskuvia (lippuja ja autoja), pinta-alafunktioita sekä avaruuskappaleiden levityskuvia. Tällä kaksoistunnilla tarkoitus oli tutustua totuusarvoihin, ehtolauseisiin sekä tehdä piilokuvaharjoitus.

Ensimmäisellä tunnilla lähdimme liikkeelle totuusarvoista. Kirjoitimme interaktioikkunaan true ja false totesimme, että ne ovat arvoja kuten luvut ja merkkijonotkin. Sitten kokeilimme vertailuoperattoreita. Annoimme ensin muuttujalle a arvon viisi, ja sitten teimme vertailuja sillä seuraavasti:

> (define a 5)

> (< a 5)
#false

> (= a 5)
#true

Tästä pääsimmekin sitten ehtolauseeseen (if), kokeilimme myös sitä interaktioikkunassa. Tätä testattiin muutaman kerran eri ehdoilla (if - lause palautettiin interaktioikkunaan painamalla Crtl+nuoliylös):

> (if (< a 5)
        "pienempi kuin 5"
        "suurempi tai yhtäsuuri")

Koska ryhmä oli tehnyt jo funktioita aikaisemmin, lähdimme tekemään funktioita, jotka käyttävät ehtolausetta hyväkseen. Ensimmäiseksi teimme funktion "lämmitin", jonka tehtävänä olisi pitää luokkahuone lämpimänä: aina kun lämpötila laskisi alle 22 astetta, lämmitin menisi päälle. Aivan ensimmäiseksi mietimme mitä muuttujia funktio tarvitsee ja mitä se palauttaa:


;; lämmitin : Luku -> Merkkijono 

Sitten kirjoitimme funktiolle rungon eli stub:in:

(define (lämmitin t) 
    "")

Sitten suunnittelimme funktion toiminnan käyttämällä check-expect - lauseita:

(check-expect (lämmitin 20)
              "lämmitin päälle")

(check-expect (lämmitin 25)
              "lämmitin pois päältä")

(check-expect (lämmitin 22)
              "lämmitin pois päältä")


Nyt tiesimme mitä funktiolta odotetaan, joten pystyimme täydentämään funktion rungon valmiiksi:

(define (lämmitin t)
  (if (< t 22)
      "lämmitin päälle"
      "lämmitin pois päältä"))


Tämän jälkeen oppilaat saivat suunnitella funktion "portsari", jonka piti päästää baariin sisälle vain täysi-ikäiset henkilöt. Tämä sujui hyvin, tosin osa portsareista ei ollut erityisen kohteliaita alaikäisille asiakkailleen. Toimivan portsarin jälkeen teimme vielä bussin "rahastaja":n, jonka piti matkustajan iän perustella palauttaa bussimatkan hinta. Päätimme, että hintaluokkia olisi: lapsi, nuori ja aikuinen (osa oppilaita otti mukaan myös seniorit). Tämäkin funktio tehtiin funktion suunnitteluportaiden avulla.

;; rahastaja : Luku -> Luku
(define (rahastaja ikä)

   0)

Sitten check-expect:it:

(check-expect (rahastaja 10)
              1)
(check-expect (rahastaja 13)
              1.20)
(check-expect (rahastaja 23)
              2)
(check-expect (rahastaja 18)
              2)
(check-expect (rahastaja 12)
              1.2)


Ja lopuksi funktio, jossa käytimme nyt cond - valintalausetta, että saimme useamman ehdon toimimaan kätevästi (perusrakenteen teimme yhdessä, tarkemman säädön jokainen sai tehdä itse):

(define (rahastaja ikä)
  (cond [(>= ikä 18) 2]
        [(< 11 ikä 18) 1.2]
        [else 1]))


Tämä funktio oli jo niin monimutkainen, että check-expectejä todellakin tarvittiin sen testaamiseen ja koodin saamiseksi oikein. Ensimmäisellä yrittämällä moni 18 täyttänyt pääsi nimittäin lastenlipulla (kun = merkki oli unohtunut koodista) eli rajatilanteiden testaaminen todellakin kannatti.

Näiden harjoitusten jälkeen otimme projektiksi piilokuvaharjoituksen. Koodiin tutustumisen jälkeen tehtäväksi tuli muuttaa koodia niin, että se tuottaa Saksan lipun. Tähän menikin sitten kaksoistunnin loppuaika ja lähes kaikki saivat lippunsa toimimaan. Yksi oppilas taisi ehtiä tehdä myös hieman haastavamman Suomen lipunkin.

Saksan lipun avulla opeteltiin valintalausetta ja vertailuoperaattoreita

Ylöjärven yhtenäiskoulussa koodattiin animaatioita

Olin maanantaina testaamassa Koodausta kouluun materiaalin animaatioharjoitusta Ylöjärven yhtenäiskoulussa. Testiryhmänä toimi puolikas 8.luokan ryhmä, joka oli aikaisemmin jo koodannut 2-3 tuntia Racket:illä (peruslaskuja, lippuja sekä autoja).

Nyt siirryimmekin jo aivan toiselle tasolle eli tutustuimme funktioiden määrittelemiseen, totuusarvoihin, vertailuoperaattoreihin sekä ehtolauseeseen. Aloitimme kertaamalla muuttujan käsitteen. Lippuja koodattaessa olimme käyttäneet jo muuttujia, ja palautimme mieleen miten muuttuja määritellään define:n avulla:

(define a 100)
(define väri "red")

Tämän jälkeen tutkimme miten saisimme tehtyä ympyrän, jonka säde ja väri on ilmoitettu muuttujien  avulla ja päädyimme tähän:

(circle a "solid" väri)

Nyt kokeilimme muuttaa a:n ja väri:n arvoa definessä ja huomasimme, että ympyräkin muuttui samalla. Tästä pääsimme hyvin siihen, että tarvitsemme muuttujia, mutta ne eivät pelkästään riitä, vaan meidän pitää saada nämä arvot jostakin, joten kirjoitimme tuon koodin ympärille funktion määritelmän:

(define (ympyrä a väri)
   (circle a "solid" väri))
  
Tätä testattiin interaktioikkunasta eri arvoilla ja todettiin se toimivaksi.

(ympyrä 100 "yellow")
(ympyrä 50 "blue")

Funktio-testausta
Nyt oppilaat saivat tehtäväksi määritellä jonkin toisen funktion, joka tekisi eri muotoisen kuvan. Tässä vaiheessa palautimme mieleen miten piirtofunktioita etsittiin Koodarin käsikirjasta. Teimme myös funktion, joka saa sisäänsä kuvan, jota se kiertää x astetta vastapäivään. Myös tätä testattiin.

(define (kierrä kuva asteet)
   (rotate asteet kuva))

Yksi pojista oli aikaisemmin koodannut USA:n lipun ja testaili sen pienentämistä ja suurentamista scale - funktion avulla.

Toisella tunnilla aloitimme tutustumaan animaatioihin. Kerroin animation - funktion toiminnasta, kuinka se kutsuu meidän "oma-kuva" - funktiota 28 kertaa sekunnissa luvuilla 0, 1, 2, 3, 4 ... jne. Selitin myös taululla piirtämäni kuvan avulla, miten empty-scene ja place-image toimivat. Sitten latasimme valmiin animaatiopohjan oppilaan tehtävät sivulta.

Kun painoimme "run", totesimme, että animaation punainen ympyrä ei värähdäkään ja pyysin oppilaita korjaamaan asian. Tämä oli yllättävän vaikeaa, vaikka olimme juuri tehneet vastaavan ympyrä - funktion, erot olivat vain pintapuolisia: funktion nimi oli eri (ympyrä vs. oma-kuva) ja muuttujan nimi oli eri (a vs. t). Pienen lypsämisen jälkeen joku ryhmästä keksi sen: muuttujaa pitää käyttää koodissa! Vaihdoimme siis 100:n t:ksi ja animaatio alkoi toimia.
 
(define (oma-kuva t)
  (circle 100 "solid" "red"))


Seuraava oppilaiden ihmettelyn aihe oli se, että miksi se vain jatkaa kasvamistaan. Miksi se ei pienene. Tähän oli helpompi vastata: koska sitä ei ole ohjelmoitu pienenemään. Se on ohjelmoitu vain suurenemaan. Tästä pääsimme hyvin siihen, että jotta se voisi pienentyä tarvitsemme koodiimme kaksi haaraa: "suureneva ympyrä" - haaran ja "pienenevä ympyrä" - haaran.

Lähdimme tutustumaan ehtolauseen käyttöön tutkimalla interaktioikkunassa ensin vertailuoperaattoreita <, > ja =. Kerroin, että nämä palauttavat totuusarvoja: #true ja #false ja että nämä ovat se tapa, jolla koodi saadaan haarautumaan "tosihaaraan" ja "epätosihaaraan".

>  (< 100 150)
#true

Näiden testailujen jälkeen testasimme interaktioikkunassa if-lausetta:

> (if (< 100 150) 
        "totta mooses"
        "väärin meni")

Kun kaikki olivat saaneet sekä "totta mooses" että "väärin meni" toimimaan, jatkoimme animaation kimpussa. Teimme siis ehtolauseen oma-kuva - funktioon.

(define (oma-kuva t)
  (if (< t 300)
      (circle t "solid" "red")

      (circle t "solid" "red")))

Nyt alkoikin sitten kova miettiminen miten ympyrä saadaan pienenemään eli mitä t:lle pitäisi tehdä. Kysyin oppilailta, että mikä laskutoimitus pienentää, ja vastaus löytyi heti: vähennyslasku. Sitten olikin hieman enemmän epäselvää mitä pitää vähentää mistäkin... Kun logiikkaa ei heti löytynyt totesin, että kokeillaan jotain, sitten nähdään mitä tapahtuu ja voidaan korjata sitä. Kokeilimme siis vähentää t:stä ensimmäisen ehdon raja-arvon (300).

(define (oma-kuva t)
  (if (< t 300)
      (circle t "solid" "red")
      (circle (- t 300) "solid" "red")))


Nyt ympyrä ei pienentynyt vaan palasi pieneksi ja lähti uudelleen suurenemaan. No seuraavaksi kokeilimme laittaa t:n ja 300 toisinpäin ehkäpä se auttaisi pienenemisessä?

(define (oma-kuva t)
  (if (< t 300)
      (circle t "solid" "red")
      (circle (- 300 t) "solid" "red")))


Nyt saimme tällaisen virheilmoituksen:
circle: expects a non negative real number as first argument, given -1

Tämän virheilmoituksen tulkinta oli helppoa: ympyrän säde ei voi olla negatiivinen. Ja negatiivinen säteen arvo koodissamme tulee heti kun t menee yli 300, koska:

> (- 300 301)
-1

Totesimme, että ehkä meidän pitää oikeasti miettiä miten tämän pitäisi toimia. Teimme seuraavan taulukon Word:illä:



Saimme tehtyä punaisen rivin perusteella yhtälön:

x - 301 = 299

Ja tämä saataiin ratkaistua:

x = 600

Ja nyt saimme lisättyä oikean arvon koodiimme:

(define (oma-kuva t)
  (if (< t 300)
      (circle t "solid" "red")
      (circle (- 600 t) "solid" "red")))


Ja nyt ympyrämme sekä suureni, että pieneni mutta törmäsimme lopuksi taas samaan ongelmaan:

circle: expects a non negative real number as first argument, given -1

Tämä oli jo helpompi ymmärtää, koska tässä toistui sama ongelma kuin ennenkin, nyt t menee yli 600 ja säde menee taas miinukselle:

> (- 600 601)
-1

Tähän otimme ratkaisuksi jakojäännöksen eli koodauskielellä modulon. Modulon avulla voidaan rajoittaa t:n arvot välille 0-599, jolloin emme joudu koskaan negatiivisiin säteisiin. Jakojäännöksen käsite oli hyvin hallussa oppilailla, koska seuraava päättely ei tuottanut mitään ongelmia:

601 / 600 jakojäännös on 1
602 / 600 jakojäännös on 2
603 / 600 jakojäännös on 3
...

Lisäsimme modulon koodiin ja animaatiomme toimi nyt niinkuin pitääkin.

(define (kuva t)
  (place-image (oma-kuva (modulo t 600)

                250 250 
               (empty-scene 500 500)))
Nyt oppilaat saivat muuttaa ympyrän muodon joksikin toiseksi, muuttaa värit haluamakseen jne. Yksi oppilas keksi kysyä miten animaatioon saisi enemmän haaroja, ja selitin miten valintalause (cond) toimii. Seuraavalla kerralla jatkamme näitä oppilaiden omia animaatioita, ehkäpä cond-lauseella terästettynä.
Yksinkertaisen ympyrä-animaation takana on yllättävän paljon matematiikkaa ja ohjelmointitietämystä