Luku 1.3: Lukuja, tekstiä, ääniä ja kuvia

../_images/person01.png

Missä mennään?

Nyt kun edelliset luvut ovat antaneet kokonaiskuvaa, lähdetään kehittämään konkreettisia ohjelmointitaitoja pienin askelin.

Lyhyen tähtäimen suunnitelma olkoon tämä:

  1. Nyt käsillä olevasta luvusta 1.3 aina lukuun 1.6 asti opit käyttämään valikoituja yleishyödyllisiä tekniikoita ja ymmärtämään niihin liittyviä käsitteitä. Ohjelmoit antamalla yksittäisiä käskyjä tietokoneelle. Nämä perustekniikat ovat aluksi "irrallisia osia", ja niistä tehdään vain pieniä erillisharjoituksia, mutta pian näet, että niitä käytetään lähes kaikkien sovellusohjelmien toteutuksessa.

  2. Luvuissa 1.7 ja 1.8 opit luomaan itse uusia komentoja olemassa olevia yhdistelemällä.

  3. Luvusta 2.1 alkaen pureudumme siihen, miten sovellusohjelman voi koostaa palasista. Aiemmin opitut tekniikat tulevat tässä tarpeeseen.

Yksi ynnä yksi

Käytännöllisesti katsoen kaikissa ohjelmissa tarvitaan perusaritmetiikkaa: yhteen-, vähennys-, kerto- ja/tai jakolaskua. Vaikkapa edellisessä luvussa kohdattu GoodStuff-ohjelma tarvitsee jakolaskua määrittääkseen kokemusten hinta–laatu-suhteen, ja Pong-ohjelma laskee pallolle ja mailoille aina vain uusia koordinaatteja pelin käydessä.

Scala-kieli, kuten muutkin ohjelmointikielet, tarjoaa välineitä luvuilla laskemiseen. Esimerkiksi seuraavalla Scala-kielen käskyllä voit ohjeistaa tietokonetta laskemaan, paljonko on yksi plus yksi:

1 + 1

Yksinkertaista. Mutta mihin tällainen käsky kirjoitetaan?

Yksi vaihtoehto olisi laatia ja tallentaa kokonainen ohjelma, jossa hyödyntäisimme käskyä jotenkin. On kuitenkin myös toinen ja usein kätevämpi tapa kokeilla Scala-kielen käskyjä yksitellen:

REPL

Otetaan esiin työkalu, josta käytetään nimeä REPL. Näin:

  1. Valitse vasemman reunan Project-näkymästä moduuli, johon REPL-työkalu käynnistetään. Tässä luvussa sopiva moduuli on GoodStuff, joten valitse se.

  2. Paina Ctrl+Shift+D tai valitse IntelliJ’n ylävalikosta Tools → Scala REPL.

  3. Esiin tulee suunnilleen tällainen näky. Varmista, että sen otsikkona on REPL for GoodStuff.

    ../_images/ij_repl.png

    REPL käynnistyy IntelliJ-ikkunan alalaitaan Run-välilehdelle. Kehotteen scala> perään voi kirjoittaa Scala-koodia. Painallus Ctrl+Enter suorittaa syötetyn koodin. Tulokset ilmestyvät kehotteen alle.

Tämä työkalu on mainio Scala-käskyjen kokeilemiseen. REPL on lyhenne sanoista read–evaluate–print loop, jotka kertovat perusidean:

  • read: Voit kirjoittaa REPLiin Scala-kielisen pätkän, jonka REPL vastaanottaa eli "lukee".

  • evaluate: REPL suorittaa koodinpätkäsi heti sen vastaanotettuaan; esimerkiksi aritmeettisen laskutoimituksen tapauksessa se määrittää laskun tuloksen.

  • print: Evaluoinnin tulokset tulostuvat näytölle. ("Tulostamisesta" voi tulla mieleen lähinnä printterit, mutta ohjelmoinnin kielessä myös tekstin kirjoittamisesta näytölle puhutaan tulostamisena.)

  • loop: Voit toistaa yllä mainittuja vaiheita niin kauan kuin haluat.

Kirjoita REPLin kehotteeseen scala> vaikkapa juuri teksti 1 + 1 ja paina Ctrl+Enter. Tulos näyttää suurin piirtein tältä:

1 + 1val res0: Int = 2

Tämä on Scala-REPLin tapa kertoa, että laskutoimituksen tulos on kaksi.

res0 tulee sanasta result ja tarkoittaa "tulos numero 0" eli ensimmäinen tällä käyttökerralla saatu tulos. Tässä yhteydessä, kuten ohjelmoinnissa usein muutenkin, numerointi alkaa nollasta eikä ykkösestä.

Int puolestaan on Scala-kieltä ja tarkoittaa kokonaislukua. Kokonaisluku on englanniksi integer; Scalassa, kuten ohjelmoinnissa usein muutenkin, monet ilmaisut pohjautuvat englannin kielen sanoihin.

val-sanan (value) voit nyt jättää huomiotta. Palaamme aikanaan siihen, miksi se toistuu näiden REPL-tulosteiden alussa.

Voit pyytää lisää laskutuloksia REPLiltä. Tulokset tulostuvat edellisten perään numeroituina:

2 + 5val res1: Int = 7
1 - 5val res2: Int = -4
2 * 10val res3: Int = 20
15 / 3val res4: Int = 5

Kokeile vapaasti itse peruslaskutoimituksia REPLissä.

Käytännön vinkki

Voit "kelata" aiemmin saman käyttösession aikana antamiasi syötteitä REPLissä painamalla näppäimistön ylä- ja alanuolia. Kokeile! Tästä on usein hyötyä.

Välilyönneistä

Välilyönnit operaattorien ympärillä eivät ole pakolliset eivätkä vaikuta Scala-koodin toimintaan. Ne kuitenkin selkiyttävät koodia (varsinkin kun sitä rupeaa olemaan enemmän), ja niiden käyttö kuuluu hyvään ohjelmointityyliin.

REPL vs. kokonainen ohjelma

Edellisessä luvussa tarkastelimme GoodStuff-ohjelmaa, joka oli tallennettu tiedostoihin. GoodStuff-ohjelman pystyi näin ollen ajamaan halutessaan. Ohjelmakoodia kirjoitettiin ja ajettiin erikseen.

REPL on luonteeltaan erilainen: sinne kirjoitetut yksittäiset käskyt eivät jää pysyvämmin talteen. REPLissä ei myöskään ole vastaavaa eroa koodin kirjoittamishetken ja ajohetken välillä: kukin käsky tulee suoritetuksi saman tien, ja ohjelmointi on "välitöntä".

Lausekkeista

Vaikka esimerkkimme ovat olleet äärimmäisen yksinkertaisia, jo niissä esiintyi useita ohjelmoinnin peruskäsitteitä, joiden ymmärtäminen on erinomaisen tärkeää. Keskeisin näistä on lauseke (expression).

Muodollista määritelmää emme tässä lausekkeen käsitteelle tarvitse, vaan riittää ajatella, että ohjelmoinnissa lausekkeella tarkoitetaan sellaista ohjelmointikielen ilmaisua, jolla on jokin arvo (value). Esimerkeissämme on esiintynyt aritmeettisia lausekkeita; niiden arvo on kyseisen laskutoimituksen tulos. Vaikkapa 1 + 1 on lauseke, jonka arvo on kokonaisluku kaksi.

Tässä vielä yksi REPL-esimerkki ja sen kautta selitettynä muutama tärkeä termi. (Muistutus: Korosta vihreäpohjaiseen selitystekstiin liittyvä kohta siirtämällä hiiren kursori selitystekstin päälle.)

50 * 30val res5: Int = 1500

Aritmeettinen lauseke muodostuu osalausekkeista, joita yhdistää aritmeettinen operaattori (operator). Tässä on käytetty kertolaskuoperaattoria *.

Kertolaskettavat ovat siis myös yksinkertaisia lausekkeita — ilmaisuja, joilla on arvo. Tässä esimerkissä nämä lausekkeet ovat literaaleja (literal) eli ohjelmakoodiin sellaisenaan kirjoitettuja arvoja. Literaalien arvo näkyy suoraan ohjelmakoodista; esimerkiksi merkkien viisi ja nolla muodostaman lausekkeen 50 arvo on luku viisikymmentä.

REPL evaluoi (evaluate) sinne syötetyt lausekkeet. Evaluoinnin tuloksena saadaan lausekkeiden arvot, jotka tulostuvat REPLiin.

Arvoilla on tietotyypit (data type). Kokonaislukutyyppi Int on eräs Scala-kieleen määritellyistä tietotyypeistä.

Yksittäisen literaalinkin voi syöttää REPLiin, kuten alla. Evaluointi on tällöin mahdollisimman yksinkertaista: literaalilausekkeen arvoksi saadaan juuri se syötetty arvo.

123val res6: Int = 123

Vielä tässä luvussa — ja kasvavassa määrin tulevissa — kohtaamme myös muita tietotyyppejä kuin Int, muunlaisia lausekkeita kuin literaaleja ja aritmeettisia lausekkeita sekä muita operaattoreita kuin aritmeettisia.

Jakolaskua

Vaikka moni asia Scala-aritmetiikassa onkin matematiikasta tuttu, eräs seikka voi yllättää. Kokeile erilaisia jakolaskuja, vaikkapa näin:

> 15 / 5
res11: Int = 3
> 15 / 7
res12: Int = 2
> 19 / 5
res13: Int = 3

(Sivuhuomautus: Tuota REPL-esimerkkiä samoin kuin kurssimateriaalin tulevia esimerkkejä on lyhennetty jättämällä toistuva kehote scala>  ja tulosteen alun val  pois. Älä siis häkelly, jos kurssimateriaalin REPL-tulosteet eivät näytä täsmälleen siltä, mitä itse saat vastaukseksi, kun annat samat käskyt REPLissä.)

Kokeile itse REPLissä ohjelmoimalla muitakin kokonaislukujen jakolaskuja. Kerro, mikä seuraavista kuvaa parhaiten lausekkeen 99999 / 100000 evaluointia.

Entä lausekkeen 1000 / (5 / 6) evaluointia?

Mitä jos haluan pyöristää "oikein"?

Scalan tapa käsitellä kokonaislukuja on ohjelmointikielissä yleinen. On ehkä yllättävänkin usein kätevää, että se toimii juuri noin.

Muunlaisiin pyöristystarpeisiin löytyy kyllä ratkaisuja, joista lisää myöhemmin (esim. luvussa 5.2).

Suoritusjärjestys ja sulkeet

Operaattoreilla on suoritusjärjestys (operator precedence). Aritmeettisten laskutoimitusten suoritusjärjestys on tuttu:

1 + 2 * 3res0: Int = 7
5 * 4 + 3 * 2 + 1res1: Int = 27

Ohjelmoija voi vaikuttaa suoritusjärjestykseen käyttämällä sulkeita:

(1 + 2) * 3res2: Int = 9
5 * ((4 + 3) * 2 + 1)res3: Int = 75

Suljevaroitus

Olet saattanut koulumatematiikassa tottua käyttämään erilaisia suljetyyppejä, kun sulkeet ovat sisäkkäin. Olet esimerkiksi ehkä käyttänyt kaarisulkeita hakasulkeiden sisällä, kuitenkin niin, että molemmilla suljetyypeillä on sama merkitys laskujärjestyksen määräämisessä.

Scala-ohjelmakoodissa näin ei voi tehdä.

Laskettavien ryhmittely on yksi niistä asioista, johon kaarisulkeet Scala-ohjelmassa sopivat; esimerkiksi haka- ja aaltosulkeet eivät tähän kelpaa. Muunmuotoisilla sulkeilla on ihan toisia käyttötarkoituksia, joista lisää myöhemmin kurssilla.

Scala on tässä suhteessa tyypillinen ohjelmointikieli. Ohjelmoinnissa on tavanomaista, että erilaisilla sulkeilla on erilaisia merkityksiä.

Desimaaliluvut

Entäs desimaaliluvut sitten?

Ne toimivat pitkälti niin kuin sopii odottaa. Huomaa käyttää desimaalierottimena epäsuomalaisittain pistettä:

4.5res4: Double = 4.5
2.12 * 3.2205res5: Double = 6.82746
4.0res6: Double = 4.0

Kuten yltä näkyy, "desimaalilukuja" kutsutaan Scalassa Doubleiksi. Tämän kummallisen nimen syyt ovat historialliset.

Double-arvoilla myös jakolasku onnistuu tutumpaan tapaan. Kun lasketaan kahdella Double-tyyppisellä arvolla, on myös tulos Double-tietotyyppiä.

999.0 / 1000.0res7: Double = 0.999

Lukutyyppien yhdistely

Double- ja Int-tyyppisiä arvoja voi yhdistellä.

29 / 10res8: Int = 2
29.0 / 10res9: Double = 2.9
29 / 10.0res10: Double = 2.9
30.0 / 10.0res11: Double = 3.0

Kun laskettavina on yksi kokonaisluku ja yksi desimaaliluku, tuloksena saadaan desimaaliluku. Näin siinäkin tapauksessa, että jakolasku menee tasan.

Entä jos tekee monimutkaisemman erityyppisiä arvoja sisältävän lausekkeen? Vaikkapa (10 / 6) * (2.0 + 3) / 4. Tällöin operaattorien suoritusjärjestys määrää, miten kukin osalauseke evaluoidaan ja minkä tyyppinen arvo kussakin vaiheessa saadaan. Osaatko päätellä, mikä mainitun lausekkeen arvo on?

Tarkista päättelysi paikkansa pitävyys tutustumalla tämän lausekkeen evaluointiin seuraavan vuorovaikutteisen animaation avulla:

Tietokoneen muistista ja kurssimateriaalin animaatioista

Tietokoneen muisti on bittivarasto, josta ohjelmat voivat varata tilaa erilaisiin tarkoituksiin. Kullakin muistin kohdalla on oma osoitteensa, eräänlainen järjestysnumero, joka identifioi kyseisen muistipaikan.

Muistin käytön täsmälliset yksityiskohdat "bittitasolla" eivät ole tällä kurssilla keskeisiä. Silti ohjelman muistinkäytön pääpiirteittäisestä osaamisesta on aloittelevallekin ohjelmoijalle kosolti hyötyä. Siksi käytämme äskeisen kaltaisia animoituja diagrammeja, jotka kuvaavat ohjelman suorituksen vaikutuksia muistin sisältöön. Diagrammin "alueet" vastaavat tietokoneen muistista tiettyihin tarkoituksiin varattuja osia.

Äskeinen ensimmäinen animaatioesimerkki on yksinkertainen, ja sen esittämä lauseke lienee hyvin ymmärrettävissä ilman animaatiotakin. Silti on hyvä jo tässä vaiheessa totutella tähän esitystapaan, sillä käytämme vastaavia animaatioita tulevassa materiaalissa myös mutkikkaampien ilmiöiden havainnollistamiseen.

Mikä on seuraavan Scala-laskutoimituksen tulos? Järkeile päässäsi ja tutki sitten REPLissä ohjelmoimalla.

6 / 10.0 + 6.0 / 10 + 6 / 10

Kirjoita tulos (vain lukuarvo, ei tietotyyppiä tms.) tähän:

Merkkijonot

Lukujen lisäksi ohjelmissa tarvitaan toistuvasti tekstiä. Kokeillaan:

"Moi"res12: String = Moi
"Täällähän kaikuu!"res13: String = Täällähän kaikuu!

Kuten REPL kertoo, tekstinpätkiä eli virallisemmin merkkijonoja kuvataan tietotyypillä String (englannin sanasta string tai pidemmin string of characters) .

Merkkijonoliteraalilla tarkoitetaan ohjelmakoodiin sellaisenaan kirjoitettua merkkijonoa (vrt. Int- ja Double-tyyppiset literaalit ylempänä). Se kirjoitetaan lainausmerkkeihin.

(Yhden merkkijonoliteraalin kohtasitkin jo aiemmin, kun edellisessä luvussa korjasit kirjoitusvirheen GoodStuff-ohjelmasta.)

Jos unohdat lainausmerkit, saat yleensä virheilmoituksen, koska silloin REPL yrittää tulkita kirjoittamaasi tekstiä Scala-käskyinä:

Moi-- Error:
  |Moi
  |^^^
  |Not found: Moi

Tulostuskäsky

REPL on tarjonnut meille kätevän palvelun näyttämällä kunkin evaluoidun lausekkeen arvon ja tyypin. Mutta mitä jos haluaisimme tulostuvan jotain muuta kuin tuon tutun litanian resX: Tyyppi = arvo?

Voimme räätälöidä halutunlaisen tulosteen Scala-kielisellä tulostuskäskyllä.

Scalassa tulostaminen onnistuu println-nimisellä käskyllä:

println("Terve!")Terve!
println(123)123
println(-5.2)-5.2

Nämä käskyt ovat melko itseselitteisiä, mutta niissäkin kohtaamme tärkeitä Scala-kielen piirteitä, jotka ansaitsevat erillisen huomion.

Käskyn nimi kirjoitetaan ensin. Se määrää yleisesti, mitä tehdään. Scalan sana println tulee englannin sanoista print line.

Nimen perään kirjoitetaan kaarisulkeet. Sulkeiden ympärillä välilyönnit eivät ole tapana (mutta voisi ne siihenkin kirjoittaa vaikuttamatta koodin toimintaan).

Sulkeiden sisään kirjoitetaan käskylle parametrilausekkeet. Ne määrittävät tarkemmin, mitä on tarkoitus tehdä. Tässä kullekin println-käskylle annetaan yksi parametrilauseke, joka määrää, mitä tulostetaan.

Parametriksi voi kirjoittaa myös literaalia monimutkaisemman lausekkeen. Esimerkiksi käsky println("Ohjelmointi" + (100 - 99)) on aivan kelvollista Scalaa. Seuraava animaatio kuvaa tuon tulostuskäskyn suorituksen vaiheet.

Suoritus eteni siis "sulkeiden sisältä ulos". Myöhemmin näet, miten tämä nyrkkisääntö pätee muissakin yhteyksissä: sulkeiden sisään kirjoitetut parametrilausekkeet evaluoidaan ensin, ja näin saadut parametriarvot käytetään sitten käskyn suorituksessa.

Parametri vai argumentti?

Joissain muissa ohjelmointia käsittelevissä teksteissä käytetään termiä argumentti (argument) tarkoittamaan joko sitä, mitä olemme kutsuneet parametrilausekkeeksi, tai sitä, mitä olemme kutsuneet parametriarvoksi, tai molempia.

Toinen tulostuskäsky: print

println-käskyn lisäksi on myös print, joka toimii samoin, paitsi ettei se vaihda riviä lopuksi. REPLissä tämän huomaa, kun antaa pari käskyä kerralla. Vertaa:

println("kissa")
println("kala")kissa
kala
print("kissa")
print("kala")kissakala

println-käsky on yleisempi, ja O1-kurssillakin käytämme lähinnä sitä.

Koetapa tätäkin

Kirjoita REPLiin println(1 + 1, siis näin:

println(1 + 1 
 
 
 
 

Vaikka kuinka Ctrl+Enteriä rämpyttää, ei tapahdu oikein mitään. Rivi vain vaihtuu. Jäikö REPL jumiin?

Ei jäänyt. Ongelma on tuolta lopusta puuttuva kaarisulje. Käsky on keskeneräisen oloinen, ja REPL odottaa sinun kirjoittavan sen loppuun.

Lisää puuttuva merkki ja kokeile uudestaan. REPL tokenee.

Tämä siis vinkkinä siltä varalta, että vahingossa käy noin. Sama voi sattua myös joidenkin muiden välimerkkien kanssa.

Lisää merkkijonoista nuoteilla

../_images/piano.png

Merkkijonoilla eli String-tyyppisillä arvoilla kuvataan usein tekstiä, mutta voi niillä kuvata muutakin. Vaikkapa musiikkia. Alla on tulostuskäsky, joka tulostaa Ukko Nooa -hitin ensimmäiset tahdit. Nuotit on tässä esitetty yksinkertaisesti kirjaimina, jotka vastaavat myös oheisen kuvan pianon koskettimia.

println("cccedddf")cccedddf

Sepä ei ollut kovin jännittävää. Nuotit olisi antoisampaa soittaa kuin tulostaa.

Otetaan avuksi toinen ilmaisu. Toisin kuin println, joka kuuluu Scala-kielen perustyökaluihin, nyt kokeiltava play on laadittu tämän kurssin tarpeisiin. Sen avulla saamme vähän eloa muun muassa näihin tämän luvun pieniin merkkijonoesimerkkeihin.

(Soittokäsky on määritelty O1Library-moduulissa. Jos et noutanut sitä IntelliJ’hin edellisessä luvussa 1.2, tee se nyt ja käynnistä REPL uudelleen.)

Kokeile seuraavaa.

play("cccedddf")

Tämä käsky ei tuota näkyvää tulostetta vaan soittaa parametriksi saamaansa String-arvoon merkityt nuotit virtuaalisella pianolla. Olihan sinulla äänet päällä koneessasi?

Kokeile antaa myös muita merkkijonoja play-käskyn parametriksi. Voit kokeilla esimerkiksi välilyöntejä, jotka play tulkitsee tauoiksi:

play("cccdeee f ffe e")

Ja viivoja, jotka play tulkitsee pidempikestoisiksi nuoteiksi:

play("cccdeee-f-ffe-e")

Ääni tällä kurssilla

Kurssilla on muutamia kohtia, joissa käytetään ääntä, kuten äsken. Tämä tietysti toimii vain, jos sinulla on äänentoistolaitteisto käytettävissäsi.

Jos opiskelet ihmisten keskellä, esimerkiksi Aallon tietokoneluokissa, varaa omat kuulokkeet mukaan.

Jos koira söi kuulokkeesi, niin voit käyttää println-käskyä play-käskyjen sijaan. Se kuiventaa näitä kohtia muttei vaaranna kurssisuoritusta.

Emme edellytä kurssin opiskelijoilta musiikillista osaamista.

Merkkijonojen yhdisteleminen

Merkkijonoja voi yhdistellä toisiinsa plus-operaattorilla. Tällä operaattorilla, joka tarkoitti lukujen yhteydessä yhteenlaskua, on merkkijonojen yhteydessä toisenlainen merkitys:

"omena" + "kynä"res14: String = omenakynä
"REPL with" + "out" + " a cause"res15: String = REPL without a cause

Lainausmerkkien sisällä välilyönneillä on väliä.

Sama operaattori toki toimii myös parametrilausekkeen osana:

println("Ukko Nooa, Ukko Nooa" + " oli kunnon mies.")Ukko Nooa, Ukko Nooa oli kunnon mies.
play("cccedddf" + "eeddc---")

Merkkijonon "kertominen"

Usein kysyttyä: onko pistemäärä vihje?

Alla on kysymys, jossa valitaan annetuista väittämistä kaikki paikkansa pitävät; tällaisia tehtäviä on kurssilla muitakin.

Jos tällaisesta tehtävästä saa esimerkiksi kaksi pistettä, tarkoittaako se, että paikkansa pitäviä väittämiä on kaksi kappaletta? Ei tarkoita. Oikeita väittämiä voi olla mikä tahansa määrä. Missään kurssin tehtävistä pistemäärä tai muu ohjelmointisisällön ulkopuolinen seikka ei ole vihje. Ratkaise tehtävät ohjelmointitiedon ja saamasi palautteen perusteella.

On myös mahdollista "kertoa" merkkijono luvulla. Voimme muodostaa esimerkiksi nämä lausekkeet:

"cha" * 3
"MC " + "koppa" * 5 + "kuoriainen"

Mikä tai mitkä seuraavista noihin kahteen lausekkeeseen liittyvistä väittämistä pitävät paikkansa? Tutki itse REPLissä ohjelmoimalla!

Kokeile näitä:

play("<cccedddfeeddc---")play(">>>" + "cccedddfeeddc---")play("ccceddd>feedd<<<c---")

play on määritelty niin, että >- ja <-merkeillä voi vaihtaa oktaavia; merkkiä seuraavat äänet soitetaan korkeammalta (>) tai matalammalta (<). Useampi oktaavinvaihdosmerkki tuottaa dramaattisemman muutoksen: esimerkiksi keskimmäinen äskeisistä kolmesta käskystä pimputtaa Ukko Nooaa kolme oktaavia korkeammalta.

Käytä Scala-merkkijonojen operaattoreita + ja *, ja tee niillä pastissi Tappajahai-elokuvan "tunnussävelestä". Tarkemmin sanoen muodosta mainittuja operaattoreita käyttäen lauseke, jonka arvo on merkkijono, jossa on

  • alussa kolme <-väkästä, jotka madaltavat kaikkia tulevia ääniä kolmella oktaavilla (nämä kolme alussa ovat merkkijonon ainoat <-merkit)

  • sitten peräkkäin nuottiparia "ef" toistettuna kuusitoista kertaa

  • lopuksi peräkkäin paria "EF" kahdeksan kertaa.

Kokeile REPLissä yksinkertaisesti syöttämällä muotoilemasi lauseke. Kokeile myös antaa tuo lauseke parametriksi play-käskylle.

Jos tulee ongelmia, niin ensimmäinen asia, joka kannattaa tarkistaa huolella, on lainausmerkit. Kukin merkkijononpätkä lainausmerkkeihin! Ongelmatilanteissa kannattaa paitsi soittaa myös tulostaa muodostamasi lausekkeen arvo, niin voit tutkia ongelmaa tarkemmin. Muista myös harkkaryhmät/Piazza/Telegram.

Korjaa pisteet kirjoittamalla yllä pyydetty lauseke operaattoreineen myös tähän alle. Siis se operaattorit sisältävä lauseke, ei soittokäskyä eikä tuon lausekkeen arvoksi muodostuvaa yhdistelmämerkkijonoa. Lausekkeessa tulee siis esiintyä luvut 3, 16 ja 8.

Toinen tapa vaihtaa oktaavia

Mainitun väkäsmerkinnän lisäksi play sallii kirjata oktaavit numeroina yksittäisten äänten kohdalle. Käytössä on numerot 0–9, joista oletusoktaavi on numero 5. Nämä siis tekevät saman asian:

play(">cd<<e")play("c6d6e4")

Tämä ei ole varsinaisesti tärkeää, koska kyse on vain kurssille laaditusta yksinkertaisesta soittopelistä, mutta tieto voi helpottaa omia äänileikkejä, jos haluat niitä tehdä.

Kuvia

GoodStuff-ohjelmassa näkyy irvinaaman kuva suosikkikokemuksen kohdalla. Pong-pelissä mailat näkyvät suorakaiteen kuvina ja pallo ympyrän kuvana. Ohjelmat käsittelevät kuvia.

Kuvia näkyviin

Ladataan kuva verkko-osoitteesta Scala-kielisellä käskyllä. Kokeile:

Pic("https://en.wikipedia.org/static/images/project-logos/enwiki.png")res16: o1.gui.Pic = https://en.wikipedia.org/static/images/project-logos/enwiki.png

Huomaa iso P-kirjain. Pic on kuvatietotyypin nimi. Se kirjoitetaan isolla samoin kuin String tai Int.

Parametriksi välitetään osoite. Osoite on tässä kuvattu merkkijonoliteraalina ja kirjoitetaan siis lainausmerkkeihin.

Pakkauksen nimi o1 kertoo siitä, että nytkin käytämme tämän kurssin tarpeisiin laadittua aputyökalustoa. Ei silti huolta: näitä työkaluja käyttäessäsikin opit kyllä ohjelmoinnin yleisempiä periaatteita, jotka toimivat kurssin ulkopuolellakin.

Tuloksena saadaan Pic-tyyppinen arvo, joka sisältää netistä ladatun kuvan.

Noin saimme erään kuvan ladattua tietokoneesi muistiin, mutta näkyviin se ei tullut. Yksi helppo tapa saada kuva näkyviin on käsky show, joka toimii samankaltaisesti kuin play äänille. Siitä on esimerkki alla.

show(Pic("https://en.wikipedia.org/static/images/project-logos/enwiki.png"))

Kuva piirtyy näkyviin erilliseen pikkuikkunaan näytön vasemman yläkulman tuntumaan. Klikkaa kuvaa tai paina Esc sulkeaksesi ikkunan.

Äskeisessä esimerkissä kuva ladattiin netistä. Kuvan voi ladata myös tiedostosta, joka on tallessa omalla koneella. Vaikkapa näin:

show(Pic("d:/jokin/kansio/koneellani/kuva.png"))

Lainausmerkeissä on polku kuvatiedostoon. (Tämä on vain esimerkkipolku tiedostoon, joka voisi olla jonkin koneen kiintolevyllä. Jos kokeilet koodia, korvaa tuo koneellesi tallennetun tiedoston sijainnilla.)

Toisaalta koko tiedostopolku ei välttämättä ole tarpeellinen. Jos tiedosto on sellaisen moduulin sisällä, joka on valittuna käsiteltäväksi, niin yksinkertaisempikin riittää. Olettaen, että käynnistit REPLin GoodStuff-moduuliin, tämäkin toimii, koska face.png löytyy tuon moduulin sisältä:

show(Pic("face.png"))

Värillisiä kuvioita

Jo nähty Pong-peli on esimerkki ohjelmasta, jonka grafiikka perustuu tuttuihin geometrisiin kuvioihin. Työkalupakkimme tarjoaa välineitä, joilla erivärisiä kuvioita on helppo luoda. Kokeillaan.

Aloitetaan väreistä. Tyypillisiin perusväreihin voi viitata yksinkertaisesti niiden englanninkielisillä nimillä:

Blueres17: o1.gui.Color = Blue
Greenres18: o1.gui.Color = Green
DarkGreenres19: o1.gui.Color = DarkGreen

Värit ovat tyyppiä Color.

Luodaan circle-käskyllä sininen ympyrä:

circle(200, Blue)res20: o1.gui.Pic = circle-shape

Sulkeisiin kirjataan kaksi parametrilauseketta pilkulla erotettuina: koko ja väri.

Tuloksena saadaan kuva, johon on piirretty ympyrä, jonka halkaisija on 200 kuvapistettä eli pikseliä (pixel; sanoista picture element). Kuva on aiemmin kohdattua tyyppiä Pic.

show-käskylle voi välittää minkä vain Pic-tyyppisen parametrin. Verkosta tai levyltä ladatun kuvan sijaan kelpaa myös itse määritelty ympyrän kuva:

show(circle(200, Blue))

Kokeile myös muita värejä ja muotoja. Tässä esimerkiksi suorakaide, sen ystävä sekä tasakylkinen kolmio:

show(rectangle(200, 500, Green))show(rectangle(500, 200, Red))show(triangle(150, 200, PhthaloBlue))

Luo soikio (ellipse) ja tuo se näkyviin. Käytä show-käskyä edellisten esimerkkien tapaan.

Soikiota luodessasi kirjaa sulkeisiin kolme parametria: leveys sekä korkeus pikseleinä ja viimeisenä väri.

Kirjoita tähän show-käsky, joka näyttää sinisen (Blue) soikion, joka on 400 pikseliä leveä ja 300 korkea.

REPListä vielä

Ehkä olet miettinyt, onko REPL vain opiskelijoiden tai aloittelijoiden työkalu osaavien ammattilaisten sijaan.

Ei ole.

Monet ammattilaisetkin käyttävät REPLiä erilaisiin kokeiluihin ja luonnosteluun. Sitä paitsi myös osaavat ammattilaiset ovat opiskelijoita perehtyessään uusiin ohjelmointikieliin ja muiden laatimiin ohjelmakomponentteihin.

REPLin kautta voi käyttää monimutkaisiakin ohjelmakomponentteja, myös sellaisia, jotka ovat osina tietyissä sovellusohjelmissa. Vaikka emme ole vielä paljon koodausta harjoitelleetkaan, voit jo helposti REPLin kautta koekäyttää valmiin ohjelman osaa. Kokeile seuraavaa, jos haluat.

GoodStuff-käyttöliittymä REPListä käsin

Edellisessä luvussa käynnistettiin GoodStuff-ohjelman käyttöliittymä IntelliJ’n valikon avulla. Voit myös avata GoodStuff-käyttöliittymäikkunan antamalla seuraavat Scala-komennot REPLissä.

(Seuraava toimii REPLissä, kunhan olet käynnistänyt REPLin siten, että sinne on ladattuna juuri GoodStuff-moduuli. Näin tapahtuu, kunhan sinulla on GoodStuff valittuna Project-näkymässä tai jokin tuon moduulin tiedostoista aktiivisena editorissa, kun painat Ctrl+Shift+D.)

val testWindow = CategoryDisplayWindow(Category("Hotel", "night"))
testWindow.visible = true

Lyhyesti selitettynä: näin määrätään tietokone luomaan uusi kokemuskategoria hotelleille (jos haluat, voit korvata lainausmerkeissä olevat sanat muillakin) sekä uusi käyttöliittymäikkuna, jossa tuon kategorian kokemuksia voi kirjata.

Kaikkien äskeisen esimerkin käskyjen täsmällisempi merkitys selviää kurssin parin ensimmäisen kierroksen aikana.

Yhteenvetoa

  • Ohjelmoija voi muodostaa aritmeettisia lausekkeita yhdistelemällä kokonaislukuja (Int), desimaalilukuja (Double) ja aritmeettisia operaattoreita.

  • Lauseke on ilmaisu, jolle voidaan määrittää arvo. Lausekkeen arvon määrittämistä sanotaan evaluoimiseksi.

  • Merkkijonotyyppiä String käyttäen voi muodostaa lausekkeita, joiden arvoina on tekstinpätkiä.

  • println-käskyllä voit itse määrittää tarkasti, mitä haluat tulostettavan.

  • Kurssin työkalupakki sisältää välineitä mm. merkkijonoina kuvatun äänen soittamiseen (play) ja kuvien käsittelyyn (Pic, show, circle, Red jne.).

  • REPL on mainio työkalu muun muassa uusien ohjelmointitekniikoiden kokeiluun ja opiskeluun.

  • Kurssin ensimmäisten viikkojen aikana selviää, miten tässä luvussa käsiteltyjä perustietotyyppejä, lausekkeita ja operaatioita voi hyödyntää GoodStuffin tai muun sovelluksen toteutuksen osana.

  • Lukuun liittyviä termejä sanastosivulla: REPL; lauseke, arvo, evaluoida, literaali; operaattori; tietotyyppi; merkkijono; tulostaa; parametrilauseke, parametriarvo.

Alla on kaavio eräistä tärkeimmistä käsitteistä ja niiden tärkeimmistä suhteista. Täydennämme tätä kaaviota kurssin parin ensimmäisen viikon aikana.

Opettele tämän luvun käsitteet!

Useat tässä luvussa ensimmäistä kertaa kohdatut termit ja käsitteet ovat erittäin keskeisiä. Eivät itseisarvoisesti vaan siksi, että pystyt niiden avulla jäsentämään ohjelmointiin liittyviä asioita. Termistön hallinta auttaa sekä tämän materiaalin lukemisessa että toisten ohjelmoijien (esim. assarien ja työparisi) kanssa viestimisessä. Kiinnitä erityistä huomiota yllä olevan kaavion käsitteisiin.

Silti vielä tärkeämpää on...

... että saat tuntumaa ohjelmoinnin käytäntöön. REPL-ympäristö sopii tähän hyvin. Älä epäröi kokeilla REPLissä omin päin erilaisia juttuja, myös muita kuin tässä materiaalissa ehdotettuja.

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.

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