Luku 5.1: Logiikkaa, verta ja ostoksia
Johdanto: vaikeutus FlappyBugiin
Palataan FlappyBug-peliin. Luvussa 3.3 lisäsit Game
-pelioliolle isLost
-metodin, joka
määrää pelin poikki, jos este koskee ötökkää:
def isLost = this.obstacle.touches(this.bug)
Nykyisessä pelissä on turhan helppo edetä lymyämällä ylä- tai alareunassa. Jospa muokkaamme tuota ehtoa niin, että peli loppuu, jos törmää esteeseen tai ylä- tai alareunaan.
Jotenkin näin se voisi mennä:
def isLost =
if this.obstacle.touches(this.bug) then
true
else if this.bug.pos.y <= 0 then
true
else
this.bug.pos.y >= GroundY
Tappio tulee, jos on osuttu esteeseen.
Tai jos ei ole osuttu mutta jos ollaan liian korkealla.
Tai jos ei olla liian korkeallakaan mutta ollaan liian matalalla.
Toimii se noinkin, mutta tuo on aika vaivalloinen tapa sanoa yksinkertainen asia. Mieluummin kirjoittaisimme: "Jos tuo tai tuo ehto on tosi." Ehkä olet ehtinyt kaipailla tällaista mahdollisuutta jo aiempien lukujen aikana.
Tässä luvussa opit käyttämään logiikkaoperaattoreita kuten "ja" ja "tai", joilla
Boolean
-arvoja voi yhdistellä. Niiden yleisesittelyn jälkeen palaamme mm. FlappyBugiin.
Logiikkaoperaattorit
Scala-kielen tarjoamia logiikkaoperaattoreita (logical operators) on taulukoitu alla:
Operaattori |
Nimi |
Esimerkki |
Vastaa tarpeeseen |
---|---|---|---|
|
ja (and) |
|
"Ovatko molemmat totuusarvot |
|
tai (or) |
|
"Onko ainakin toinen totuusarvoista |
|
joko–tai eli poissulkeva tai
(exclusive or eli xor)
|
|
"Onko tasan yksi totuusarvoista |
|
ei tai negaatio
(not tai negation)
|
|
"Onko totuusarvo |
Tämän kurssin kannalta hyödyllisimpiä ovat &&
, ||
ja !
, joista viimeinen onkin jo
aiemmista luvuista tuttu.
Logiikkaoperaattoreilla rakennetaan Boolean
-tyyppisistä lausekkeista monimutkaisempia
lausekkeita, joilla on niilläkin Boolean
-tyyppinen arvo.
val luku = 50luku >= 0 && luku <= 5res0: Boolean = false if luku >= 0 && luku <= 5 then "on kelvollinen arvosana" else "ei ole kelvollinen arvosana"res1: String = "ei ole kelvollinen arvosana" luku == 100 || luku == 50res2: Boolean = true !(luku >= 0)res3: Boolean = false
&&
- eli ja-operaattori tuottaa true
n vain, jos molemmat
osalausekkeista ovat true
. Tässä ensimmäinen on mutta toinen
ei, joten koko lausekkeen arvo on false
.
||
- eli tai-operaattori tuottaa true
n, jos kumpi tahansa
osalausekkeista on true
(tai molemmat ovat). Tässä ensimmäinen
ei ole, mutta toinen on, joten koko lausekkeen arvo on true
.
Termi: osalausekkeita, joita jokin operaattori käsittelee,
sanotaan usein operandeiksi (operand). Tässä esitellyistä
operaattoreista negaatio-operaattorille !
riittää yksi
operandi, kun taas muut logiikkaoperaattorit vaativat kaksi.
Logiikkaoperaattorien väljä evaluointi
&&
- ja ||
-operaattorien evaluointi on väljää (non-strict). Tässä väljyys
tarkoittaa käytännössä sitä, että vasemmanpuoleinen operandi evaluoidaan ensin, ja jos
se riittää määräämään koko lausekkeen totuusarvon, niin oikeanpuoleista operandia ei
evaluoida lainkaan. (Väljää evaluointia käsitellään laajemmin luvussa 7.2.)
Asialla on käytännön merkitystä, kuten seuraavasta esimerkistä selviää.
Määritellään aluksi pari muuttujaa, joilla on jotkin lukuarvot. Tässä ne ovat eräät literaalit, mutta luvut voitaisiin myös vaikkapa kysyä ohjelman käyttäjältä.
val jaettava = 50000jaettava: Int = 50000 var jakaja = 100jakaja: Int = 100
Tutkitaan jakolaskun lopputuloksen suuruutta, kunhan ensin varmistetaan, että jakaja ei
ole nolla. Tarkastus onnistuu joko &&
- tai ||
-operaattorilla:
jakaja != 0 && jaettava / jakaja < 10res4: Boolean = false jakaja == 0 || jaettava / jakaja >= 10res5: Boolean = true
Silloin, kun jakajana ei ole nolla, voi operandien järjestyksen vaihtaa ja lopputulos pysyy samana:
jaettava / jakaja >= 10 || jakaja == 0res6: Boolean = true
Vaan entä jos jakaja onkin nolla?
jakaja = 0jakaja: Int = 0 jaettava / jakaja >= 10 || jakaja == 0java.lang.ArithmeticException: / by zero ...
Nyt jakolasku suoritetaan ensimmäistä operandia evaluoitaessa. Syntyy ajonaikainen
virhe: nollalla ei voi jakaa. Lauseketta jakaja == 0
ei koskaan edes ehditty aloittaa
evaluoimaan.
Jos taas tarkastus on ensimmäisessä operandissa, homma toimii:
jakaja == 0 || jaettava / jakaja >= 10res7: Boolean = true
Koska jakaja oli nolla, niin lausekkeen jakaja == 0
arvoksi saatiin true
. Näin ollen
loppuosaa lausekkeesta ei edes evaluoitu sillä perusteella, että true || mitaTahansa
on aina true
. Näin myös vältettiin virhe. Järjestyksellä on väliä!
Operaattorien yhdistelemisestä
Kuten aritmeettisia lausekkeitakin, myös logiikka- ja vertailuoperaattoreita yhdistelemällä muodostettuja lausekkeita voi ryhmitellä kaarisulkeilla.
if (luku > 0 && luku % 2 == 0) || luku < 20 then
println("Joko sekä positiivinen että parillinen tai 20:ä pienempi.")
if luku > 0 && (luku % 2 == 0 || luku < 20) then
println("Positiivinen; lisäksi joko parillinen tai 20:ä pienempi.")
Logiikkaoperaattoriharjoittelua
Tarkastele seuraavaa koodinpätkää ja mieti huolellisesti, mitä tapahtuu, kun se suoritetaan. Muistiinpanolappusen käyttäminen ei ole huono idea.
val first = 20
val second = 10
var third = 50
if first > second && first + second < third then
third = 30
println("One")
val result = first > second && first + second < third
if first < second || result then
println("Two")
if first > second || second == third then
println("Three")
third = 10
if !(result && third >= 50) then
println("Four")
else
println("Five")
Parempi pullokone
Logiikkaoperaattorit ovat monessa tilanteessa kätevämpi vaihtoehto kuin if
-käskyjen
yhdistelmä.
Palautetaan mieleen luvun 3.5 sellBottle
-metodi, josta on tässä alkuperäinen Int
-paluuarvoinen versio.
def sellBottle() =
if this.isSoldOut then
-1
else if !this.enoughMoneyInserted then
-1
else
this.earnedCash = this.earnedCash + this.bottlePrice
this.bottleCount = this.bottleCount - 1
val changeGiven = this.insertedCash - this.bottlePrice
this.insertedCash = 0
changeGiven
Tutki seuraavia kahta yritystä kirjoittaa tämä metodi logiikkaoperaattoria käyttäen:
def sellBottle() =
if this.isSoldOut || !this.enoughMoneyInserted then
-1
else
this.earnedCash = this.earnedCash + this.bottlePrice
// jne. kuten edellä
def sellBottle() =
if this.enoughMoneyInserted && !this.isSoldOut then
this.earnedCash = this.earnedCash + this.bottlePrice
// jne. kuten edellä
else
-1
FlappyBug-tehtävä (osa 15/17: tappavat reunat)
Vaikeuta FlappyBug-peliä johdannossa suunnitellulla tavalla. Tee se näin:
Lisää
Bug
-luokkaan parametriton, vaikutukseton metodiisInBounds
, jonka palauttamaBoolean
-arvo kertoo, onko ötökkä sallitulla pelialueella eli nollakoordinaatin ja maanpinnan välissä (rajat poislukien). Käytä sopivaa logiikkaoperattoria.Muokkaa
Game
-luokanisLost
-metodia niin, että se ilmoittaa pelin päättyneeksi myös silloin, jos ötökkä on sallitun pelialueen ulkopuolella. Käytä logiikkaoperaattoreita jaisInBounds
-metodia.
A+ esittää tässä kohdassa tehtävän palautuslomakkeen.
Verityyppitehtävä
Tehtävänanto
Blood-moduulissa on useita numeroituja pakkauksia. Ota nyt esiin o1.blood1
ja sieltä
luokka BloodType
. Toteuta se moduulin Scaladoc-dokumentaation mukaiseksi.
Ohjeita ja vinkkejä
Tässä yksi esimerkki siitä, miten luokan pitäisi toimia:
import o1.blood1.*val myBlood = BloodType("AB", true)myBlood: o1.blood.BloodType = AB+ val yourBlood = BloodType("A", true)yourBlood: o1.blood.BloodType = A+ val theirBlood = BloodType("O", false)theirBlood: o1.blood.BloodType = O- myBlood.canDonateTo(yourBlood)res8: Boolean = false yourBlood.canDonateTo(myBlood)res9: Boolean = true theirBlood.canDonateTo(yourBlood)res10: Boolean = true
Voit myös ajaa annetun
test
-ohjelman kokeillaksesi kaikkia eri yhdistelmiä.Tässäkään tehtävässä ei tarvitse välittää sellaisista erikoistapauksista ja virhekäyttötilanteista, joita ei ole erikseen mainittu. Saat luottaa siihen, että
BloodType
lle annetaan vain mielekkäitä merkkijonoja luontiparametriksi.Pyri toteuttamaan pyydetyt metodit mahdollisimman yksinkertaisesti ja toistamatta samaa koodinpätkää eri paikoissa.
Käytä logiikkaoperaattoreita. Pärjäätkö kokonaan ilman
if
- jamatch
-valintakäskyjä (muissa metodeissa kuintoString
issä)?Kutsu muita saman luokan metodeita. Lisävinkki: myös viittauksen
this
-olioon voi antaa parametriksi metodille.
Palauttaminen
A+ esittää tässä kohdassa tehtävän palautuslomakkeen.
Tehtävä: FixedPriceSale
Moduulin AuctionHouse1 Scaladoc-dokumentit kuvailevat useita luokkia, jotka mallintavat kuvitteellisella verkkohuutokauppasivustolla myytäviä esineitä. Tässä tehtävässä keskitymme yhteen myyntitapaan, jossa esineillä on tietty vakiomyyntihinta. Alempana olevissa valinnaisissa tehtävissä toteutetaan huutokauppoja, joissa hinta muuttuu.
Tehtävänanto
Nouda moduuli AuctionHouse1 ja avaa sen Scaladoc-dokumentaatio. Toteuta pakkauksen
o1.auctionhouse
luokka FixedPriceSale
dokumentaation mukaiseksi. Kirjoita ratkaisusi
tiedostoon FixedPriceSale.scala
.
Ohjeita ja vinkkejä
On hyvä ajatus käyttää
Option
-tyyppistä ilmentymämuuttujaa, jonka alkuarvo onNone
. Jos teet niin, muista että sinun täytyy merkitä sille tietotyyppi (kuten luvussa 4.3). Siis:muuttujanNimi: Option[Tyyppi]
.Lisävinkkejä ilmentymämuuttujista
Pari kolmesta luontiparametrista on syytä määritellä ilmentymämuuttujiksi. Näet nuo julkiset ilmentymämuuttujat dokumentaatiosta.
Lisäksi tarvitset pari ilmentymämuuttujaa: yhden, jossa pidät kirjaa esineen vähenevästä aukioloajasta, ja toisen, jossa pidät kirjaa ostajan nimestä.
Koska ostajaa ei välttämättä ole, sopii jälkimmäisen tyypiksi
Option[String]
.Viimeksi mainittuja ilmentymämuuttujia ei ole mainittu dokumentaatiossa, vaan ne ovat osa sisäistä toteutusta. Tee niistä yksityisiä ja nimeä ne haluamallasi tavalla.
Luokan osat on kuvattu Scaladocissa aakkosjärjestyksessä, mutta se ei liene kätevin toteuttamisjärjestys (eikä metodeita myöskään ole koodiin pakko kirjoittaa tähän järjestykseen). Voit valita järjestyksen itse; tässä on yksi ehdotus, joka edennee suunnilleen helpoimmasta vaikeimpaan:
toString
,daysLeft
,buyer
,isExpired
,isOpen
,advanceOneDay
,buy
.Vinkkejä metodien toteutuksesta
Lue Scaladoc tarkasti. Huomaa esimerkiksi, että open ja expired eivät ole toistensa suoria vastakohtia, vaikka esine ei voikaan olla molempia yhtäaikaisesti.
Suurin osa metodeista on vaikutuksettomia. Niiden tulee vain palauttaa ilmentymämuuttujien arvoja tai selvittää jokin ilmentymämuuttujiin liittyvä tieto. Nämä metodit voi toteuttaa yksinkertaisilla yhden rivin lausekkeilla.
Esineillä on kaksi vaikutuksellista metodia:
advanceOneDay
muuttaa jäljellä olevien päivien lukumäärää jabuy
ostajaa. Nuo tiedot ovat tallessa ilmentymämuuttujissa. Muista kummassakin metodissa tarkistaa, onko esine auki; voit käyttääisOpen
-metodia.Sinulle on annettu valmis testiohjelma
testFixedPrice
. Käytä sitä!Tämän testiohjelman määrittely aiheuttaa aluksi virheilmoituksia, jotka johtuvat vain siitä, ettet ole vielä toteuttanut niitä metodeita, joita ohjelma kutsuu. Ilmoitukset häviävät kyllä, kun teet tehtävän. (Muista: virheilmoituksen syy ei aina ole siellä, mihin virheilmoitus osoittaa.)
Voit aluksi "kommentoida ulos" osan testiohjelman koodista, niin pystyt testaamaan osittaista toteutusta luokastasi.
Voit lisäksi ajaa pakkauksesta
o1.auctionhouse.gui
löytyvän toisen testisovelluksenTestApp
, jonka avulla voit luoda ja koekäyttääFixedPriceSale
-olioita vuorovaikutteisesti tällaisessa ikkunassa:
A+ esittää tässä kohdassa tehtävän palautuslomakkeen.
Lisätehtävä: Moment
ja Interval
Loput luvusta koostuu vapaaehtoisista mutta suositeltavista lisätehtävistä, joilla voit kehittää ohjelmointirutiiniasi. Suosittelemme näitäkin tehtäviä, vaikka sitten niin, että teet ensin kierroksen pisteytetyt tehtävät ja palaat sen jälkeen tänne. Alla oleviin tehtäviin menee helposti useita tunteja.
Pakkauksen o1.time
esittely
Tässä tehtävässä pääset soveltamaan logiikkaoperaattoreita hieman aiempia mutkikkaammin ja muutenkin treenaamaan opittuja työkaluja.
Ajanhetkiä ja aikavälejä
Oletetaan, että on ohjelma (tai ohjelmia), joiden on tarpeellista käsitellä
aikavälejä, jotka alkavat tietystä ajanhetkestä ja jatkuvat toiseen hetkeen
saakka. Tätä varten halutaan laatia luokat Moment
kuvaamaan yksittäistä
ajanhetkeä ja Interval
kuvaamaan aikaväliä. Kuhunkin Interval
-olioon
liittyy kaksi Moment
-oliota, jotka kuvaavat aikavälin alku- ja loppuhetkeä.
Moduulissa Miscellaneous on pakkaus o1.time
, josta löytyy jo alku
Moment
-luokan toteutukselle. Interval
-luokka puuttuu vielä kokonaan.
Aloitetaan luokasta Moment
, jonka pohjakoodista on selitys alla.
import scala.math.abs
class Moment(private val time: Int):
override def toString = this.time.toString
def distance(another: Moment) = abs(another.time - this.time)
def isLaterThan(another: Moment) = this.time > another.time
def later(another: Moment) = if this.isLaterThan(another) then this else another
def earlier(another: Moment) = if this.isLaterThan(another) then another else this
end Moment
Moment
-oliota luotaessa ilmoitetaan mistä ajanhetkestä on
kyse. Tässä toteutuksessa ei oteta lainkaan kantaa siihen,
mitä yksikköä ajan mittaamiseen käytetään, vaan mitä tahansa
kokonaislukumuotoista voi käyttää (nanosekunteja, päiviä,
vuosilukuja jne.).
Moment
-olio delegoi toString
-toteutuksen kokonaisuudessaan
kokonaisluvun huoleksi. Huomaa: Int
-arvollekin voi kutsua
metodia! Kokonaisluvun toString
-metodi palauttaa lukua
kuvaavat merkit, esimerkiksi luvulle 123 kutsuttuna merkkijonon
"123"
. (Int
-arvojen metodeista lisää seuraavassa
luvussa 5.2.)
distance
-metodi määrittää kahden hetken etäisyyden.
isLaterThan
-, later
- ja earlier
-metodeilla voi vertailla
ajanhetkiä toisiinsa.
Yleinen vinkki: hyödynnä abstraktioita
Yksi tämän harjoituksen teemoista on itse laatimiesi metodien käyttö kirjoittaessasi toisia metodeita. Toki tuota on tehty aiemmissa tehtävissäkin, mutta tässä se erityisesti korostuu.
Jos toteutat seuraavat metodit aivan toisistaan riippumattomasti, tulet toistaneeksi samoja koodinpätkiä. Älä kuitenkaan tee niin, vaan mieti joka kohdassa, mitä aiemmin laatimaasi metodia voisit hyödyntää. Koeta saada koodistasi mahdollisimman DRY, eli don’t repeat yourself. Toisteeton koodi on helpommin muokattavaa ja vähemmän virhealtista.
Hienommin sanoen: Jokainen metodi on abstraktio (luku 1.6). Rakenna uusia
abstraktioita vanhojen päälle. Esimerkki: Yllä kuvattu isLaterThan
-metodi on
abstraktio siitä konkreettisesta toteutuksesta, jossa katsotaan kahden Moment
-olion
ilmentymämuuttujien arvot ja verrataan niitä vertailuoperaattorilla toisiinsa:
this.time > another.time
. Toiset metodit, joilla on tarvetta vertailla kahta
Moment
-oliota voivat käyttää tätä metodia, eikä niiden tarvitse itse ruveta
vertailemaan muuttujien arvoja keskenään.
Harjoitus neljässä vaiheessa
Täydennä Interval
ja Moment
dokumentaation mukaisiksi. Alla on ehdotus työvaiheista
ja niihin liittyviä vinkkejä, mutta voit edetä muussakin järjestyksessä.
Vaihe 1/4: Interval
-luokka alkuun
Lue moduulin Scaladoc-dokumentaatiosta nyt ainakin luokkien yleiskuvaukset sekä kuvaukset
Interval
-luokan metodeistalength
jatoString
. Ne toteutetaan tässä vaiheessa.Luo uusi tiedosto
Interval
-luokkaa varten.Kirjoita luontiparametrit. Koska molemmat parametriarvot on saatava talteen metodien toteuttamiseksi, voi niille samalla määritellä ilmentymämuuttujat otsikkorivillä. Pitääkö näiden ilmentymämuuttujien olla yksityisiä?
Laadi metodi
length
. Käytä apunaMoment
-luokan metodia.Vaikka kiusaus iskisi, niin älä laadi nyt eikä myöhemmin
Moment
-luokkaan mitään sellaisia julkisia osia, joita ei ole erikseen pyydetty. Erityisesti: älä teetime
-ilmentymämuuttujasta julkista.
Laadi metodi
toString
. Se on vähän monimutkaisempi. Vinkkejä:Hyödynnä aiemmin laatimaasi metodia.
Käytä
if
-käskyjä jaelse
-osioita erottaaksesi toisistaan tarvittavat kolme tapausta.Muista, että merkkijononkin voi "kertoa", esim.
"ho" * 3
tuottaa"hohoho"
.
Siirry
timeTest
-ohjelmaan, jolle on pohjustus valmiina. Lisää sinne käskyjä, joilla testaatInterval
-olioiden luomista ja uusia metodeitasi.
Ajanhetkien yhtäsuuruudesta
Ajanhetkien yhtäsuuruusvertailu operaattoreilla ==
ja !=
on identiteettivertailu
("Osoittavatko viittaukset juuri samaan Moment
-olioon?"; ks. luku 3.3.) Se siis
ei vertaa sitä, kuvaavatko kaksi eri Moment
-oliota samaa ajanhetkeä eli onko
niiden time
-muuttujalla sama kokonaislukuarvo.
Identiteettivertailua yhtäsuuruusoperaattoreilla ei tarvitse tässä tehtävässä lainkaan eikä siitä tässä oikein hyötyäkään ole. Muilla metodeilla pärjää mainiosti!
Vaihe 2/4: isLaterThan
ja metodinimen kuormitusta
Aikavälitehtävä oli sangen mullistava kokemus.
Olin jo vauhdikkaasti tekemässä jokaiselle metodille omaa
if
-lausetta ja jättämässä metodien uusiokäytön vähille,
kun sattumalta paikalla olleet pelottavat ja tarkkasilmäiset
assistentit huomauttivat asiasta.
En uskaltanut uhmata viisaita assareita, joten muutaman
tovin mietin hikoillen, miten ihmeessä nyt voin ilman
yhtäkään if
-lausetta selvitä. Kun lopulta keksin
isLaterThan(Interval)
-metodin ratkaisun (assarin vahvasti
vinkattua), tuntui kuin olisin keksinyt pyörän. Sehän oli
nerokasta!
Laadi
Interval
-luokan metodi nimeltäisLaterThan
. Huomaa, että metodinimeä on kuormitettu (luku 4.1) ja tällaisia metodeita on kaksi. Yksi ottaaMoment
-tyyppisen parametrin ja toinenInterval
-tyyppisen. Laadi näistä nyt ensinmainittu. Käytä apuna erästä jo olemassa olevaa metodia.Laadi sitten toinen
Interval
-luokanisLaterThan
-metodeista. Käytä apuna äsken laatimaasi metodia. Niin tehdessäsi muista luvun 4.1 mainitsema pikkuseikka: jos kuormitetuista Scala-metodeista yksi kutsuu kaimaansa, on kutsujalle kirjattava paluuarvon tyyppi koodiin. Nyt tyyppi on siis kirjoitettava vähintäänkin yhdelleisLaterThan
-metodeista.Lisää taas
timeTest
-ohjelmaasi uusia käskyjä ja aja se. Kutsu testiohjelmasta molempiaisLaterThan
-metodeita ja varmista, että ne toimivat.Lisää myös
Moment
-luokkaan sieltä vielä puuttuvaisLaterThan
-metodi, joka ottaaInterval
-tyyppisen parametrin.
Vaihe 3/4: logiikkaoperaatioita
Toteuta lisää metodeita Interval
- ja Moment
-luokkiin:
Toteuta se
Interval
-luokancontains
-nimisistä metodeista, joka ottaa parametriksiMoment
-olion. Hyödynnä logiikkaoperaattoreita ja aiemmin laadittuja metodeita.Toteuta toinenkin
contains
-metodi. Hyödynnä tässäkin logiikkaoperaattoreita ja aiemmin laadittuja metodeita. Muista lisäksi yllä kerrattu asia metodinimien kuormittamisesta.Toteuta
Moment
-luokanisIn
-metodi. Se tekee käytännössä "saman asian toisin päin" kuin eräs aiemmin laatimasi metodi, joten sen voi toteuttaa yksinkertaisella tavalla.Toteuta
Interval
-luokanoverlaps
-metodi. Logiikkaoperaattoreista ja edellä laadituista metodeista on jälleen apua. Muistithan huomioida kaikki erilaiset tapaukset?Lisää uusia metodikutsuja
timeTest
-ohjelmaan. Toimivatko uudet metodisi?
Vaihe 4/4: uusia olioita vanhoja yhdistelemällä
Toteuta ja testaa vielä Interval
-luokasta puuttuvat metodit union
ja
intersection
, joille on yhteistä uusien Interval
-olioiden luominen.
A+ esittää tässä kohdassa tehtävän palautuslomakkeen.
Kuinka yksityinen on private
?
Kysyttyä: toimiiko tuo Moment
tosiaan? time
hän on yksityinen!
Katsotaan vähän tarkemmin, miksi äskeisen tehtävän koodi toimii eikä tuota virheilmoitusta.
class Moment(private val time: Int):
def isLaterThan(another: Moment) = this.time > another.time
Muuttuja time
on yksityinen. Sitä ei ole tarkoitus käyttää
ulkopuolelta. Mutta minkä ulkopuolelta?
Moment
-olio voi "kysyä omaa time
ään".
Moment
-olio voi myös "kysyä toisen Moment
-olion time
ä".
Se käy, kun pisteen edessä on jokin toiseen olioon viittaava
lauseke, tässä muuttujan another
nimi.
private
luokan koodissa tarkoittaa, että kyseinen ohjelman osa on
käytettävissä vain tuon luokan sisältä. Tuo osa ei siis ole vain yhden
olion saatavilla vaan kyseisen luokan olioiden yhteinen yksityisasia.
Lisätehtäviä: huutokaupat
DutchAuction
-tehtävä
Ota esiin AuctionHouse1-moduuli. Toteuta dokumentaation kuvaama luokka
DutchAuction
.
Ohjeita ja vinkkejä:
Pidä ensinnäkin huolta siitä, että luet kuvauksen "hollantilaistyyppisistä huutokaupoista" tunnollisesti! Kuvaus löytyy luokan
DutchAuction
dokumentaatiosta. Ellei sinulla ole kirkasta käsitystä siitä, mitä luokan pitäisi tehdä, on Scala-toteutuksen laatiminen piinallista.Huomaat jo dokumentaatiota lukiessasi, että
DutchAuction
-luokka on joiltain osin aivan samanlainen kuin ylemmän tehtävänFixedPriceSale
. Voit napata koodia ratkaisustasiDutchAuction
-luokkaasi.Voit käyttää samaa
TestApp
-ohjelmaa pakkauksestao1.auctionhouse.gui
kokeillaksesi ratkaisusi toimivuutta. Voit toki myös kirjoittaa oman tekstipohjaisen testiohjelman.Kokonaisluvusta saa vastaavan desimaaliluvun joko
A+ esittää tässä kohdassa tehtävän palautuslomakkeen.
Harmittiko kirjoittaa samoja metodeita uudestaan DutchAuction
-luokkaan
tai kopioida niitä tiedostosta toiseen? Verratonta! Olet siis motivoitunut
oppimaan aiheesta, jota käsitellään luvussa 7.3 ja jolla moinen toisto
vältetään.
EnglishAuction
-tehtävä
Jatka AuctionHouse1-moduulin parissa. Toteuta EnglishAuction
.
Ohjeita ja vinkkejä:
Varmista taas ensin, että ymmärrät miten "englantilaistyyppisten huutokauppojen" on tarkoitus toimia.
Käytä apuna annettua pientä
Bid
-luokkaa.EnglishAuction
-luokasta on annettu vain vähän pohjakoodia.Vaikka tehtävän voi ratkaista käyttäen puskureita, joihin talletetaan kaikki huutokauppoihin tehdyt huudot, niin puskurittakin pärjäät hyvin. Ihan kaikkia tehtyjä huutoja ei tarvitse tallentaa vaatimusten täyttämiseksi...
... vaan pohjaksi annetussa koodissa käytetään kahta muuttujaa, joissa on kaksi ylintä huutoa. Kiinnitä huomiota siihen, millaiset alkuarvot näille muuttujille on annettu: kun varsinaisia huutoja ei vielä ole, muuttujissa on huutajattomat alkuhintaa kuvaavat
Bid
-oliot.TestApp
-kokeiluohjelmaa sopii käyttää tässäkin.
A+ esittää tässä kohdassa tehtävän palautuslomakkeen.
Yhteenvetoa
Logiikkaoperaattoreilla voi yhdistellä totuusarvoja. Niiden avulla voi käsitellä moniosaisia ehtoja: "X ja Y", "X tai Y".
Lukuun liittyviä termejä sanastosivulla: logiikkaoperaattori, kuormittaa; DRY.
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!
Materiaalin luvut tehtävineen ja viikkokoosteineen on laatinut Juha Sorva.
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, Kaisa Ek, Joonatan Honkamaa, Antti Immonen, Jaakko Kantojärvi, Onni Komulainen, Niklas Kröger, Kalle Laitinen, Teemu Lehtinen, Mikael Lenander, Ilona Ma, Jaakko Nakaza, Strasdosky Otewa, Timi Seppälä, Teemu Sirkiä, Joel Toppinen, Anna Valldeoriola Cardó ja Aleksi Vartiainen.
Lukujen alkuja koristavat kuvat ja muut vastaavat kuvituskuvat on piirtänyt Christina Lassheikki.
Yksityiskohtaiset animaatiot Scala-ohjelmien suorituksen vaiheista suunnittelivat Juha Sorva ja Teemu Sirkiä. Teemu Sirkiä ja Riku Autio toteuttivat ne apunaan Teemun aiemmin rakentamat työkalut Jsvee ja Kelmu.
Muut diagrammit ja materiaaliin upotetut vuorovaikutteiset esitykset laati Juha Sorva.
O1Library-ohjelmakirjaston ovat kehittäneet Aleksi Lukkarinen, Juha Sorva ja Jaakko Nakaza. Useat sen keskeisistä osista tukeutuvat Aleksin SMCL-kirjastoon.
Tapa, jolla 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+ luotiin alun perin Aallon LeTech-tutkimusryhmässä pitkälti opiskelijavoimin. Nykyään tätä avoimen lähdekoodin projektia kehittää Tietotekniikan laitoksen opetusteknologiatiimi ja tarjoaa palveluna laitoksen IT-tuki; sitä ovat kehittäneet kymmenet Aallon opiskelijat ja muut.
A+ Courses -lisäosa, joka tukee A+:aa ja O1-kurssia IntelliJ-ohjelmointiympäristössä, on toinen avoin projekti. Sen suunnitteluun ja toteutukseen on osallistunut useita opiskelijoita yhteistyössä O1-kurssin opettajien kanssa.
Kurssin tämänhetkinen henkilökunta löytyy luvusta 1.1.
Joidenkin lukujen lopuissa on lukukohtaisia lisäyksiä tähän tekijäluetteloon.
Kertaus:
touches
-metodi palauttaatrue
taifalse
. Vastaavasti myösisLost
-metodi palauttaa jommankummanBoolean
-arvon.