Sisällysluettelo

Tehtävät

Kysely: Oma arvio osaamisesta

Tutkimus: Oma arvio osaamisesta

Käytämme tietoja kurssiemme kehittämiseen ja opetuksen tutkimukseen.

Tässä kyselyssä tutkitaan suhtautumistasi omaan kurssin aikana karttuneeseen osaamiseesi.

 

Arvioi skaalalla yhdestä sataan tämän kurssin sisällön hallitsemistasi. Kirjoita arvo 1 jos olet sitä mieltä että et hallitse kurssin sisältöä lainkaan, arvo 50 jos olet sitä mieltä että hallitset noin puolet kurssin sisällöstä, ja arvo 100, jos olet sitä mieltä että hallitset tähänastisen kurssin sisällön täysin.

 

Kirjoita allaolevaan laatikkoon ne kurssin asiat, mitkä ovat olleet mielestäsi helpoimpia:

 

Kirjoita allaolevaan laatikkoon ne kurssin asiat, mitkä ovat olleet mielestäsi vaikeimpia:

 

Tällä hetkellä, kuinka monta pistettä (0-15) uskot saavasi kurssikokeesta:

Tällä hetkellä, kuinka monta pistettä (0-15) uskot saavasi konekokeesta:

MOOC-kurssin suorittamisesta

Kurssimme lähenee valitettavasti loppuaan. Tässä kohdassa on taas hyvä tutustua MOOC-kurssin suorittamiseen liittyviin mahdollisuuksiin. Kurssista on mahdollista saada esimerkiksi opintosuoritusmerkintä Helsingin yliopiston Avoimen yliopiston kautta maksutta.

Huom! Jos teet MOOCia väylänä yliopistoon, lue myös siihen liittyvä infosivu. Erityisesti, jos olet tehnyt vaaditun määrän tehtäviä annetussa aikataulussa, mutta et ole vielä saanut kutsua näyttökokeeseen, ota pikaisesti yhteyttä osoitteeseen mooc@cs.helsinki.fi.

60 Erilaisista ohjelmointiparadigmoista ja deklaratiivisesta ohjelmoinnista

Ohjelmointiparadigmalla tarkoitetaan ohjelmointikielen taustalla olevaa tapaa ajatella ja jäsentää ohjelman toiminta. Tällä kurssilla olemme keskittyneet lähinnä imperatiiviseen ohjelmointiin, missä koneelle kerrotaan askeleet, joita sen tulee ottaa, jotta haluttu tehtävä saadaan suoritettua. Konetta siis käsketään tekemään annettuja toimintoja.

Eräs imperatiivisen ohjelmoinnin osajoukko on proseduraalinen ohjelmointi, mitä harjoittelimme erityisesti kurssin alussa. Proseduraalisessa ohjelmoinnissa ohjelman tilaa pidetään yllä muuttujissa, ja mahdolliset metodit käsittelevät vain niille parametrina annettuja arvoja. Ohjelma suoritetaan askel askeleelta, ja koneelle kerrotaan sen määrittelemällä kielellä mitä pitäisi tapahtua. Esimerkiksi alla on kuvattu koneen ymmärtämällä kielellä muuttujien a ja b arvojen vaihtaminen.

int a = 10;
int b = 15;

// vaihdetaan muuttujien a ja b arvot
int c = b;
b = a;
a = c;

Kun olio-ohjelmointia verrataan proseduraaliseen ohjelmointiin, muutamat oleelliset erot tulevat ilmi. Olio-ohjelmoinnissa olion tila voi periaatteessa muuttua mitä tahansa olion metodia käytettäessä, ja tuo tilan muutos voi vaikuttaa myös muiden olion metodien toimintaan -- ja sitä kautta ohjelman suorituksen osa-alueisiin. Olemme käyttäneet olioita kurssilla lähinnä myös tietokonetta käskyttäen, mutta myös toisenlaisia tapoja on olemassa.

Deklaratiivinen ohjelmointi on ohjelmointiparadigma, missä pyritään kuvailemaan mitä ohjelman tulee tehdä sen sijaan, että kuvattaisiin yksittäisiä suoritettavia käskyjä. Esimerkiksi funktionaalisessa ohjelmoinnissa, joka voidaan nähdä deklaratiivisen ohjelmoinnin osajoukkona, ohjelmoija keskittyy lähinnä halutun tiedon tunnistamiseen, sekä tiedon muutamiseen haluttuun muotoon.

Koska ohjelmointikielet tarjoavat nykyään tyypillisesti välineitä sekä imperatiiviseen että deklaratiiviseen ohjelmointiin, tapahtuu ohjelmien rakentaminen usein moniparadigmaisesti, missä imperatiivista ja deklaratiivista ohjelmointityyliä sekoitetaan tarvittaessa. Myös Java tarjoaa välineitä sekä imperatiiviseen että deklaratiiviseen ohjelmointiin.

Tutustutaan hieman näihin Javan ominaisuuksiin seuraavaksi.

60.1 Listan läpikäynti

Tarkastellaan kahta erilaista tapaa tulostaa listalla olevat alkiot. Ensimmäisenä vuorossa imperatiivinen lähestymistapa, missä käytämme for-toistolausetta alkioiden läpikäyntiin sekä tuttua System.out.println-komentoa yksittäisten alkioiden tulostamiseen.

List<Integer> lista = new ArrayList<>();
Collections.addAll(lista, 1, 3, 5, 7);

for (int arvo: lista) {
    System.out.println(arvo);
}
1
3
5
7

Deklaratiivisessa ohjelmointityylissä listalle kerrotaan mitä sen jokaiselle alkiolle tulee tehdä. Alla listalle sanotaan että sen jokainen alkio tulee antaa tulostusmetodille.

List<Integer> lista = new ArrayList<>();
Collections.addAll(lista, 1, 3, 5, 7);

lista.forEach(System.out::println);
1
3
5
7

60.2 Metodiviite

Komento forEach antaa jokaisen listalla olevan alkion vuorollaan komennon parametrina olevalle metodille. Kuten huomaat, tulostuskomennossa on kaksoispisteet tulostusmetodin yhteydessä -- System.out::println -- tällä tavalla annetaan viittaus metodiin, jolle listan alkiot annetaan. Käytössä olevat metodit eivät ole rajattu Javan omiin metodeihin kuten tulostuskutsuun, vaan voimme yhtä hyvin käyttää myös itse ohjelmoimiamme metodeja.

public class Apumetodit {

    public static void kerroKahdellaJaTulosta(int luku) {
        System.out.println(luku * 2);        
    }
}

Listan läpikäynnin yhteydessä ylläolevaa metodia kutsuttaisiin seuraavanlaisesti:

List<Integer> lista = new ArrayList<>();
Collections.addAll(lista, 1, 3, 5, 7);

lista.forEach(Apumetodit::kerroKahdellaJaTulosta);
2
6
10
14

60.3 Anonyymit metodit (funktiot)

Kun tarkastelemme forEach-kutsua tarkemmin, voimme oikeastaan antaa sille myös tiedon alkioiden käsittelytavasta. Tämä tieto annetaan anonyymien metodien avulla. Anonyymit metodit määritellään muodossa alkio -> kasittely, esimerkiksi i -> System.out.println(i).

lista.forEach(i -> System.out.println(i));

Anonyymi metodi voi sisältää myös useampia komentoja, jolloin käytetään aaltosuluilla alkavaa ja loppuvaa lohkoa komentojen listaamiseen. Komennot suoritetaan järjestyksessä ylhäältä alas.

lista.forEach(i -> {
    if (i == 5) {
        System.out.print("Kapow ");
    }

    System.out.println(i);
});
1
3
Kapow 5
7

Edelläoleva anonyymi metodi määsittelee annetulle alkiolle suoritettavan koodin sekä metodin parametrin. Se vastaa kutakuinkin seuraavaa staattista metodia.

public static void tulosta(int luku) {
    if (i == 5) {
        System.out.print("Kapow ");
    }

    System.out.println(i);
}

60.4 Syötevirrat

Kutsun lista.forEach yhteydessä oikeastaan luodaan virta syötteitä (Stream), jolle kaikki listalla olevat alkiot syötetään, ja joka ohjaa alkiot eteenpäin. Kutsu näyttää käytännössä seuraavalta:

lista.stream().forEach(System.out::println);

Tämä "stream" tarjoaa joukon metodeja, joiden avulla käsiteltävän listan alkioita voidaan käsitellä muokata ennen (esimerkiksi) tulostusta.

Käsiteltävien alkioiden rajaus (Filter)

Stream tarjoaa esimerkiksi filter-metodin, jonka avulla voidaan rajata käsiteltävät alkiot. Alla rajataan käsittely vain alkioihin, joiden arvon on yli 5.

lista.stream().filter(i -> i > 5).forEach(System.out::println);
7

Rajaus on tehty anonyymillä metodilla, jossa alkion arvoa verrataan lukuun 5. Ylläoleva anonyymi metodi vastaa seuraavaa metodia:

public static boolean onSuurempiKuinViisi(int arvo) {
    return i > 5;
}

Alkioiden muuntaminen toiseen muotoon (Map)

Syötevirran erilaisilla map-metodeilla alkioita voidaan muuntaa toiseen muotoon. Esimerkiksi aiemmin tekemämme kahdella kertominen onnistuu map-metodin avulla.

lista.stream().filter(i -> i > 5).map(i -> i * 2).forEach(System.out::println);
14

Map-metodi voi sisältää myös lohkon, mutta, tällöin sille tulee erikseen määritellä return-komento.

lista.stream().map(x -> {
    if (x == 5) {
        return "Kapow " + 5;
    }
    
    return x;
}).forEach(System.out::println);

Tämä komento erityisen kätevä esimerkiksi olioita läpikäytäessä. Metodin map avulla voidaan myös valita metodin palauttama arvo. Esimerkiksi Henkilöiden nimet saisi seuraavalla tavalla -- olettaen, että käytössämme on Henkilo-luokka, ja luokalla metodi getNimi.

List<Henkilo> lista = new ArrayList<>();
// luetaan listalle henkilot

lista.stream().map(h -> h.getNimi()).forEach(System.out::println);

Alkioiden muuntaminen toisen tyyppiseksi

Syötevirrat tarjoavat myös metodeja alkioiden muuntamiseksi tiettyyn tyyppiin. Esimerkiksi metodilla mapToInt tehdään muunnos lukuvirraksi (IntStream), jonka jälkeen pääsemme käsiksi lukuja sisältävän syötevirran tarjoamiin metodeihin, kuten keskiarvon laskemiseen.

Allaoleva lähdekoodi laskee kaikkien listalla olevien positiivisten alkioiden keskiarvon ja tulostaa sen.

List<Integer> lista = new ArrayList<>();
Collections.addAll(lista, 1, 3, 5, 7);

lista.stream().filter(i -> i >= 0).mapToInt(i -> i).average().ifPresent(System.out::println);
3.5

IntStream-lukuvirran metodi average palauttaa OptionalDouble-tyyppisen alkion, joka tarjoaa metodin ifPresent, jonka avulla kerrotaan mitä tehdään jos keskiarvon laskeminen onnistuu. Tässä tapauksessa keskiarvo annetaan tulostusmetodille.

Rajattujen tai käsiteltyjen alkioiden kerääminen

Syötevirrassa käsiteltäviä alkioita voi myös kerätä collect-metodin avulla. Alla kerätään syötevirrasta alkiot, joiden arvon on yli 5.

List<Integer> luvut = lista.stream().filter(i -> i > 5).collect(Collectors.toList());

 

Oracle tarjoaa lisää oppaita tähän ohjelmointityyliin liittyen, hyvä lähtökohta lienee Lambda QuickStart.

61 Kertausta

Kurssin viimeinen viikko koostuu edellä olevan pikakatsauksen lisäksi kurssilla nähtyjen teemojen kertauksesta. Osa tehtävistä on jo tuttuja, osa uusia. Kaikista tehtävistä on tehty sellaisia, että että niissä ei ole testejä -- olet täysin vastuussa ohjelman toiminnasta -- voit kokeilla edellä näkemiäsi menetelmiä, tai kerrata aiemmin tutuksi tulleita käsitteitä. Palauttamalla tehtävän takaat että se toimii toivotusti, jolloin saat siitä myös pisteet. Kertaa tehtäviä tehdessäsi materiaalia -- kannattaa varata tehtäville myös ajatteluaikaa.

Tehtävä 208: Sademäärät

Huom! Vaikka olisit tehnyt tehtävän jo aiemmin, tee se silti uudestaan. Tee tehtävä nykyisen tietämyksesi perusteella, äläkä katso mahdollista aiempaa vastaustasi.

Tässä ohjelmassa harjoitellaan toistolauseiden, lukujen käyttöä sekä käyttäjän antaman syötteen lukemista. Tehtäväpohjassa ei ole automaattisia testejä, joten testeistä ei ole apua ohjelman rakentamisessa. Tehtävä on kolmen tehtäväpisteen arvoinen.

Toteuta ohjelma sademäärien keskiarvon laskemiseen

Ohjelman tulee lukea käyttäjän antamasta syötteestä sademääriä kunnes käyttäjä syöttää luvun 999999. Sademääriksi kelpaavat nollat ja positiiviset luvut. Käyttäjän syöttämät negatiiviset luvut ohitetaan.

Kun käyttäjä syöttää luvun 999999, ohjelman ohjelman tulee tulostaa käyttäjän syöttämien sademäärien keskiarvo tai ilmoitus siitä, ettei keskiarvoa voida laskea (koska ei syötetty yhtään sademäärää).

Käytä Javan Scanner-luokkaa tai muuta sinulle tuttua tapaa käyttäjän syötteen lukemiseen. Voit olettaa, että syötteet ovat desimaalilukuja (double).

Sinun ei tarvitse huomioida mitenkään tapauksia, joissa käyttäjä antaa tyhjän syötteen tai syöttää luvuiksi kelpaamaattomia merkkejä.

Luku 999999 annetaan vain lopettamisen merkiksi, eikä sitä tule ottaa mukaan keskiarvoon.

Alla on annettu esimerkki siitä, miltä ohjelman käyttäminen voi näyttää. Käyttäjän antamat syötteet on merkitty punaisella värillä. Sinun EI ole pakko tuottaa pilkulleen samanlaista tulostetta, mutta ohjelman on laskettava oikea tulos syötteen perusteella tähän tapaan.

Anna sademääriä, lopeta luvulla 999999.
Anna sademäärä:
1000
Anna sademäärä:
2000.50
Anna sademäärä:
0
Anna sademäärä:
-100
Anna sademäärä:
999.50
Anna sademäärä:
999999
Sademäärien keskiarvo on 1000.0.

Tässä taas keskiarvoa ei saada määritettyä:

Anna sademääriä, lopeta luvulla 999999.
Anna sademäärä:
999999
Yhtään sademäärää ei syötetty.

Tehtävä 209: Lintubongarin tietokanta

Huom! Kuten edellisessä tehtässä; vaikka olisit tehnyt tehtävän jo aiemmin, tee se silti uudestaan. Tee tehtävä nykyisen tietämyksesi perusteella, äläkä katso mahdollista aiempaa vastaustasi.

Tehtävä vastaa kolmea yksiosaista tehtävää.

Tässä tehtävässä suunnittelet ja toteutat tietokannan lintubongareille. Tietokanta sisältää lintuja, joista jokaisella on nimi (merkkijono) ja latinankielinen nimi (merkkijono). Tämän lisäksi tietokanta laskee kunkin linnun havaintokertoja.

Ohjelmasi täytyy toteuttaa seuraavat komennot:

  • Lisaa - lisää linnun (huom: komennon nimessä ei ä-kirjainta!)
  • Havainto - lisää havainnon
  • Tilasto - tulostaa kaikki linnut
  • Nayta - tulostaa yhden linnun (huom: komennon nimessä ei ä-kirjainta!)
  • Lopeta - lopettaa ohjelman

Lisäksi virheelliset syötteet pitää käsitellä. (Ks. Simo alla). Tässä vielä esimerkki ohjelman toiminnasta:

? Lisaa
Nimi: Korppi
Latinankielinen nimi: Corvus Corvus
? Lisaa
Nimi: Haukka
Latinankielinen nimi: Dorkus Dorkus
? Havainto
Mikä havaittu? Haukka
? Havainto
Mikä havaittu? Simo
Ei ole lintu!
? Havainto
Mikä havaittu? Haukka
? Tilasto
Haukka (Dorkus Dorkus): 2 havaintoa
Korppi (Corvus Corvus): 0 havaintoa
? Nayta
Mikä? Haukka
Haukka (Dorkus Dorkus): 2 havaintoa
? Lopeta

Huom! Ohjelmasi rakenne on täysin vapaa. Testaamme vain että Paaohjelma luokan main-metodi toimii kuten tässä on kuvailtu. Yritä miettiä millaisista luokista ja olioista olisi hyötyä ohjelman toteuttamisessa!

Tehtävä 210: Pomo ja koodarit

Tässä tehtaväsarjassa hahmotellaan pomon ja siihen liittyvien alaisten tallentamista. Vaikka tehtäväsarjassa on tarkemmat ohjeet tehtävän tekemiseen, toimivat testit kuten edellisissä tapauksissa -- niitä ei ole. Tehtävä on yhteensä viiden tehtäväpisteen arvoinen.

210.1 Rajapinta tai abstrakti luokka työntekijä

Tee rajapinta tai abstrakti luokka Tyontekija, joka vaatii seuraavien metodien olemassaolon:

  • public String haeNimi()
    Metodi palauttaa työntekijän nimen.
  • public int haePalkka()
    Metodi palauttaa työntekijän palkan.
  • public int laskeAlaiset()
    Metodi palauttaa, kuinka monta alaista työntekijällä on.
  • public void lisaaKieli(String kieli)
    Metodi lisää ohjelmointikielen työntekijän hallitsemiin kieliin.
  • public boolean onkoTaitoa(String kieli)
    Metodi palauttaa arvon true, jos työntekijä tai työntekijän alainen hallitsee annettua ohjelmointikieltä, ja muuten arvon false.

210.2 Koodari

Tee luokka Koodari, joka toteuttaa rajapinnan Tyontekija. Luokan konstruktorissa annetaan nimi ja palkka. Koodarin alaisten määrä on aina 0.

Testaa koodarin toimintaa ainakin seuraavalla koodilla:

Koodari aapeli = new Koodari("Aapeli", 1000);
System.out.println(aapeli.haeNimi());
System.out.println(aapeli.haePalkka());
System.out.println(aapeli.laskeAlaiset());
aapeli.lisaaKieli("Java");
aapeli.lisaaKieli("Python");
System.out.println(aapeli.onkoTaitoa("Cobol"));
System.out.println(aapeli.onkoTaitoa("Java"));
System.out.println(aapeli.onkoTaitoa("Python"));

Koodin tulostuksen tulisi olla seuraava:

Aapeli
1000
0
false
true
true

210.3 Pomo

Tee luokka Pomo, joka toteuttaa rajapinnan Tyontekija. Lisää luokkaan vielä seuraava metodi:

  • public void lisaaAlainen(Tyontekija alainen)
    Metodi lisää pomolle uuden alaisen.

Testaa pomon toimintaa ainakin seuraavalla koodilla:

Koodari aapeli = new Koodari("Aapeli", 1000);
Pomo maija = new Pomo("Maija", 2000);
maija.lisaaAlainen(aapeli);
System.out.println(maija.haeNimi());
System.out.println(maija.haePalkka());

Koodin tulostuksen tulisi olla seuraava:

Maija
2000

210.4 Pomon alaiset

Muuta luokan Pomo metodi laskeAlaiset toimivaksi. Sen tulee laskea pomon alaisten, alaisten alaisten jne. määrät.

Testaa luokan toteutusta ainakin seuraavalla koodilla:

Koodari jenna = new Koodari("Jenna", 1000);
Koodari kalle = new Koodari("Kalle", 1000);
Koodari pauli = new Koodari("Pauli", 1000);
Koodari arto = new Koodari("Arto", 1000);
Koodari matti = new Koodari("Matti", 1000);

Pomo jarmo = new Pomo("Jarmo", 2000);
jarmo.lisaaAlainen(jenna);
jarmo.lisaaAlainen(kalle);
jarmo.lisaaAlainen(pauli);

Pomo pekka = new Pomo("Pekka", 2000);
pekka.lisaaAlainen(arto);
pekka.lisaaAlainen(matti);

Pomo maija = new Pomo("Maija", 4000);
maija.lisaaAlainen(jarmo);
maija.lisaaAlainen(pekka);

System.out.println(kalle.laskeAlaiset());
System.out.println(jarmo.laskeAlaiset());
System.out.println(pekka.laskeAlaiset());
System.out.println(maija.laskeAlaiset());

Koodi vastaa seuraavaa tilannetta:

 
             Maija
            /     \
      Jarmo         Pekka
     /  |  \         / \
Jenna Kalle Pauli Arto Matti

Koodin tulostuksen tulisi olla seuraava:

0
3
2
7

210.5 Ohjelmointikielet

Muuta luokan Pomo metodi onkoTaitoa toimivaksi. Sen tulee palauttaa true, jos pomo itse tai joku pomon alaisista, alaisten alaisista jne. hallitsee annettua ohjelmointikieltä.

Testaa toteutustasi seuraavalla koodilla:

Koodari jenna = new Koodari("Jenna", 1000);
Koodari kalle = new Koodari("Kalle", 1000);
Koodari pauli = new Koodari("Pauli", 1000);
Koodari arto = new Koodari("Arto", 1000);
Koodari matti = new Koodari("Matti", 1000);

Pomo jarmo = new Pomo("Jarmo", 2000);
jarmo.lisaaAlainen(jenna);
jarmo.lisaaAlainen(kalle);
jarmo.lisaaAlainen(pauli);

Pomo pekka = new Pomo("Pekka", 2000);
pekka.lisaaAlainen(arto);
pekka.lisaaAlainen(matti);

Pomo maija = new Pomo("Maija", 4000);
maija.lisaaAlainen(jarmo);
maija.lisaaAlainen(pekka);

jenna.lisaaKieli("Fortran");
kalle.lisaaKieli("Prolog");
kalle.lisaaKieli("C");
pauli.lisaaKieli("Haskell");
arto.lisaaKieli("Java");
matti.lisaaKieli("Java");
jarmo.lisaaKieli("Ruby");
pekka.lisaaKieli("C++");
maija.lisaaKieli("Cobol");

System.out.println(maija.onkoTaitoa("C"));
System.out.println(maija.onkoTaitoa("Cobol"));
System.out.println(maija.onkoTaitoa("Python"));
System.out.println(maija.onkoTaitoa("Java"));

Koodin tulostuksen tulisi olla seuraava:

true
true
false
true

Tehtävä 211: Sanatutkimus

Tehtäväpohjassa tulevassa tiedostossa sanalista.txt on Kotimaisten kielten keskuksen julkaisema nykysuomen sanalista, joka sisältää yli 90000 suomen kielen sanaa. Tässä tehtäväsarjassa tutkitaan listassa olevia sanoja ohjelman avulla.

Palauta tehtävä kun olet saanut kaikki osat valmiiksi. Tehtävä on yhteensä yhdeksän tehtäväpisteen arvoinen.

Tehtävissä voi ilmetä merkistöongelmia testejä suorittaessa. Tällöin tulee Scanneria luotaessa määrittää merkistöksi "UTF-8" (esim. Scanner lukija = new Scanner(new File("tiedosto"), "UTF-8")).

211.1 Tiedoston lukeminen

Tee luokka Sanatutkimus, joka sisältää listan sanoja. ArrayList sopii hyvin tietorakenteeksi. Lisää luokkaan seuraavat metodit:

  • public Sanatutkimus(String tiedostonimi)
    Konstruktori saa parametrina nimen tiedostoon, joka sisältää aineiston sanat. Jokaisella tiedoston rivillä on yksi sana. Sanat kannattanee lukea tiedostosta listaan konstruktorissa.
  • public int sanojenMaara()
    Metodi palauttaa aineiston sanojen määrän.
  • public boolean onkoSanaa(String sana)
    Metodi palauttaa true, jos sana on listassa, ja muuten false.

Testaa luokkaasi seuraavalla koodilla:

Sanatutkimus tutkimus = new Sanatutkimus("sanalista.txt");
System.out.println(tutkimus.sanojenMaara());
System.out.println(tutkimus.onkoSanaa("porkkana"));
System.out.println(tutkimus.onkoSanaa("porkana"));
91591
true
false

211.2 Sanojen pituudet

Lisää luokkaan Sanatutkimus seuraava metodi:

  • public int laskeSanat(int pituus)
    Metodi palauttaa annetun pituisten sanojen yhteismäärän aineistossa.

Seuraava koodi testaa luokkaasi:

Sanatutkimus tutkimus = new Sanatutkimus("sanalista.txt");
System.out.println(tutkimus.laskeSanat(8));
System.out.println(tutkimus.laskeSanat(15));

Koodin tulostuksen tulisi olla seuraava:

8412
4411

211.3 Pituustilasto

Lisää luokkaan Sanatutkimus seuraava metodi:

  • public void pituustilasto()
    Metodi tulostaa esimerkin mukaisesti tilaston eri pituisten sanojen määristä.

Seuraava koodi testaa luokkaasi:

Sanatutkimus tutkimus = new Sanatutkimus("sanalista.txt");
tutkimus.pituustilasto();

Koodin tulostuksen tulisi olla seuraava:

1 0
2 25
3 191
....
28 4
29 1
30 1

211.4 Kirjainmäärät

Lisää luokkaan Sanatutkimus seuraava metodi:

  • public int laskeKirjaimet(char kirjain)
    Metodi palauttaa, kuinka monta kertaa annettu kirjain esiintyy yhteensä aineiston sanoissa.

Seuraava koodi testaa luokkaasi:

Sanatutkimus tutkimus = new Sanatutkimus("sanalista.txt");
System.out.println(tutkimus.laskeKirjaimet('a'));
System.out.println(tutkimus.laskeKirjaimet('h'));

Koodin tulostuksen tulisi olla seuraava:

112291
21396

211.5 Kirjaintilasto

Lisää luokkaan Sanatutkimus seuraava metodi:

  • public void kirjaintilasto()
    Metodi tulostaa esimerkin mukaisesti tilaston kirjainmääristä, kun kirjaimet ovat abcdefghijklmnopqrstuvwxyzåäö.

Seuraava koodi testaa luokkaasi:

Sanatutkimus tutkimus = new Sanatutkimus("sanalista.txt");
tutkimus.kirjaintilasto();

Koodin tulostuksen tulisi olla seuraava:

a 112291
b 1496
c 213
...
å 1
ä 31475
ö 7250

211.6 Sanan pituudella haku

Lisää luokkaan Sanatutkimus seuraava metodi:

  • public ArrayList<String> haePituudella(int pituus)
    Metodi palauttaa listan sanoista, joiden pituus on parametrina annettu pituus.

Seuraava koodi testaa luokkaasi:

Sanatutkimus tutkimus = new Sanatutkimus("sanalista.txt");
System.out.println(tutkimus.haePituudella(28));

Koodin tulostuksen tulisi olla seuraava:

[muotokuvanpaljastustilaisuus, sotasyyllisyysoikeudenkäynti, tietojenkäsittelyjärjestelmä, ylioppilastutkintolautakunta]

211.7 Sanan osalla haku

Lisää luokkaan Sanatutkimus seuraava metodi:

  • public ArrayList<String> haeOsalla(String osa)
    Metodi palauttaa listan sanoista, joiden osana on parametrina annettu merkkijono.

Seuraava koodi testaa luokkaasi:

Sanatutkimus tutkimus = new Sanatutkimus("sanalista.txt");
System.out.println(tutkimus.haeOsalla("koodi"));

Koodin tulostuksen tulisi olla seuraava:

[juovakoodi, konekoodinen, koodi, koodijärjestelmä, koodinlukija, koodinumero, koodisanoma, koodittaa, koodittaja, kooditus, lyhytvalintakoodi, tavarakoodi, viivakoodi]

211.8 Palindromit

Lisää luokkaan Sanatutkimus seuraava metodi:

  • public ArrayList<String> haePalindromit()
    Metodi palauttaa listan sanoista, jotka ovat palindromeja. Palindromi tarkoittaa, että sana on sama alusta loppuun ja lopusta alkuun luettuna.

Seuraava koodi testaa luokkaasi:

Sanatutkimus tutkimus = new Sanatutkimus("sanalista.txt");
System.out.println(tutkimus.haePalindromit());

Koodin tulostuksen tulisi olla seuraava:

[ajaja, akka, ala, alla, autioitua, ele, enne, hah, heh, huh, hyh, häh, imaami, isi, niin, oho, olo, opo, otto, piip, pop, sadas, sammas, sees, siis, sus, suuruus, sylys, sytytys, syys, syöppöys, tuut, tyyt, tööt, utu, yty, älä, ämmä, ässä]

211.9 Ristikkoapuri

Lisää luokkaan Sanatutkimus seuraava metodi:

  • public ArrayList<String> haeRistikkoon(String pohja)
    Metodi palauttaa listan sanoista, jotka täsmäävät annettuun pohjaan. Pohjassa kirjaimet tarkoittavat sanan kirjaimia ja merkki ? tarkoittaa mitä tahansa kirjainta.

Ideana on, että ristikon ratkaisija voi hyödyntää metodia, kun osassa ruuduista on kirjain mutta joistakin ruuduista puuttuu vielä.

Seuraava koodi testaa luokkaasi:

Sanatutkimus tutkimus = new Sanatutkimus("sanalista.txt");
System.out.println(tutkimus.haeRistikkoon("s???is??s"));

Koodin tulostuksen tulisi olla seuraava:

[saalistus, salaisuus, sateisuus, satoisuus, sekaisuus, sijaisuus, siloisuus, sisäistys, sopuisuus, sotaisuus, suloisuus, suoristus, syntisyys, säröisyys, sävyisyys]

Tehtävä 212: Tikkupeli

Tehtävänanto on mukaelma osoitteessa http://nifty.stanford.edu/2014/laaksonen-vihavainen-game-of-sticks/handout.html olevasta tehtävästä.

Tässä tehtävässä toteutetaan peli, jossa pelaajat nostavat vuorotellen tikkuja pinosta. Viimeisen tikun nostaja häviää pelin. Kun tämä toiminnallisuus on valmis, toteutetaan tekoäly, joka oppii pelistä.

Tehtävä on yhteensä kahdeksan tehtäväpisteen arvoinen.

Kuvaus

Tikkupelissä kaksi pelaajaa ovat pöydän äärellä. Pöydällä on kasa tikkuja, ja kumpikin pelaaja ottaa vuorollaan kasasta yhdestä kolmeen tikkua. Se, joka ottaa viimeisen tikun, häviää pelin.

Allaoleva on esimerkki pelistä.

  • Pöydällä on aluksi 20 tikkua.
  • Aapeli ottaa 3 tikkua, jolloin tikkuja on 17.
  • Maija ottaa 2 tikkua, jolloin tikkuja on 15.
  • Aapeli ottaa 1 tikun, jolloin tikkuja on 14.
  • Maija ottaa 3 tikkua, jolloin tikkuja on 11.
  • Aapeli ottaa 2 tikkua, jolloin tikkuja on 9.
  • Maija ottaa 2 tikkua, jolloin tikkuja on 7.
  • Aapeli ottaa 3 tikkua, jolloin tikkuja on 4.
  • Maija ottaa 1 tikun, jolloin tikkuja on 3.
  • Aapeli ottaa 2 tikkua, jolloin tikkuja on 1.
  • Maija joutuu ottamaan viimeisen tikun ja häviää.

Tehtävä kannattaa tehdä useammassa pienemmässä osassa:

  1. Kaksinpelin toteuttaminen.
  2. "Tyhmän" tekoälyn, jota vastaan voi pelata, toteuttaminen.
  3. Oppivan tekoälyn toteuttaminen.

212.1 Kaksinpelin toteuttaminen

Toteuta peli, missä kaksi pelaajaa voivat pelata tikkupeliä. Allaolevat esimerkit antavat kuvan siitä, miten pelin tulee toimia.

Esimerkki 1

Tervetuloa tikkupeliin!
Kuinka monta tikkua pöydällä on aluksi (10-100)? 10

Pöydällä on 10 tikkua.
Pelaaja 1: Kuinka monta tikkua nostat (1-3)? 3

Pöydällä on 7 tikkua.
Pelaaja 2: Kuinka monta tikkua nostat (1-3)? 3

Pöydällä on 4 tikkua.
Pelaaja 1: Kuinka monta tikkua nostat (1-3)? 3

Pöydällä on 1 tikku. 
Pelaaja 2: Kuinka monta tikkua nostat (1-3)? 1
Pelaaja 2, hävisit :/

Esimerkki 2

Tervetuloa tikkupeliin!
Kuinka monta tikkua pöydällä on aluksi (10-100)? 500
Valitse luku väliltä 10-100
Kuinka monta tikkua pöydällä on aluksi (10-100)? 3
Valitse luku väliltä 10-100
Kuinka monta tikkua pöydällä on aluksi (10-100)? 50

Pöydällä on 50 tikkua.
Pelaaja 1: Kuinka monta tikkua nostat (1-3)? 3

Pöydällä on 47 tikkua.
Pelaaja 2: Kuinka monta tikkua nostat (1-3)? 55
Valitse luku väliltä 1-3
Pelaaja 2: Kuinka monta tikkua nostat (1-3)? -2
Valitse luku väliltä 1-3
Pelaaja 2: Kuinka monta tikkua nostat (1-3)? 3

Pöydällä on 44 tikkua.
Pelaaja 1: Kuinka monta tikkua nostat (1-3)? 3

Pöydällä on 41 tikkua.
Pelaaja 2: Kuinka monta tikkua nostat (1-3)? 1

Pöydällä on 40 tikkua.
...

Pöydällä on 2 tikkua.
Pelaaja 2: Kuinka monta tikkua nostat (1-3)? 1

Pöydällä on 1 tikku. 
Pelaaja 1: Kuinka monta tikkua nostat (1-3)? 1
Pelaaja 1, hävisit :/

Toteuta yllä kuvattu peli. Pohdi jo tässä vaiheessa pelaajan toiminnallisuutta ja sitä, että miten pelaajan voisi vaihtaa tekoälyyn.

212.2 Tekoälyn toteuttaminen

Kavereita vastaan pelaaminen on varsin jees, mutta tietojenkäsittelytieteen kurssilla on pakko fiilistellä :). Aivan kuten opiskellessa oppii siistejä asioita, myös tietokoneet voivat oppia siistejä asioita. Luodaan tekoäly tikkupelille.

Yksi tapa tekoälyn tekemiseen olisi tehdä matemaattinen analyysi ongelmasta, ja luoda tekoäly analyysin pohjalta. Tehdään kuitenkin toisin, ja luodaan tekoäly joka osaa oppia pelistä sitä pelaamalla.

  • Tekoälyllä on joukko hattuja, yksi jokaiselle pöydällä olevien tikkujen lukumäärälle. Pelin alkutilassa jokaisessa hatussa on kolme palloa; pallo, jossa on numero 1, pallo, jossa on numero 2, ja pallo, jossa on numero 3.
  • Aina kun on tekoälyn vuoro pelata, se katsoo pöydällä olevien tikkujen lukumäärän ja valitsee lukumäärää vastaavan hatun. Tekoäly ottaa satunnaisen pallon kyseisestä hatusta. Kun tekoäly nostaa pallon, se katsoo pallossa olevan numeron, ottaa numeron kertoman määrän tikkuja pöydältä, ja asettaa pallon hatun viereen odottamaan.
  • Jos tekoäly voittaa pelin, se asettaa jokaiseen hattuun kaksi kappaletta hatun vieressä olevaa palloa. Jos tekoäly häviää, se heittää pallon pois -- olettaen kuitenkin että kyseisiä palloja jää kuitenkin vähintään yksi hattuun.
  • Kun tekoäly pelaa useamman pelin, edellistä toistaen se hiljalleen lisää voittavia palloja (eli valintoja) hattuihin -- tämä taas tarkoittaa sitä, että se nostaa paremmalla todennäköisyydellä hyvän pallon (ja tekee hyvän valinnan).

Esimerkki

Alla olevassa esimerkissä on 10 tikkua pelin alussa. Hattujen sisällöt tekoälylle ovat seuraavat:

hattu 1 2 3 4 5 6 7 8 9 10
pallot 1,2,3 1,2,3 1,2,3 1,2,3 1,2,3 1,2,3 1,2,3 1,2,3 1,2,3 1,2,3

Peli voi edetä esimerkiksi seuraavasti:

  1. Pelaaja valitsee 3 tikkua, 7 tikkua jäljellä.
  2. Tekoäly valitsee satunnaisen pallon hatusta numero 7. Palloksi tulee 2. Tekoäly valitsee pöydältä 2 tikkua, ja asettaa pallon hatun viereen; pöydällä on 5 tikkua jäljellä.
  3. Pelaaja valitsee yhden tikun, 4 tikkua jäljellä.
  4. Tekoäly valitsee satunnaisen pallon hatusta numero 4. Palloksi tulee 3. Tekoäly valitsee pöydältä 3 tikkua, ja asettaa pallon hatun viereen; pöydällä on 1 tikku jäljellä.
  5. Pelaajan täytyy ottaa viimeinen tikku, jolloin pelaaja häviää.

Pelin jälkeen tekoälyn tilanne on seuraava:

hattu 1 2 3 4 5 6 7 8 9 10
sisältö 1,2,3 1,2,3 1,2,3 1,2 1,2,3 1,2,3 1,3 1,2,3 1,2,3 1,2,3
hattujen vieressä 3 2

Koska tekoäly voittaa pelin, se asettaa kaksi kappaletta vieressä olevia palloja takaisin hattuihin. Pelitilanne on tämän jälkeen seuraava:

hattu 1 2 3 4 5 6 7 8 9 10
sisältö 1,2,3 1,2,3 1,2,3 1,2,3,3 1,2,3 1,2,3 1,2,2,3 1,2,3 1,2,3 1,2,3

Nyt tekoäly ottaisi todennäköisemmin kolme tikkua joa pöydällä on 4 tikkua, ja kaksi tikkua jos pöydällä on 7 tikkua.

Toteuta yllä kuvattu tekoäly ja muokkaa peliä siten, että pelaaja voi valita pelaako se tekoälyä vai normaalia pelaajaa vastaan.

Alla oleva esimerkki näyttää miltä pelin pitäisi näyttää kun olet saanut tämän osan valmiiksi.

Tervetuloa tikkupeliin!
Kuinka monta tikkua pöydällä on aluksi (10-100)? 10
Vaihtoehdot:
 Pelaa kaveria vastaan (1)
 Pelaa tietokonetta vastaan (2)
Minkä vaihtoehdon valitset (1-2)? 2

Pöydällä on 10 tikkua.
Pelaaja 1: Kuinka monta tikkua nostat (1-3)? 3

Pöydällä on 7 tikkua.
Tekoäly valitsee 2

Pöydällä on 5 tikkua.
Pelaaja 1: Kuinka monta tikkua nostat (1-3)? 3

Pöydällä on 2 tikkua.
Tekoäly valitsee 2
Tekoäly häviää

Pelaa uudestaan (1 = kyllä, 0 = ei)? 1

Pöydällä on 10 tikkua.
Pelaaja 1: Kuinka monta tikkua nostat (1-3)? 3

Pöydällä on 7 tikkua.
Tekoäly valitsee 1

Pöydällä on 6 tikkua.
Pelaaja 1: Kuinka monta tikkua nostat (1-3)? 1

Pöydällä on 5 tikkua.
Tekoäly valitsee 3

Pöydällä on 2 tikkua.
Pelaaja 1: Kuinka monta tikkua nostat (1-3)? 1

Pöydällä on 1 tikku.
Tekoäly valitsee 2
Tekoäly häviää

Pelaa uudestaan (1 = kyllä, 0 = ei)? 0
Kiitos!

212.3 Tekoäly vastaan tekoäly

Teit edellisessä osassa tekoälyn, joka oppii pelatessaan. Sitä vastaan pelatessa huomataan kuitenkin, että oppiminen vaatii paljon työtä, ja tekoäly joutuu tekemään huomattavasti toistoja ennenkuin se pärjää. Tässä osassa muokkaat ohjelmaa siten, että pelaaja voi päättää pelaako se tekoälyä vastaan joka ei ole harjoitellut, vai kouliintunutta tekoälyä vastaan.

Jotta tekoälyä voisi koulia, joudut toteuttamaan ohjelman, missä tekoäly ensin pelaa toista tekoälyä vastaan. Tämän jälkeen tekoäly pääsee pelaamaan pelaajaa vastaan. Tekoälyn harjoittelu vaatii hetken -- ehkä noin satatuhatta peliä -- kannattanee kokeilla erilaisia harjoitusjaksojen pituuksia.

Allaoleva esimerkki näyttää miten peli toimii kun tekoäly voi harjoitella myös toista tekoälyä vastaan.

Tervetuloa tikkupeliin!
Kuinka monta tikkua pöydällä on aluksi (10-100)? 10
Vaihtoehdot:
 Pelaa kaveria vastaan (1)
 Pelaa tietokonetta vastaan (2)
 Pelaa kouliintunutta tietokonetta vastaan (2)
Minkä vaihtoehdon valitset (1-3)? 3

Treenataan...

Pöydällä on 10 tikkua.
Pelaaja 1: Kuinka monta tikkua nostat (1-3)? 3

Pöydällä on 7 tikkua.
Tekoäly valitsee 3

Pöydällä on 4 tikkua.
Pelaaja 1: Kuinka monta tikkua nostat (1-3)? 2

Pöydällä on 2 tikkua.
Tekoäly valitsee 1

Pöydällä on 1 tikku.
Pelaaja 1: Kuinka monta tikkua nostat (1-3)? 1
Pelaaja 1, hävisit :/

Pelaa uudestaan (1 = kyllä, 0 = ei)? 1

Pöydällä on 10 tikkua.
Pelaaja 1: Kuinka monta tikkua nostat (1-3)? 2

Pöydällä on 8 tikkua.
Tekoäly valitsee 1

Pöydällä on 7 tikkua.
Pelaaja 1: Kuinka monta tikkua nostat (1-3)? 2

Pöydällä on 5 tikkua.
Tekoäly valitsee 1

Pöydällä on 4 tikkua.
Pelaaja 1: Kuinka monta tikkua nostat (1-3)? 1

Pöydällä on 3 tikkua.
Tekoäly valitsee 2

Pöydällä on 1 tikku.
Pelaaja 1: Kuinka monta tikkua nostat (1-3)? 1
Pelaaja 1, hävisit :/

Pelaa uudestaan (1 = kyllä, 0 = ei)? 0
Kiitos!

Kun olet saanut ohjelman toimimaan, haasta kaverisi pelaamaan tekoälyn vastaan! :) -- eräs mallivastaus tehtävään julkaistaan vasta kurssin jälkeen..

Viikon 14 Loppukysely

Viikon 14 Loppukysely

 

Alla on esitetty viikkoon liittyviä väittämiä. Jos olet täysin eri mieltä väittämän kanssa, valitse 1. Jos olet täysin samaa mieltä väittämän kanssa, valitse 7. Muuten, valitse luku väliltä.

Täysin eri mieltä.
1
2
3
4
5
6
7
Täysin samaa mieltä.

 

1. Viikko oli työläs.
2. Viikko oli opettavainen.
3. Viikko oli turhauttava.
4. Viikko oli mukava.
5. Viikko oli vaikea.

 

62 Kurssipalaute

Tehtävä 213: Kurssipalaute

Olemme saaneet paljon arvokasta palautetta TMC:n kautta. Näin kurssin viimeisenä kysymyksenä haluaisimme koko kurssin sisältöä koskevan palautteen. Anna palaute täyttämällä täältä löytyvä lomake. Palaute on anonyymi.

Jotta saat merkatuksi tämän tehtävän, aja tehtävän TMC-testit ja lähetä tehtävä palvelimelle.

Vaikka olemme saaneet paljon arvokasta palautetta TMC:n kautta yksittäisistä tehtävistä, palauttaessasi tätä, kirjoitathan kommenttikenttään palautteen koko MOOC-kurssista. Mainitsethan siinä, mikäli et halua palautettasi julkaistavan anonyymisti sivustoillamme. Vain osa palautteesta tullaan julkaisemaan.