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

Luku 3.3: Kokemuksia ja totuusarvoja

Tästä sivusta:

Pääkysymyksiä: Millaisia luokkia on GoodStuff-esimerkkiprojektissa? Miten vertailen arvoja keskenään? Miten ilmaisen ohjelmassa, onko tietty arvo suurempi kuin toinen, tai vastaavia "juu tai ei" -tietoja? Miten saan ötökän mätkähtämään päin estettä?

Mitä käsitellään? Totuusarvot, Boolean-tietotyyppi ja vertailuoperaattorit.

Mitä tehdään? Luetaan ja kokeillaan itse mukana.

Suuntaa antava työläysarvio:? Pari tuntia.

Pistearvo: A70.

Oheisprojektit: GoodStuff, Oliointro, Odds, FlappyBug. Vapaaehtoisessa tehtävässä esiintyy myös projekti Miscellaneous (uusi).

../_images/person05.png

Kertausta: GoodStuff

Luvussa 2.1 tutustuit esimerkkiin siitä, miten GoodStuff-ohjelman luokat toimivat yhteen. Se kannattaa nyt kerrata. Tässä uusinta:

GoodStuff-projektin osat

Tässä luvussa alamme tutkia GoodStuff-sovelluksen Scala-ohjelmakoodia. Se koostuu seuraavista osista.

../_images/goodstuff-fi.png

GoodStuff-ohjelman käyttöliittymä. Iloisella irvinaamalla merkitään se kokemus, jolle käyttäjä on antanut korkeimman arvosanan.

Pakkaus o1.goodstuff:

  • Experience-luokka kuvaa kokemuksista tehtyjä muistikirjamerkintöjä; yksi luokan ilmentymä on yksi tällainen merkintä. Tätä luokkaa tutkitaan tässä luvussa ja vähän seuraavassakin.
  • Category-luokan avulla voidaan koota useita kokemusolioita yhteen kokemuskategoriaan. Kullakin kategorialla on nimi ja hinnoitteluyksikkö (esim. hotelliyö). Kategoriaan myös liittyy tieto siitä, mikä kyseisen kategorian kokemuksista on käyttäjän suosikki. Tähän luokkaan tutustumme luvussa 4.2.

Pakkaus o1.goodstuff.gui:

  • CategoryDisplayWindow on luokka, joka kuvaa eräänlaisia käyttöliittymäikkunoita. Annetussa muodossaan GoodStuff-sovelluksessa on tasan yksi tällainen ikkuna hotellikategorialle, mutta periaatteessa niitä voisi olla useitakin. Ikkuna on toteutettu Swing-kirjastolla, josta kerrotaan luvussa 12.3.
  • GoodStuff on yksittäisolio, jolla on erikoistehtävä: se toimii sovelluksen käynnistysoliona (luku 2.7). Kyseessähän on tiedosto GoodStuff.scala, josta käsin olet käynnistänyt sovelluksen Eclipsessä.

Tässä luvussa siis keskitymme luokkaan Experience. Samalla osoittautuu oitis, että on syytä tutustua erääseen uuteen Scalan perustietotyyppiin ja siihen liittyviin yleisempiin ohjelmoinnin käsitteisiin.

Lue dokumentaatiota!

Etsi nyt käsiisi Experience-luokan Scaladoc-dokumentaatio GoodStuff-projektista Eclipsessä tai tämän sivun alussa olevasta projektilinkistä. Lue se. Jatka vasta, kun olet lukenut sen.

Muiden projektiin kuuluvien luokkien dokumentaatiota ei ole tarpeen nyt lukea.

Experience-kokeilu

Kokeillaan Experience-luokan käyttöä REPLissä. Experience-oliolle annetaan luotaessa konstruktoriparametreiksi nimi, kuvaus, hinta ja arvosana. Annetussa sovelluksessa merkinnät koskivat hotellikokemuksia, mutta se ei ole oleellista. Tehdään nyt vaihtelun vuoksi vaikkapa viinikokemuksia kuvaavia olioita:

import o1.goodstuff._import o1.goodstuff._
val wine1 = new Experience("Il Barco 2001", "ookoo", 6.69, 5)wine1: o1.goodstuff.Experience = o1.goodstuff.Experience@a62427

Experience-luokkaa voi käyttää sen Scaladoc-dokumentaatiossa kuvatulla tavalla. Tässä pari esimerkkiä:

wine1.nameres0: String = Il Barco 2001
wine1.valueForMoneyres1: Double = 0.7473841554559043

Jotta GoodStuff-ohjelma voisi pitää kirjaa tietyn kategorian suosikista, sen täytyy pystyä vertailemaan kokemusmerkintöjä niiden arvosanojen perusteella. Tähän liittyen Experience-luokkaan on määritelty kaksikin metodia: isBetterThan ja chooseBetter. Näistä ensimmäisen ymmärtäminen edesauttaa jälkimmäisen ymmärtämistä; siksi aloitamme siitä. Kokeillaan nyt isBetterThan-metodia ja pureudutaan chooseBetter-metodiin seuraavassa luvussa.

val wine2 = new Experience("Tollo Rosso", "turhahko", 6.19, 3)wine2: o1.goodstuff.Experience = o1.goodstuff.Experience@140b3c7
wine2.isBetterThan(wine1)res2: Boolean = false
Kun kokemusolion isBetterThan-metodia kutsutaan, sille pitää antaa parametriksi viittaus johonkin kokemusolioon, johon "puhuteltavaa" oliota verrataan.
Metodi vertailee toisiinsa sitä kokemusta, jolle metodia on kutsuttu, ja sitä, joka on annettu parametriksi. Se palauttaa arvon, joka kertoo, onko ensin mainitun olion arvosana parametriolion arvosanaa korkeampi.
Palautusarvo ei kuitenkaan näytä ihan tutulta. Mikä on arvo false ja mikä on Boolean-tietotyyppi, jota se edustaa?

Totuusarvot ja Boolean

Kaksijakoiset tilanteet ovat ohjelmissa erittäin yleisiä: Onko tämä luku suurempi kuin tuo? Löytyvätkö tietyn henkilön asiakastiedot ohjelmaan kirjatuista tiedoista? Onko käyttäjä laittanut rastin tiettyyn ruutuun? Valitsiko pelaaja mustat vai valkoiset nappulat? Oliko Shift-näppäin pohjassa, kun hiirellä klikattiin? Onko ötökkä törmännyt esteeseen?

On siis tarve totuusarvoille, tarkemmin sanoen Boolen logiikalle (Boolean logic). Boolen logiikassa käytetään tasan kahta totuusarvoa, tosi ja epätosi.

Boolean-tyypistä

"Totta" ja "tarua" vastaavat Scalan literaalimerkinnät true ja false (vrt. luku- ja merkkijonoliteraalit). Nämä Boolean-tyyppiset literaalit ovat Scalan varattuja sanoja, eli niitä ei voi käyttää esimerkiksi muuttujien niminä.

Scalassa totuusarvoja kuvaa tietotyyppi Boolean, joka on määritelty pakkauksessa scala ja on siis aina käytettävissä Scala-ohjelmissa Int- ja String-tyyppien tapaan.

val paaviOnKatolilainen = truepaaviOnKatolilainen: Boolean = true
val maapalloOnLittea = falsemaapalloOnLittea: Boolean = false

Mitään muita Boolean-arvoja truen ja falsen lisäksi ei ole olemassa. (Vertaa: erilaisia merkkijonoja ja lukuja on vaikka kuinka paljon.)

Pelkkä yksittäinen totuusarvoliteraalikin on lauseke, jonka arvo on kyseinen totuusarvo itse:

falseres3: Boolean = false

Tarvitaanko erillinen Boolean?

Voisiko isBetterThan-metodi palauttaa merkkijonon "yes" tai "no" Boolean-arvon sijaan? Tai jonkin luvun: sovitaan vaikkapa, että nolla tarkoittaa epätotta ja kaikki muut luvut totta?

Periaatteessa kyllä, ja käytännössäkin jälkimmäistä ehdotusta sovelletaan joissakin ohjelmointikielissä. Kuitenkin Scalassa ja monessa muussa ohjelmointikielessä on erillinen tietotyyppi totuusarvojen kuvaamiseen. Erillisen tietotyypin käyttäminen usein selkeyttää ohjelmakoodia ja mahdollistaa myös paremmat automaattiset virhetarkastukset ja -ilmoitukset. Näin voidaan esimerkiksi varmistaa, että totuusarvomuuttujaan ei vahingossakaan sijoiteta muuta kuin juuri totuusarvo.

Totuusarvojen käyttöä

Voit käyttää totuusarvoja tuttuun tapaan esimerkiksi muuttujiin sijoituksissa, parametrilausekkeissa ja metodien palautusarvoina:

println("Totuus on " + paaviOnKatolilainen)Totuus on true
val oliParempi = wine2.isBetterThan(wine1)oliParempi: Boolean = false
val viiniOnParempiKuinSeItse = wine2.isBetterThan(wine2)viiniOnParempiKuinSeItse: Boolean = false

Lukuihin ja merkkijonoihin liittyy operaattoreita kuten +. Niin totuusarvoihinkin. Yksi totuusarvo-operaattoreista on !. Tämä huutomerkkioperaattori luetaan "ei" tai englantilaisittain "not". Se "kääntää" totuusarvon, joka sen perään kirjoitetaan, eli falsesta tulee true ja toisin päin. Esimerkiksi:

!oliParempires4: Boolean = true

Tässä siis lausekkeen !oliParempi arvo on true. Muuttujan oliParempi arvoon tämän lausekkeen evaluoiminen ei vaikuta yhtään mitenkään, vaan muuttujassa on edelleen false.

Sen lisäksi, että voidaan käyttää literaaleja, totuusarvoja syntyy myös arvoja vertailemalla:

Vertailuoperaattorit

Scalan vertailuoperaattoreilla voi muodostaa lausekkeita, joissa vertaillaan osalausekkeiden arvoja.

Operaattori Merkitys
> suurempi kuin
< pienempi kuin
>= suurempi tai yhtä suuri kuin
<= pienempi tai yhtä suuri kuin
== yhtä suuri kuin
!= erisuuri kuin

Huomaa, että vertailuoperaattorit kirjoitetaan <= ja >= eikä =< tai => (joista jälkimmäisellä on Scalassa ihan muu merkitys; siitä lisää myöhemmin). Muistisääntö: kirjoita samassa järjestyksessä kuin luetkin: pienempi (<) tai yhtä suuri (=) kuin.

Lukujen vertailua

Vertaileminen tuottaa Boolean-arvoja:

10 <= 10res5: Boolean = true
20 < (10 + 10)res6: Boolean = false
val ikavuodet = 20ikavuodet: Int = 20
val onAikuinen = ikavuodet >= 18onAikuinen: Boolean = true
ikavuodet == 30res7: Boolean = false
20 != ikavuodetres8: Boolean = false
Vertailtaviksi voi kirjoittaa mitä vain tietotyypiltään sopivia lausekkeita. Ne evaluoidaan ja niiden arvoja verrataan toisiinsa.
Huomaa, että yhtäsuuruutta vertaillessa on aina käytettävä kahta yhtäsuuruusmerkkiä. Tämä unohtuu aluksi helposti. Yksi yhtäsuuruusmerkkihän on käytössä ihan muissa yhteyksissä, erityisesti muuttujaan sijoittamisessa ja metodin määrittelyn alussa.

Alla on totuusarvoja sisältävä animaatio. Osaatko jo animaatiota katsomatta päätellä pelkästä koodista, mitä se tulostaa?

Erilaisia vertailuja

Kokeile tässä välissä REPLissä totuusarvoja ja vertailuoperaattoreita.

Kokeile operaattoreita myös muilla arvoilla kuin luvuilla. Merkkijonoja voi vertailla samaan tapaan kuin lukuja, ja Boolean-arvoja voi myös vertailla keskenään.

Jatka eteenpäin seuraaviin harjoituksiin, kun olet kokeillut vertailuoperaattoreiden käyttöä REPLissä.

Vertailuharjoituksia

Totuusarvoja ja vertailuoperaattoreita tarvitaan jatkossa jatkuvasti. Olisi hyvä, jos ne tulisivat mahdollisimman pian sujuvasti selkärangasta, jotta et joudu niitä liikaa miettimään monimutkaisempaa kokonaisuutta laatiessa tai lukiessa. Niinpä alla on koko joukko pieniä totuusarvoharjoitteita. Kokeile/päättele ja kirjoita vastaukset. Älä tässäkään tyydy vain arvaamaan tai kopioimaan REPListä, vaan mieti myös miksi ja koettele päätelmiäsi REPLissä.

Oletetaan annetuiksi nämä muuttujien alustukset:

val iso = 10000
val pieni = 10

Valitse kussakin seuraavista kohdista mainitun lausekkeen arvo.

iso > pieni
pieni < iso
!(iso > pieni)
"P" == "NP"
"kissa" + "kala" != "kissakala"
"mun isä" > "sun isä"
"aaaaaaaaaa" < "bb"
false == true
true == true
false == false
(10 < 20) != (20 > 10)
"laama" < 100
"100" < 100
"100" == 100

Oletetaan annetuiksi nämä käskyt:

var luku = 19
println(luku / 20)
val onNolla = luku == 0

Mikä on nyt muuttujan onNolla arvo?

Annetaan äskeisten lisäksi nämä käskyt:

luku = 0
println(onNolla)

Mitä tulostuu?

Annetaan vielä lisäksi nämä käskyt:

luku = 20
println(luku + luku * 10 < (luku + luku) * 5)

Mitä tulostuu?

Annetaan sitten tämä käsky:

println((19 >= luku) == (0 >= luku))

Mitkä seuraavista pitävät paikkansa?

Ja vielä lopuksi tämäkin:

println(0 >= luku != onNolla)

Mitä tämä käsky tulostaa?

Olkoon määriteltyinä kaksi kokonaislukumuuttujaa luku1 ja luku2 sekä kaksi kokemusolioon viittaavaa muuttujaa exp1 ja exp2. Näiden muuttujien täsmällisillä arvoilla ei ole tehtävän kannalta merkitystä. Mitkä kaikki seuraavista pitävät joka tapauksessa paikkansa?

Minitehtävä: pystykuva

Kuvia jaotellaan joskus pysty- ja vaakakuviin (portrait vs. landscape). Pystykuvan korkeus on suurempi kuin sen leveys ja vaakakuvalla vastaavasti toisin päin.

Nouda projekti Miscellaneous. Älä välitä nyt sen muusta sisällöstä; paikanna vain tiedosto misc.scala. Kirjoita tuohon tiedostoon vaikutukseton funktio isPortrait, joka:

  • ottaa yhden Pic-tyyppisen parametrin, ja
  • palauttaa true, jos annetun kuvan korkeus on leveyttä suurempi ja false muutoin (eli jos kuva on neliön muotoinen tai vaakakuva).

REPLissä kokeillessasi anna aluksi käsky import o1.misc._.

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

Olioiden yhtäsuuruudesta

Mitä tahansa olioita voi vertailla toisiinsa operaattoreilla == ja !=. Mutta mitä yhtäsuuruus tarkoittaa vaikkapa kokemusolioiden tapauksessa? Tutki asiaa itse REPLissä vastatessasi seuraavaan tehtävään.

Oletetaan annetuiksi nämä käskyt:

val wine1 = new Experience("Il Barco 2001", "ookoo", 6.69, 5)
val wine2 = new Experience("Tollo Rosso", "turhahko", 6.19, 3)
val wine3 = wine1
val wine4 = new Experience("Il Barco 2001", "ookoo", 6.69, 5)

Mitkä seuraavista lausekkeista ovat nyt arvoltaan true?

Huomaat: pelkkä kokemusolioiden ominaisuuksien keskinäinen samankaltaisuus ei riittänyt tekemään niistä "yhtä suuria".

Esimerkit ==-operaattorista yllä vertailivat pelkästään muuttujien sisältöä eli niitä viittauksia, jotka muuttujiin on tallennettu. Ne eivät verranneet varsinaisia olioita lainkaan. Esimerkiksi wine1 == wine4 on false, koska kyseessä ei ole kaksi viittausta samaan olioon vaan kaksi viittausta kahteen samanlaiseen mutta kuitenkin erilliseen olioon. wine1 == wine3 taas on true, koska molempien muuttujien arvona on viittaus täsmälleen samaan olioon; viittaukset vievät samaan paikkaan.

Yleisesti ottaen se, miten yhtäsuuruusvertailu olioille toimii, riippuu olioiden tyypistä. Itse määritetyille tietotyypeille se on oletusarvoisesti ns. identiteettivertailu eli toimii kuin kokemusolioille yllä. Toisaalta monilla Scalan valmiilla tietotyypeillä on tietotyyppikohtaiset määritelmät yhtäsuuruudelle. Hyvä esimerkki tästä ovat puskurit: on määritelty, että kaksi kokonaan erillistäkin puskuria ovat yhtäsuuret, jos niillä on sama sisältö. Tämä käy ilmi seuraavasta REPL-esimerkistä:

import scala.collection.mutable.Bufferimport scala.collection.mutable.Buffer
val erasPuskuri = Buffer(2, 10, 5, 4)erasPuskuri: Buffer[Int] = ArrayBuffer(2, 10, 5, 4)
val toinenPuskuri = Buffer(2, 10, 5)toinenPuskuri: Buffer[Int] = ArrayBuffer(2, 10, 5)
erasPuskuri == toinenPuskurires9: Boolean = false
toinenPuskuri += 4res10: Buffer[Int] = ArrayBuffer(2, 10, 5, 4)
erasPuskuri == toinenPuskurires11: Boolean = true

Experience-luokan toteutus

Vertailuoperaattorein varustettuina voimme nyt laatia Experience-luokalle ohjelmakoodin. Aloitetaan hahmottelemalla toteutus pseudokoodina:

class Experience(vaadi konstruktoriparametreiksi nimi, kuvaus, hinta ja arvosana, jotka
                 kaikki tallennetaan sellaisenaan kiintoarvoisiin ilmentymämuuttujiin) {

  def valueForMoney = palauta arvosanasi ja hintasi osamäärä

  def isBetterThan(another: Experience) = palauta totuusarvo, joka kertoo,
                                          onko oma arvosanasi korkeampi kuin
                                          parametriksi annetun kokemusolion arvosana

}
Vertailumetodimme saa parametriksi viittauksen vertailukohtana olevaan Experience-olioon. Parametrimuuttujan nimi voi olla esimerkiksi another. Ajatus on tältä osin samankaltainen kuin Pos-luokan xDiff- ja yDiff-metodeissa (luku 2.5), joissa myös käsiteltiin this-oliota ja parametrina osoittamaa toista saman luokan ilmentymää.

Tässä Scala-toteutus:

class Experience(val name: String, val description: String, val price: Double, val rating: Int) {

  def valueForMoney = this.rating / this.price

  def isBetterThan(another: Experience) = this.rating > another.rating

}
Mitään muuta uutta tässä esimerkissä ei ole, kuin että metodin palautusarvo tuotetaan vertailuoperaattorilla ja on siis Boolean-tyyppinen.

Pikkutehtävä: totuusarvoinen ilmentymämuuttuja

Valmisteleva kertaus

Palautetaan mieleen Asiakas- ja Tilaus-luokat:

val testihenkilo = new Asiakas("T. Testaaja", 12345, "test@test.fi", "Testitie 1, 00100 Testaamo")testihenkilo: o1.Asiakas = o1.Asiakas@a7de1d
val testitilaus = new Tilaus(10001, testihenkilo)testitilaus: o1.Tilaus = o1.Tilaus@18c6974

Tehtävänanto

Boolean-arvot sopivat myös olion ominaisuuksien kuvaamiseen. Esimerkiksi kustakin tilauksesta voitaisiin kirjata, onko se kallis mutta nopea pikatilaus vai ei. Tilauksilla voisi tällöin olla onPika-niminen ilmentymämuuttuja:

testitilaus.onPikares12: Boolean = false
testitilaus.onPika = true

Lisää Oliointro-projektin Tilaus-luokkaan tällainen ilmentymämuuttuja. Sen arvon tulee siis olla aluksi false mutta arvoa voi muuttaa sijoituskäskyllä kuten yllä.

Palauttaminen

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

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

Hyödynnetään Boolean-tietotyyppiä kehittäessämme viimeksi luvussa 2.7 käsiteltyä Odds-projektia taas vähän eteenpäin.

(Jos et tehnyt projektiin liittyviä tehtäviä viime kierroksella, käy aiemmat vaiheet nyt läpi; voit käyttää tälle tehtävälle pohjana niiden esimerkkiratkaisuja, jotka löytyvät linkeistä tehtävien kohdalta määräajan jälkeen.)

Tehtävänanto

Laadi metodi isLikely, jolla voi selvittää, onko Odds-olion kuvaama tapahtuma todennäköinen vai ei. Tapahtuman katsotaan tässä olevan todennäköinen, jos Odds-olio kuvaa sen toteutumisen olevan todennäköisempää kuin sen toteutumatta jäämisen. Esimerkiksi kuutosen heittäminen nopalla ei ole todennäköistä, mutta "minkä vaan muun kuin kuutosen" heittäminen on:

val rollingSix = new Odds(5, 1)rollingSix: Odds = o1.Odds@d4c0c4
val notRollingSix = new Odds(1, 5)notRollingSix: Odds = o1.Odds@a5e42e
rollingSix.isLikelyres13: Boolean = false
notRollingSix.isLikelyres14: Boolean = true

Laadi myös metodi isLikelierThan, jolla voi selvittää kahdesta tapahtumasta todennäköisemmän:

rollingSix.isLikelierThan(notRollingSix)res15: Boolean = false
notRollingSix.isLikelierThan(rollingSix)res16: Boolean = true
rollingSix.isLikelierThan(rollingSix)res17: Boolean = false

Ohjeita ja vinkkejä

  • Lisää metodit tiedostoon Odds.scala.
  • Voit käyttää käynnistysoliota OddsTest2 metodiesi testaamiseen. Tuo pikkuohjelma on annettu valmiina, joskin sen sisältö on "kommentoitu ulos", jotta koodi ei tuottaisi virheilmoituksia isLikely- ja isLikelierThan-metodien puuttumisesta ennen kuin olet ne toteuttanut. Poista kommenttimerkit testiohjelmasta, kun olet ensin kirjoittanut pyydetyt metodit Odds-luokkaan, ja aja ohjelma.
  • Kuten luvun 2.7 edellisessä Odds-tehtävässä, myös nyt on tarkoitus, että testiohjelma OddsTest2 kutsuu Odds-luokkaan kirjattuja metodeita. Älä nytkään kopioi Odds-luokan määrittelyä tai sen osia testiohjelmaan.

Palauttaminen

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

FlappyBug-tehtävä (osa 11/17: Game Over)

Olet varmasti jo huomannut, ettei ötökkäpelimme este estä mitään. Laitetaan peli pysähtymään esteen koskettaessa ötökkää.

Pohjustus: näkymien isDone-metodi

Luvussa 3.1 tutkimme esimerkkiohjelmaa, joka kasvatti klikatessa ruudulla näkyvää ympyrää:

object Klikkausohjelma extends App {
  val klikkauslaskuri = new Laskuri(5)
  val tausta = rectangle(500, 500, Black)

  val nakyma = new View(klikkauslaskuri) {
    def makePic = tausta.place(circle(klikkauslaskuri.arvo, White), new Pos(100, 100))

    override def onClick(klikkauskohta: Pos) = {
      klikkauslaskuri.etene()
      println("Klikkaus koordinaateissa " + klikkauskohta + "; " + klikkauslaskuri)
    }
  }

  nakyma.start()
}

View-oliolle voi lisätä myös isDone-metodin, joka säätelee sitä, milloin käyttöliittymä lakkaa käsittelemästä klikkauksia, tikityksiä ja muita käyttöliittymätapahtumia:

object PysahtyvaKlikkausohjelma extends App {
  val klikkauslaskuri = new Laskuri(5)
  val tausta = rectangle(500, 500, Black)

  val nakyma = new View(klikkauslaskuri) {
    def makePic = tausta.place(circle(klikkauslaskuri.arvo, White), new Pos(100, 100))

    override def onClick(klikkauskohta: Pos) = {
      klikkauslaskuri.etene()
      println("Klikkaus koordinaateissa " + klikkauskohta + "; " + klikkauslaskuri)
    }

    override def isDone = klikkauslaskuri.arvo > 10

  }

  nakyma.start()
}
isDone palauttaa Boolean-arvon, joka määrittää, onko käyttöliittymä jo "valmis" eli voidaanko tapahtumankäsittely jättää sikseen. Tässä esimerkissä klikkausten käsittely lopetetaan, kun laskurin arvo on yli 10.
Toteutuksemme korvaa oletustoteutuksen, joka palauttaa aina false eikä siis pysäytä käyttöliittymää lainkaan. Siksi tässäkin override (luku 3.1).

Tehtävänanto

Tee kolme asiaa:

  1. Määrittele Obstacle-luokkaan metodi, jolla selvitetään, koskettaako este ötökkää.
  2. Määrittele Game-luokkaan äskeistä metodia käyttävä metodi, joka kertoo, onko peli päättynyt pelaajan tappioon esteeseen osumisen vuoksi.
  3. Määrittele FlappyBugApp-käyttöliittymään isDone-metodi, joka huolehtii siitä, että käyttöliittymä pysähtyy pelin päättyessä.

Tarkemmin sanoen:

  1. Lisää Obstacle-luokkaan vaikutukseton metodi touches, joka selvittää onko este parhaillaan ötökän kohdalla vai ei.

    • Se ottaa ainoaksi parametrikseen viittauksen Bug-olioon.
    • Se palauttaa Boolean-arvon.
    • Se selvittää etäisyyden kyseisen esteen (this) ja parametrin osoittaman ötökän välillä ja muodostaa palautusarvonsa tämän etäisyyden perusteella. Palautusarvo on true jos ja vain jos etäisyys on pienempi kuin ötökän ja esteen säteet (radius) yhteensä; muuten se on false.
    • Etäisyys lasketaan suoraa viivaa pitkin ötökän ja esteen keskipisteiden välillä. Apuna voit käyttää Pos-luokan distance-metodia (luku 2.5).
  2. Lisää Game-luokkaan alla oleva metodi isLost, joka määrittää, onko pelaaja hävinnyt pelin. Tämä metodi käyttää ensin laatimaasi touches-metodia: peli on hävitty nimenomaan silloin, jos pelin (toistaiseksi ainoa) este koskettaa ötökkää.

    def isLost = this.obstacle.touches(this.bug)
    
  3. Lisää FlappyBugApp-ohjelman View-oliolle isDone-metodi, joka palauttaa true pelaajan hävittyä pelin ja false muuten. Käytännössä siis peli pysähtyy ötökän osuessa esteeseen.

    • Ota isDone-metodissa mallia yllä olevasta klikkausohjelmasta. Rungoksi riittää yksinkertaisesti yksi isLost-metodikutsu.

Palauttaminen

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

Yhteenvetoa

  • "Kyllä vai ei" -ilmiöitä kuvataan tietokoneohjelmissa usein Boolen logiikan arvoina "tosi" ja "epätosi", joille on monissa kielissä määritelty oma tietotyyppi.
  • Scalassa Boolen logiikan arvoja edustaa tietotyyppi Boolean. Tämäntyyppisiä arvoja on tasan kaksi: true ja false. Niitä voi käyttää literaaleina Scala-ohjelmakoodissa.
  • Totuusarvoja saadaan myös käyttämällä vertailuoperaattoreita, esimerkiksi vertailemalla, onko tietty lukuarvo pienempi kuin toinen vai ei.
  • Tapa, jolla arvojen yhtäsuuruus määritellään riippuu tietotyypistä. Kyseessä voi olla identiteettivertailu tai samanlaisuusvertailu jonkin ominaisuuden tai ominaisuuksien mukaan?
  • Lukuun liittyviä termejä sanastosivulla: totuusarvo; vertailuoperaattori.

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: (aakkosjärjestyksessä) Riku Autio, Nikolas Drosdek, Joonatan Honkamaa, Jaakko Kantojärvi, Niklas Kröger, Teemu Lehtinen, Strasdosky Otewa, 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.

a drop of ink
Palautusta lähetetään...