Tämä kurssi on jo päättynyt.

Kurssin viimeisimmän version löydät täältä: O1: 2024

Luku 3.5: Valintoja, valintoja

Tästä sivusta:

Pääkysymyksiä: Pitäisikö vielä treenata valintakäskyä? Miten saan pelini käyttäytymään ennalta-arvaamattomammin? Miten teen pelintapaisia, joissa voin liikuttaa hahmoa vapaasti eri suuntiin?

Mitä käsitellään? if-käskyä edelleen. Satunnaisuutta. Esimerkkejä yksityisestä metodista. Lisätehtävissä mm. tyyppi o1.Direction.

Mitä tehdään? Ohjelmoidaan: tarjolla on muutama pisteytetty tehtävä ja lisätehtäviä.

Suuntaa antava työläysarvio:? Pisteytettyihin tehtäviin menee tuskin tuntiakaan. Lisätehtävissä on haastavampiakin.

Pistearvo: A25.

Oheisprojektit: FlappyBug, Odds. Lisätehtävissä MoreApps (uusi).

../_images/person05.png

FlappyBug-tehtävä (osa 12/16: toistuva este)

Alkusanat

FlappyBug-pelissämme maiseman poikki kulkee toistaiseksi este vain kerran. Se ei oikein tyydytä. Tyydyttävämpää olisi, jos ötökälle tulisi toistuvasti uusia esteitä ohitettavaksi.

Voimme lähestyä ongelmaa kahdella eri tavalla:

  1. Kun este on liikkunut pois näkyvistä maiseman vasemmasta reunasta eli ei ole enää "aktiivinen", luodaan uusi esteolio, joka sijaitsee oikealla. Korvataan peliin aiemmin liitetty esteolio tällä uudella esteellä. Vanha esteolio jää ilman käyttöä.
  2. Kun este on liikkunut pois näkyvistä maiseman vasemmasta reunasta eli ei ole enää "aktiivinen", siirretään se oikealle yksinkertaisesti vaihtamalla sen koordinaatteja. Teknisessä mielessä ötökkä siis kohtaa saman esteolion aina vain uudelleen, mutta käytännössä näyttää siltä kuin oikealta saapuisi toistuvasti uusia esteitä.

Kumpikaan vaihtoehdoista ei ole yksiselitteisesti parempi kuin toinen. Valitsemme nyt jälkimmäisen tavan, joka on helppo toteuttaa.

Tehtävänto

Lisää ensin Obstacle-luokkaan vaikutukseton ja parametriton metodi isActive, joka palauttaa true, jos esteen oikea reuna on ruudun vasemmassa laidassa tai sen oikealla puolella, ja false muuten. Esimerkiksi jos 50-säteisen esteen keskipisteen x-koordinaatti on -50, niin este juuri ja juuri luetaan vielä aktiiviseksi, mutta yhtään pienemmällä koordinaatilla ei luettaisi.

Muokkaa sitten estettä liikuttavaa approach-metodia. Obstacle-luokassa on siitä ennestään tällainen versio:

def approach() = {
  this.currentPos = this.currentPos.addX(-ObstacleSpeed)
}

Muuta metodi sellaiseksi, että se tilanteesta riippuen joko liikuttaa estettä vasemmalle tai siirtää sen takaisin oikealle. Tarkemmin sanoen:

  • Mikäli este oli kutsuhetkellä aktiivinen, niin se liikkuu kuten ennenkin.
  • Mikäli este ei ollut aktiivinen, niin sen uudeksi x-koordinaatiksi tulee näkyvän pelimaailman leveys plus 250 (käytännössä 1250) ja y-koordinaatiksi puolet pelimaailman korkeudesta (käytännössä 200). Este lähtee siis uudelleen liikkeelle jonkin verran pelialueen oikean reunan takaa, pystysuunnassa keskeltä.

Palauttaminen

A+ esittää tässä kohdassa tehtävän palautuslomakkeen.

Loppusanat

Maiseman poikki kulkee nyt este useasti mutta ilmestyen aina samaan kohtaan. Se ei oikein tyydytä. Tyydyttävämpää olisi, jos esteet ilmestyisivät arvaamattomampiin paikkoihin.

Miten saisimme esteen koordinaatit valittua satunnaisesti?

Tämä onkin ihan oma ongelmansa. Käsitellään satunnaisuutta ensin vähän yleisemmin.

Satunnaisluvuista

Tuota päässäsi luettelo 30 täysin satunnaisesta luvusta väliltä 0–9. Jokaista numeroa "arpoessasi" täytyy jokaisella vaihtoehdolla olla täsmälleen yhtä suuri todennäköisyys tulla valituksi. Ulkoisten apuvälineiden käyttö on kiellettyä.

Random-luokka

Hyviä uutisia: Scalassa on luokka nimeltä Random, jolla voi helposti tuottaa satunnaislukuja:

import scala.util.Randomimport scala.util.Random
val generaattori = new Random(74534161)generaattori: scala.util.Random = scala.util.Random@1413cb7
generaattori.nextInt(10)res0: Int = 3
generaattori.nextInt(10)res1: Int = 8
generaattori.nextInt(10)res2: Int = 7
generaattori.nextInt(10)res3: Int = 2
generaattori.nextInt(10)res4: Int = 3
generaattori.nextInt(10)res5: Int = 2
Random-oliot ovat "satunnaislukugeneraattoreita". Niitä kuvaava luokka löytyy pakkauksesta scala.util. (Tämä Scala API:n pakkaus sisältää sekalaisia työkaluja. Sen nimi tulee sanasta utilities.)
Random-olioilla on erilaisia arvojen arpomiseen sopivia metodeita. Usein hyödyllinen on metodi nextInt(n: Int), joka arpoo luvun nollan ja n-1:n väliltä.
Esimerkiksi kun kutsutaan metodia parametrilla 10, saadaan lukuja väliltä 0–9.
Mikä tuo tuolla suluissa on? Palataan siihen hetken päästä.

Voit itse kokeilla antaa samat käskyt REPLissä. Jos kokeilet, saat täsmälleen saman luettelon satunnaislukuja nextInt-metodin palautusarvoina: 3, 8, 7, 2, 3, 2, jne.

Mitä ihmettä? Lukujenhan piti olla satunnaisia.

Näennäissatunnaisluvut

The generation of random numbers is too important to be left to chance.

—Robert Coveyou

"Tuota 30 täysin satunnaista lukua väliltä 0–9" on ihmiselle paha pala purtavaksi. Yksi mahdollisuus on käyttää jotain "riittävän hyvää" matemaattista algoritmia, jolla muodostetaan lukujen sarja. Esimerkiksi:

  • Valitse jokin luku N, esim. N=20
  • Ota N:s piin desimaali. Se olkoon ensimmäinen "satunnaisluku".
  • Määritä seuraava "satunnaisluku" ottamalla piin desimaali kohdasta 2*N.
  • Sitten 3*N, 4*N ja niin edelleen

Myös tietokoneelle satunnaislukujen generointi on hankala ongelma. Aitoa satunnaisuutta se ei osaa nyhjäistä tyhjästä.

Tietyn algoritmin tuottamat luvut ovat ns. näennäissatunnaislukuja (pseudorandom numbers). Samalla "aloitusluvulla" eli satunnaislukujen siemenellä (seed) saadaan aina sama näennäissatunnaislukujen sarja. Esimerkiksi yllä hahmotellussa algoritmissa N oli siemen, ja aina tätä algoritmia N:n arvolla 20 sovellettaessa saadaan samat luvut.

On kehitelty erilaisia algoritmeja näennäissatunnaislukujen generointiin. Esimerkiksi Scalan luokka Random käyttää erästä tällaista algoritmia (johon ei tällä kurssilla perehdytä tarkemmin). Algoritmin siemenenä toimii luku, joka annetaan oliolle konstruktoriparametriksi (esim. yllä luku 74534161).

Se, että algoritmi tuottaa tietyllä siemenluvulla aina saman näennäissatunnaislukujen sarjan, voi olla tilanteesta riippuen joko etu (esim. jos on tarpeen pystyä toistamaan tietty alun perin satunnaisesti valittu tapahtumasarja) tai haaste (jos halutaan joka kerta täysin erillinen satunnaislukusarja).

Siemenluku kellonajasta

On erilaisia tapoja valita siemenluku. Joskus voi olla perusteltua pyytää siemenluku käyttäjältä. Voidaan myös käyttää apuna jotakin ympäristön "riittävän satunnaista" piirrettä; perinteinen konsti on käyttää siemenenä tietokoneen ajohetkistä päiväystä ja kellonaikaa esimerkiksi nanosekunnin tarkkuudella.

Monissa tilanteissa ei ole väliä, mitä nimenomaista siemenlukua käytetään. Siksi scala.util-pakkaukseenkin on määritelty Random-luokan lisäksi myös Random-niminen yksittäisolio, jolta voi pyytää kellonajan pohjalta "arvottuja" satunnaislukuja luomatta erikseen Random-oliota lainkaan:

import scala.util.Randomimport scala.util.Random
Random.nextInt(10)res6: Int = 8
Random.nextInt(10)res7: Int = 6
Random.nextInt(10)res8: Int = 2

Jos kokeilet näitä käskyjä itse, saat (erittäin todennäköisesti) eri palautusarvot.

FlappyBug-tehtävä (osa 13/16: arvaamattomampi este)

Pohjustus: randomLaunchPosition-metodi

Laaditaan Obstacle-luokkaan uusi metodi, jonka tehtävänä on arpoa lähtösijainti ruudun oikealta puolelta lähtevälle esteelle. Tässä alku:

private def randomLaunchPosition() = {
  val launchX = Laske yhteen ruudun leveys (1000), esteen säde ja satunnainen kokonaisluku väliltä 0—499.
  val launchY = Arvo satunnainen kokonaisluku, joka on vähintään 0 ja pienempi kuin ruudun korkeus (400).
  new Pos(launchX, launchY)
}
Pari lauseketta on jätetty täydennettäväksesi.
Tämä metodi on yksityinen. Se on tarkoitettu vain Obstacle-luokan sisäiseen käyttöön eikä kuulu julkiseen rajapintaan. (Vrt. yksityiset muuttujat; luku 3.1.)

Tehtävänanto

  1. Toteuta randomLaunchPosition. Käytä yllä olevaa koodia pohjana ja täydennä se puuttuvin osin.
  2. Muokkaa approach-metodia siten, että se ei aseta vasemman laidan ohittanutta estettä vakiopaikkaan vaan kutsuu randomLaunchPosition-metodia saadakseen sille uuden sijainnin.
  3. Muokkaa Obstacle-luokkaa siten, että estettä luodessa ei enää anneta konstruktoriparametriksi lähtösijaintia vaan vain säde. Sen sijaan luotava esteolio käyttää randomLaunchPosition-metodiaan arpoakseen itselleen lähtösijainnin.

Ohjeita ja vinkkejä

  • Käytä arpomisolioon Random-yksittäisolion metodia, niin saat eri pelikerroilla erilaisia tuloksia.
  • Voit myös kokeilla siemenluvun kirjaamista koodiin ja havaita, että tällöin este ilmestyy joka pelikerralla samoihin paikkoihin.

Palauttaminen

A+ esittää tässä kohdassa tehtävän palautuslomakkeen.

Pelottavampaa grafiikkaa peliin

Hylkää FlappyBugApp-ohjelman toistaiseksi käyttämä rockPic. Vaihda esteen kuvaksi Pic("obstacle.png"), jonka skaalaat oikean kokoiseksi metodikutsulla scaleTo(esteenHalkaisija). Pelaa jos uskallat.

Lisää tehtäviä

Odds-tehtävä (osa 9/9)

Lisää Odds-projektin samannimiseen luokkaan metodi eventHappens, joka arpoo, toteutuuko tapahtuma, jolla on Odds-olion kuvaama todennäköisyys tapahtua:

val nopallaKuutonen = new Odds(5, 1)nopallaKuutonen: Odds = 5/1
nopallaKuutonen.eventHappens()res9: Boolean = false
nopallaKuutonen.eventHappens()res10: Boolean = false
nopallaKuutonen.eventHappens()res11: Boolean = true
Metodia kutsuttaessa tulee satunnaisesti joko true tai false. Tässä nopanheittoa kuvaavassa tapauksessa false tulee koko lailla viisi kertaa niin usein kuin true.

Metodi on vaikutuksellinen, koska se kutsuu vaikutuksellista nextInt-metodia. Käytä siksi määrittelyssä tyhjiä kaarisulkeita parametriluettelona (luku 2.6). Metodi nextInt lasketaan vaikutukselliseksi, koska se vaikuttaa satunnaislukugeneraattorin sisäiseen tilaan.

Muista, että Random pitää ottaa käyttöön pakkauksesta scala.util. Ja muista että Random.nextInt(n) palauttaa luvun nollan ja n-1:n väliltä.

A+ esittää tässä kohdassa tehtävän palautuslomakkeen.

Ohjastusta näppäimistöllä

MoreApps-projektin pakkauksessa o1.trotter on pieni sovellus, jossa voi juoksuttaa virtuaalista heppaa ruudukkotaustaa vasten. Heppa liikkuu ruudusta toiseen kellon tikittäessä. Sen suunta vaihtuu nuolinäppäimillä, tai ainakin on tarkoitus vaihtua.

../_images/trotter.png

Pakkauksesta löytyy luokka TrotterGame, jota käytämme aihealueen mallina. Voit tutustua sen koodiin muiltakin osin, mutta tämän tehtävän kannalta keskeiset asiat on selitetty tässä:

import o1._, o1.trotter._import o1._
import o1.trotter._
val game = new TrotterGame(5, 40)game: o1.trotter.TrotterGame = a 5-by-5 grid
game.horseHeadingres12: o1.Direction = Direction.Right
game.horseHeading = Direction.Up
Tässä esimerkissä luodaan hyvin pieni maailma hepan temmellyskentäksi. Siinä on viisi kertaa viisi ruutua, ja heppa askeltaa 40 koordinaattiyksikköä eli yhden ruudun kerrallaan (ks. kuva).
Muuttujan horseHeading arvo on O1Libraryyn kuuluvaa tyyppiä Direction. Direction kuvaa suuntia sellaisissa kaksiulotteisissa koordinaatistoissa, joiden sijainteja kuvaamme Pos-olioilla.
Kyseessä on var-muuttuja, joten voimme sijoittaa sille uuden arvon. Mielekkäitä arvoja ovat tässä Direction.Up, Direction.Down, Direction.Right ja Direction.Left.

Projektista löytyy myös käyttöliittymä TrotterApp, joka luo isomman ruudukon. Kokeile ajaa se. Heppa liikkuu. Voit painella nuolinäppäimiä, mutta huomaat, että hepan saa käännettyä niillä vain ylös.

TrotterApp-ohjelmassa on valmiina grafiikan tuottava koodi ja onTick-metodi. Lisäksi siellä on alku onKeyDown-metodille, joka tehtävänä on tulkita näppäinten (Key) painallukset ja valita hepalle näppäintä vastaava suunta (Direction). Annettu koodi on tällainen:

override def onKeyDown(key: Key) = {
  if (key == Key.Up) {
    game.horseHeading = Direction.Up
  }
}

Koodissa esiintyy kaksi eri Up-käsitettä:

Key.Up on vakio, joka tarkoittaa ylöspäin osoittavaa nuolinäppäintä. Direction.Up on suunta suoraan ylös, kohti pienempiä y-koordinaatteja.

Virallinen tehtäväsi on vain täydentää tämä metodi sellaiseksi, että se ohjaa heppaa myös muihin kolmeen pääsuuntaan (Right, Down, Left). Voit tehdä tämän lisäämällä metodiin vastaavia if-käskyjä (vaikka koodista näin konstein tuleekin toisteista).

Voit myös kehitellä ohjelmaa pidemmälle haluamallasi tavalla.

A+ esittää tässä kohdassa tehtävän palautuslomakkeen.

Kiihdytystä näppäimistöllä

MoreApps-projektin pakkauksessa o1.charger on edellistä muistuttava sovellus, jossa kappaletta liikutetaan koordinaatistossa. Tässä sovelluksessa näppäimet antavat “ryntääjälle” vauhtia, joka kasvaa näppäintä pohjassa pidettäessä.

Annettu koodi ei saa ryntääjää liikkeelle. Korjaa asia:

  1. Täydennä onKeyDown-metodi vastaavaksi kuin aiemmassa tehtävässä: käyttöliittymän on havaittava neljän nuolinäppäimen painallukset ja kutsuttava niitä vastaavilla Direction-parametreilla ryntääjän accelerate-metodia.

  2. Tutustu Charger-luokan koodiin. Luokan haluttu toiminta on kuvattu Scaladoc-kommenteissa ja niiden perusteella luodussa dokumentaatiossa. Suuri osa on jo toteutettu, mutta huomaat, että osia puuttuu.

  3. Täydennä if-käskyn haarat metodiin accelerate siten, että ne säätävät ryntääjän vauhtia ja kulkusuuntaa halutusti.

  4. Täydennä move-metodi siten, että se muuttaa ryntääjän sijaintia vauhdin ja suunnan perusteella.

    • Annetussa koodissa on esimerkki Direction-olion dx-muuttujasta, joka kertoo, paljonko x-koordinaatti muuttuu, jos liikutaan yksi yksikkö kyseiseen suuntaan. Direction.Rightin dx on siis +1, Leftin -1, ja ylä- ja alasuuntien nolla. Vastaavasti on olemassa dy.
    • Tuota tietoa hyödyntämällä on move yksinkertaisempi toteuttaa. (Voit myös palata etsimään vinkkiä edellisen tehtävän TrotterGame-luokasta.)
  5. Kokeile ohjelmaa.

  6. Ryntääjän kuvan soisi vastaavan sen suuntaa. Muutos on helppo. Tiedämme jo, että Pic-luokassa on pyörittämiseen sopivat metodit clockwise ja counterclockwise (luku 2.3). Lisäksi jokaisella Direction-oliolla on metodi toDegrees, jota voi käyttää näin:

    Direction.Up.toDegreesres13: Double = 90.0
    Direction.Left.toDegreesres14: Double = 180.0
    

    Vapaasti muotoillen: metodi kertoo, montako astetta kyseinen suunta poikkeaa oikealle osoittavasta suunnasta vastapäivään lukien. Esimerkiksi Direction.Up on 90 astetta vastapäivään Direction.Rightista.

    Muokkaa käyttöliittymän makePic-metodia siten, että se pyöräyttää kuvan osoittamaan kohti menosuuntaa.

A+ esittää tässä kohdassa tehtävän palautuslomakkeen.

Nopeuden mallintaminen Velocity-luokalla

Äsken kuvasimme erikseen ryntääjän vauhtia (sijainnin muutosten suuruutta) ja suuntaa. Yhdessä vauhti ja suunta muodostavat nopeuden (velocity).

On luontevaa ja kätevää määritellä nopeuden käsitettä kuvaamaan oma luokkansa. Eikä sinun nyt tarvitse määritellä sitä itse: nopeus on monessa ohjelmassa hyödyllinen käsite, jota vastaava luokka löytyy kurssin ohjelmakirjastosta:

Nopeus koostuu suunnasta ja vauhdista.

Velocity-luokassa on paljon metodeita, joista osasta on hyötyä myöhemmin ja osa sopii käytettäväksi juuri nyt:

  1. Silmäile Velocity-luokan dokumentaatiota. Huomaa erityisesti metodit faster, noFasterThan ja nextFrom.
  2. Refaktoroi Charger-luokkaa (eli muokkaa koodia sen toiminnallisuutta muuttamatta): Korvaa erilliset angle- ja speed- muuttujat yhdellä Velocity-tyyppisellä muuttujalla. Käytä tätä muuttujaa metodien heading, accelerate ja move uusituissa versioissa.
    • Älä koske luokan julkiseen rajapintaan. Metodien tulee edelleen tehdä samat asiat kuin ennenkin.

A+ esittää tässä kohdassa tehtävän palautuslomakkeen.

Sulavaa liitoa näppäimistöllä

Äskeisessä ohjelmassamme on monia vajavaisuuksia. Härkä kääntyy kovin jähmeästi. Lisäksi tapa, jolla näppäimenpainalluksiin reagoidaan, ei ole teknisesti tyydyttävä:

  • Ohjelmaa ajava ympäristö kutsuu onKeyDown-metodia, kun näppäin painuu alas. Lisäksi tuo metodi tulee kutsutuksi silloin tällöin niin kauan kuin näppäin pysyy alhaalla. Näiden myöhempien onKeyDown-kutsujen määrä ei kuitenkaan ole standardi ja riippuu osin ympäristöstä, jossa ohjelmaa ajetaan. Ohjelmamme käyttäytyminen ei siksi ole luotettavalla pohjalla.
  • Samoin onKeyDown-metodin luonteesta johtuen usean näppäimen käyttö yhdistelmänä ei toimi niin kuin voisi toivoa: jos näpäytät yhtä nuolinäppäintä toisen ollessa pohjassa, niin ohjelma "unohtaa" pohjassa olleen suunnan. (Kokeile.) Tämä ei tunnu luonnolliselta eikä lupaa hyvää, jos vaikka haluaisimme liikuttaa härkää vinoon kahden näppäimen yhdistelmällä.

Lähestytään pohjassa olevien näppäinten käsittelyä hieman toisin. Tämä toinen tapa on aavistuksen mutkikkaampi mutta toisaalta helpottaa sulavampien liikkeiden ohjelmointia.

Pakkauksessa o1.glider on pohjakoodi "liituria" ohjaavalle ohjelmalle. Se muistuttaa muistuttaa äskeistä ohjelmaa monin osin.

  1. Tutustu GliderApp-ohjelmaan. Huomaa ainakin nämä:
    • onTick-tapahtumankäsittelijä yksinkertaisesti komentaa liituria liitämään kullakin kellonlyömällä.
    • Keskeinen uudistus verrattuna edelliseen ohjelmaan löytyy metodista onKeyDown: se ei varsinaisesti kasvata liiturin nopeutta vaan vain asettaa tiedon siitä, että "kaasu on pohjassa", kun ylänuolinäppäintä painetaan.
    • Vastaava onKeyUp käsittelee näppäimen irtipäästötapahtumia.
  2. Tutki Glider-luokkaa. Huomaa ainakin nämä:
    • Liiturin nopeus on kuvattu Velocity-oliolla.
    • Lisäksi liiturilla on kolme Boolean-tyyppistä ominaisuutta, jotka kertovat, onko kaasu pohjassa sekä onko "rattia" käännetty vasempaan tai oikeaan.
    • Liikkeestä huolehtii glide-metodi apumetodeineen. Se säätää nopeutta ohjaimien perusteella ja liikuttaa liituria säädetyn nopeuden mukaan.
    • Liiturissa ei ole jarruja mutta "kitka" hidastaa liituria hieman joka liikahduksen lopuksi, joten ilman kaasutusta liituri pysähtyy aikanaan itsekseen.
  3. Varsinainen liiturin siirtäminen ja kitkan huomiointi ovat valmiina. Toteuta nopeuden ja suunnan säätö; tavoite on selitetty glide-metodin kuvauksessa.
    • Huomaat, että glide delegoi tämän osatehtävän yksityiselle apumetodille adjustVelocity. Voit tehdä tarvittavat muutokset sinne.
  4. Voit jo tässä vaiheessa koeajaa GliderAppin. Liiturin pitäisi lähteä ylänuolta painaessa eteenpäin ja vähitellen hidastua itsestään. Se ei vielä käänny.
  5. Täydennä GliderAppin tapahtumankäsittelijät siten, että ne välittävät tiedon sivunuolten painalluksista Glider-oliolle.

A+ esittää tässä kohdassa tehtävän palautuslomakkeen.

Toinenkin liituri?

Jos haluat, voit kokeilla lisätä näkymään toisenkin liiturin, joka liikkuu esimerkiksi W-, A-, ja D-näppäimillä.

Jos tuloksena syntyi toimivaa mutta toisteista koodia, voit miettiä, miksi niin kävi. Kurssin edetessä löydämme lisää keinoja toiston kitkemiseen.

Lisänäppäimiä

Miten olisi helppo reagoida esimerkiksi Shift-painallukseen hiirellä? Tai selvittää, onko Shift-, Ctrl-, tai Alt-erikoisnäppäin pohjassa, kun toista näppäintä painetaan?

Luvun 2.8 lisätehtävässä käsittelijämetodin parametrina oli hiirenklikkausta kuvaava MouseClicked-olio eikä pelkkä klikkauksen sijainti. Tapahtumankäsittelijoitä voi muutenkin määritellä siten, että käsittelijämetodi saa parametrikseen viittauksen kyseistä tapahtumaa yleisesti kuvaavaan olioon. Tällaiselta tapahtumaa kuvaavalta oliolta voi pyytää tiedon muun muassa siitä, onko tietty erikoisnäppäin painallettuna tapahtumahetkellä. Tässä pari esimerkkiä:

override def onClick(mouseEvent: MouseClicked) = {
   println(mouseEvent.isControlDown)
}
override def onKeyDown(keyPressEvent: KeyPressed) = {
  println(keyPressEvent.isAltDown)
}
Huomaa parametrimuuttujien tyypit.

Voit kokeilla lisätä tällaiset metodit johonkin aiemmista ohjelmista. Voit myös etsiä muita vastaavia tapahtumankäsittelijöitä View-luokan dokumentaatiosta. Ehkä kehität myös jonkin sovelluksen, jossa erikoisnäppäimillä on vaikutus ohjelman toimintaan?

Yhteenvetoa

  • Satunnaisten lukujen arpominen ei ole ongelmatonta.
  • Muun muassa Scala-peruskirjastossa on välineitä näennäisen satunnaisuuden tuottamiseen.
  • Luokan sisäiseen käyttöön voi laatia yksityisiä apumetodeita.
  • Lukuun liittyviä termejä sanastosivulla: if; näennäissatunnaisluku, satunnaislukujen siemen; yksityinen.

Palaute

Huomaathan, että tämä on henkilökohtainen osio! Vaikka olisit tehnyt lukuun liittyvät tehtävät parin kanssa, täytä palautelomake itse.

Tekijät

Tämän oppimateriaalin kehitystyössä on käytetty apuna tuhansilta opiskelijoilta kerättyä palautetta. Kiitos!

Kierrokset 1–13 ja niihin liittyvät tehtävät ja viikkokoosteet on laatinut Juha Sorva.

Kierrokset 14–20 on laatinut Otto Seppälä. Ne eivät ole julki syksyllä, mutta julkaistaan ennen kuin määräajat lähestyvät.

Liitesivut (sanasto, Scala-kooste, usein kysytyt kysymykset jne.) on kirjoittanut Juha Sorva sikäli kuin sivulla ei ole toisin mainittu.

Tehtävien automaattisen arvioinnin ovat toteuttaneet Riku Autio, Jaakko Kantojärvi, Teemu Lehtinen, Timi Seppälä, Teemu Sirkiä ja Aleksi Vartiainen.

Lukujen alkuja koristavat kuvat ja muut vastaavat kuvituskuvat on piirtänyt Christina Lassheikki.

Yksityiskohtaiset animaatiot Scala-ohjelmien suorituksen vaiheista ovat suunnitelleet Juha Sorva ja Teemu Sirkiä. Niiden teknisen toteutuksen ovat tehneet Teemu Sirkiä ja Riku Autio käyttäen Teemun toteuttamia Jsvee- ja Kelmu-työkaluja.

Muut diagrammit ja materiaaliin upotetut vuorovaikutteiset esitykset on laatinut Juha Sorva.

O1Library-ohjelmakirjaston ovat kehittäneet Aleksi Lukkarinen ja Juha Sorva. Useat sen keskeisistä osista tukeutuvat Aleksin SMCL-kirjastoon.

Opetustapa, jossa käytämme O1Libraryn työkaluja (kuten Pic) yksinkertaiseen graafiseen ohjelmointiin on saanut vaikutteita tekijöiden Flatt, Felleisen, Findler ja Krishnamurthi oppikirjasta How to Design Programs sekä Stephen Blochin oppikirjasta Picturing Programs.

Oppimisalusta A+ on luotu Aallon LeTech-tutkimusryhmässä pitkälti opiskelijavoimin. Pääkehittäjänä toimii tällä hetkellä Jaakko Kantojärvi, jonka lisäksi järjestelmää kehittävät useat tietotekniikan ja informaatioverkostojen opiskelijat.

Kurssin tämänhetkinen henkilökunta on kerrottu luvussa 1.1.

Joidenkin lukujen lopuissa on lukukohtaisia lisäyksiä tähän tekijäluetteloon.

../_images/imho3.png
Palautusta lähetetään...