lauantai 3. tammikuuta 2015

Seymour Papert:in Turtlet

Ostin itselleni joululahjaksi Seymour Papert:in klassikkokirjan "Mindstorms: Children, Computers, and Powerful Ideas". Vaikka kirja on ilmestynyt ensimmäisen kerran vuonna 1980, se on silti hämmästyttävän ajankohtainen ja ajatuksia herättelevä. Erityisesti Papertin kritiikki "koulumatematiikkaa" ja "koulufysiikkaa" kohtaan osui ja upposi. Ne todellakin ovat historian muovaamia konstruktioita, aihepiirejä joitka ovat valikoituneet mukaan sen mukaan mitä on perinteisesti voitu opettaa ja oppia niillä välineillä, joita kouluissa on ollut saatavilla: kynä, kumi, paperi, viivoitin ja harppi. Papert näki jo 1980, että tietokoneita käytettiin opetuksessa aivan väärin, niiden avulla yritettiin opettaa näitä "kuolleita kynä-plus-paperi-ajan taitoja". Hänen mielestään on jo lähtökohtaisesti väärin ohjelmoida drillaavia opetusohjelmia, jotka "ohjelmoivat" oppilaita toimimaan tietyllä tavalla. Hänen mielestään asian pitäisi olla täysin päinvastainen eli oppilaiden pitäisi päästä ratkomaan oikeita "aikuisten" ongelmia eli ohjelmoimaan tietokoneita. Tämä on Papertin mukaan ainoa tapa saada kuollut (paperille kirjoitettu) koulumatematiikka palautettua elävien kirjoihin.

Papertin ratkaisu tähän oli LOGO-ohjelmointikieli ja turtle-geometria, joita en itse lapsena valitettavasti päässyt kokeilemaan. Omassa peruskoulussani/lukiossani ei 1980-luvulla ollut tarjolla kuin konekirjoitusta. Heti kirjan luettuani halusin päästä kokeilemaan Turtlen ohjaamista, joten koodasin itselleni sellaisen Racket:illä. Halusin seurata kirjan "design principles"-ohjeita, ja tehdä niiden pohjalta oman versioni klassikosta. Jos Lego Mindstorms:in, Scratch:in sekä Turtle-Roy:n kehittäjät ovat seuranneet Papertin jalanjälkiä, niin aion minäkin. Ja kivastihan siinä lomapäivä vierähtikin...

Olin toki aikaisemminkin piirrellyt "turtle-geometrisia"-kuvioita Scratch:illä, joten periaate oli sinänsä tuttu. Miksi halusin tehdä vastaavan Racket:illä, johtui siitä että olemme jo käyttäneet oppilaideni kanssa Racket:iä, joten saman välineen kanssa jatkaminen tuntuisi paremmalta idealta kuin eri ympäristöjen välillä sinkoilu. 7. luokan koulugeometrian opettamisen lisäksi, mietin samalla miten voisin opettaa listojen ja rekursion käyttöä KoodauksenABC-kurssilaisilleni. Ja aina kannattaa käyttää tilaisuus hyväksi: koodaamista oppii vain itse koodaamalla :-)

Racket-turtle:a ohjataan periaatteessa samalla tavalla kuin esikuvaansa LOGO-Turtlea, mutta komennot annetaan listana. Esim. tämä koodin pätkä määrittelee Turtle-komentolistan neliön piirtämiselle:

(define neliö
  (list (forward 100)
        (turn-left 90)
        (forward 100)
        (turn-left 90)
        (forward 100)
        (turn-left 90)
        (forward 100)))


Varsinainen piirtäminen tehdään kutsumalla "piirrä"-funktiota tai "piirrä-osissa"-funktiota, joka piirtää kuvan pala palalta, kun jotain näppäintä painetaan. Eli näin piirrettäisiin neliö:

(piirrä neliö) TAI
(piirrä-osissa neliö)
Ensimmäinen Racket-turtlella piirretty kuvio
Kynän väri on oletuksena sininen ja se on aina laskettuna, mutta kynää voi halutessaan ohjailla myös näillä komennoilla:

(pen-up)
(pen-down)
(change-color "red")
(change-color (make-color 255 0 0))

Jos haluaa tehdä neliönsä älykkäämmin käyttäen toistorakennetta, sekin onnistuu repeat:in avulla:

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

(define toisto-neliö
  (repeat 4 sivu))


(piirrä toisto-neliö)

Jos haluaa tehdä samaan kuvaan kaksi kuviota, komentolistat voi yhdistään käyttämällä append:a:

(define siirry
  (list (pen-up)
        (forward 100)
        (pen-down)
        (change-color "red")))

(define kaksi-neliötä
  (append neliö
          siirry
          toisto-neliö))

Yhdistelmäkuvio

Koska Racket on oikea ohjelmointikieli, sillä voi koodata myös funktioita, jotka tekevät komentolistoja eri kokoisille tai värisille kuvioille. Nämä funktiot yhdessä piirtävät halutun kokoisen ja värisen neliön:

(define (sivu2 pituus kulma)
  (list (forward pituus)
        (turn-left kulma)))

(define (neliö2 pituus väri)
  (cons (change-color väri)
        (repeat 4 (sivu2 pituus 90))))


(piirrä (neliö2 50 "red"))
Neliö muuttuvalla sivun pituudella sekä värillä
Yllä olevan sivu2-koodin avulla voi rakentaa funktioita myös muille säännöllisille monikulmioille. Huomaa, että neliö2:ssa on käytetty cons:ia list:in tilalla, koska repeat palauttaa kokonaisen listan ja (change-color väri) on pelkkä lista-alkio (list vaatisi kaksi lista-alkiota ja append puolestaan kaksi listaa). Racket-turtlen yksi tarkoitus on opettaa listojen käsittelyä, ja listojen käsittelyssä on pidettävä mielessä listan ja alkion ero. Seuraava dia selventänee list, cons ja append - funktioiden käyttöä:

Mitä eroa on list, cons ja append - funktioilla

Kun sain Racket-turtleni toimimaan, mopo karkasi välittömästi lapasista ja huomasin leikkiväni sillä  kuin pieni lapsi. Illan aikana tuli piirrettyä mm. nämä Papertin kirjan innoittamat kuviot:
Ympyrä-kukka


Random-kukat (random koko, random väri)
Vino "squiral"
Ja tässä vielä video Racket-turtlen toiminnasta (melko hypnoottista):


Jos haluat itse kokeilla Racket-turtlea niin lataa tästä tiedosto ja avaa se DrRacket:iin. Kirjoita tiedoston loppussa olevien esimerkkien tilalle omat komentosi. Pidä hauskaa!

Videolla näkyvä "squiral" on toteutettu rekursion avulla. Jos haluat kokeilla sitä itse niin tässä on koodi, joka generoi tarvittavan komentolistan Racket-turtlelle:

(define (squiral pituus kerrokset)
  (if (<= kerrokset 0)
      '()
      (append (list (forward (* 5 pituus)) 

                    (turn-left 90)) 
              (squiral (add1 pituus) (sub1 kerrokset)))))

2 kommenttia:

  1. Ero komennon ja komentolistan välillä vaikuttaa aiheuttavan turhia hankaluuksia. Tulee mieleen ainakin kaksi ratkaisua: 1. Komennot suoritettaisiin rekursiivisesti sisäkkäisistäkin listoista, jolloin toimisi myös esim. (list neliö siirry). 2. Uusi komento "sequence", "block" tms., joka suoritettaessa suorittaisi parametrina annetun komentolistan. Tätä käytettäisiin sitten list-funktion sijaan omia komentoja määriteltäessä.

    VastaaPoista
    Vastaukset
    1. Kiitos kommentista! Tein Racket-turlen ajatellen kahta käyttöä, listojen ja rekursion opettamista sekä geometrian opettamista. En ole vielä käyttänyt tätä koodia luokkatilanteessa, joten en osaa sanoa aiheuttaako listojen käsittely (liikaa) ongelmia 7.luokkalaisille. Näin jätettynä se ainakin vaatii koodaria ajattelemaan listan rakennetta, eli pakottaa oppimaan listan käsittelyn perusjutut. Mutta ehdottomasti hyvä pointti mietittäväksi!

      Poista