Kertaustehtäviä osiin 8-14 liittyen
Tälle sivulla on kerättynä kertaustehtäviä materiaalin osiin 8-14 liittyen. Kertaustehtävät saa ladattua TMC:stä. Tehtävät eivät missään nimessä kata kaikkea osien 8-14 sisällöstä, vaan ne toimivat lisäkertauksena kurssin aihepiiriin. Osa tehtävistä on materiaalista tuttuja.
Kertaustehtävät eivät ole "pakollisia", eikä niitä tarvitse tehdä esimerkiksi MOOCin kautta opiskelupaikkaa haettaessa.
Painoindeksi on mitta-arvo, jonka avulla voidaan arvioida ihmisen painon ja pituuden suhdetta. Painoindeksi lasketaan kaavalla:
Painoindeksi = paino / (pituus * pituus)
Painoindeksiä käytetään muunmuassa ali- ja ylipainon tunnistamisessa. Jos henkilön painoindeksi on alle 18.5 luokitellaan hänet alipainoiseksi ("alipaino"). Jos painoindeksi on vähintään 18.5 mutta alle 25, on luokittelu "normaali". Jos taas painoindeksi on vähintään 25 mutta alle 30, on luokittelu "ylipainoinen". Jos taas painoindeksi on vähintään 30, on luokittelu "merkittävästi ylipainoinen".
Luokissa Raportinluoja1
ja Raportinluoja2
on metodi public PainoindeksiRaportti painoindeksiRaportti(List<Henkilo> henkilotiedot)
, joka saa parametrina listan henkilöitä ja palauttaa painoindeksiraportin -- kannattaa tutustua luokkiin Painoindeksiraportti
ja Henkilo
.
Luo luokkiin Raportinluoja1
ja Raportinluoja2
erilaiset toteutukset metodille painoindeksiRaportti
painoindeksiraporttien luomiseen.
Tuotettavan painoindeksiraportin tulee sisältää lista nimistä (huom! ei henkilöistä) siten, että henkilöt ovat kategorisoitu heihin sopiviin painoindeksiluokkiin.
Testaa toteutustasi ennen sen palautusta. Tehtävässä ei ole automaattisia testejä.
Data-analytiikassa mittausten tasoittamisella tarkoitetaan liiallisen kohinan tai muiden häiriöiden poistamiseen datasta, jonka jälkeen oleellisten hahmojen tunnistamista datasta tulee mahdollisesti helpommaksi. Eräs suoraviivainen tekniikka mittausten tasoitukseen on muuttaa jokainen mittausarvo sen, sitä edeltävän mittausarvon ja sitä seuraavan mittausarvon mittausten keskiarvoksi. Jos oletamme, että poikkeukselliset arvot ovat häiriö mittadatassa, tämä keskiarvomenetelmä tasaa arvot potentiaalisesti luotettavimmiksi arvoiksi.
Tutkitaan esimerkiksi seuraavia sykemittauksia, jotka on kerätty henkilötietodatasta.
95 102 98 88 105
Jos ylläolevan mittausdatan tasaa keskiarvomenetelmällä, on tasauksen tuottama data seuraavanlainen:
95 98.33 96 97 105
Tässä:
- Arvo 102 muutettiin arvoon 98.33: (95 + 102 + 98) / 3
- Arvo 98 muutettiin arvoon 96: (102 + 98 + 88) / 3
- Arvo 88 muutettiin arvoon 97: (98 + 88 + 105) / 3
Luokissa MittaustenTasoittaja1
ja MittaustenTasoittaja2
on metodi public List<Double> tasoita(List<Henkilo> henkilotiedot)
, joka saa parametrina listan henkilö-olioita (henkilöiden nimillä ei ole väliä, oleellista on sykemittausdata -- muuttuja syke
) ja palauttaa listan tasattuja sykemittauksia -- luokka Henkilo
on tässä sama kuin edellisessä tehtävässä.
Luo luokkiin MittaustenTasoittaja1
ja MittaustenTasoittaja2
erilaiset toteutukset metodille tasoita
listana annettujen henkilo-olioihin tallennettujen sykemittausten tasoittamiseen. Toteutusten tulee siis käsitellä lista henkilötietueita, joista jokaisessa on sykemittaus, ja palauttaa lista double-arvoja, jotka ovat tasoitettuja sykemittauksia.
Testaa toteutustasi ennen sen palautusta. Tehtävässä ei ole automaattisia testejä.
Luokissa YleisimmatSanat1
ja YleisimmatSanat2
on metodi public List<String> yleisetSanat(List<String> sanat)
, joka saa parametrina listan merkkijonoja ja palauttaa listan merkkijonoja.
Luo luokkiin YleisimmatSanat1
ja YleisimmatSanat2
erilaiset toteutukset kolmen yleisimmän merkkijonon tunnistamiseen. Yleisimmät merkkijonot tulee tunnistaa metodille yleisetSanat
syötteeksi annetusta listasta, ja metodin tulee palauttaa yleisimmät merkkijonot listassa. Palauttava lista tulee olla järjestettynä siten, että listan ensimmäisenä alkiona on yleisin merkkijono, toisena alkiona on toiseksi yleisin merkkijono, ja kolmantena alkiona on kolmanneksi yleisin merkkijono.
Jos merkkijonot ovat yhtä yleisiä, aseta lyhin sana (vähiten merkkejä) ennen pidempää sanaa. Voit olettaa, että syötteen kolme yleisintä sanaa ovat eri pituisia. Voit lisäksi olettaa, että syötteessä on vähintään kolme eri sanaa.
Testaa toteutustasi ennen sen palautusta. Tehtävässä ei ole automaattisia testejä.
Geologit haluavat tarkastella paikallisen vuoren mahdollista maanjäristystoimintaa. He ovat asentaneet mittarin seismisen toiminnan (maan tärinän) mittaamiseen. Mittari lukee seismistä toimintaa tietyin aikavälein ja lähettää mitattua dataa mittausarvo kerrallaan tutkimuslaboratorion tietokoneelle.
Mittari lisää lisäksi mittausdataan päivämäärätietoja näyttämään seismisen toiminnan mittauspäivää. Mittarin lähettämä data on seuraavassa muodossa:
20151004 200 150 175 20151005 0.002 0.03 20151007 ...
Kahdeksanlukuiset arvot ovat päivämääriä (vuosi-kuukausi-päivä -muodossa) ja numerot nollan ja viidensadan välillä ovat värähtelyjen taajuuksia (hertzeinä). Ylläoleva esimerkki näyttää mittaukset 200, 150, ja 175 lokakuun neljäntenä päivänä vuonna 2015 ja mittaukset 0.002 ja 0.03 lokakuun viidentenä päivänä vuonna 2015. Lokakuun kuudennelta päivältä ei ole lainkaan mittausdataa (välillä verkkoyhteydessä on ongelmia, jolloin mittausdataa saattaa kadota).
Oleta, että mittausdata on järjestetty päivämäärien mukaan (myöhempi päivämäärä ei ikinä ilmesty datassa ennen aiempaa päivämäärää) ja että kaikki data on samalta vuodelta. Voit myös olettaa, että jokaiselta datassa olevalta päivältä on vähintään yksi mittausarvo.
Luokissa MittausRaportoija1
ja MittausRaportoija2
on tyhjä metodi List<SuurinTaajuusRaportti> paivittaisetMaksimit(List<Double> mittausData, int kuukausi)
, joka saa parametrina listan mittausdataa sekä kuukauden (oleta, että yksi (01) vastaa tammikuuta ja kaksitoista (12) vastaa joulukuuta). Metodin tulee tuottaa lista raportteja, joista jokainen sisältää suurimman mittaustuloksen kuukauden yksittäiselle päivälle, josta löytyy mittausdataa.
Suunnittele ja toteuta kaksi erilaista toteutusta metodille paivittaisetMaksimit
ja toteuta ne luokkiin MittausRaportoija1
ja MittausRaportoija2
. Metodin tulee siis käsitellä lista Double-muotoisia syötteitä, joista löytyy sekä päivämääriä että mittausarvoja. Metodin tulee käsitellä vain parametrina annettuun kuukauteen liittyviä arvoja, ja syötteiden perusteella tulee tunnistaa jokaiselle parametrina annetulle kuukauden päivälle suurin päiväkohtainen arvo. Suurimmat päiväkohtaiset arvot asetetaan palautettavaan listaan SuurinTaajuusRaportti
-muotoisina olioina, ja metodi palauttaa lopulta listan tulevaa käsittelyä varten.
Testaa toteutustasi ennen sen palautusta. Tehtävässä ei ole automaattisia testejä.
Kun olet tehnyt neljä edellistä tehtävää (tai ainakin yrittänyt tehdä kaikkia neljää tehtävää), vastaa osoitteessa http://goo.gl/forms/VZ2yyRNUVB olevaan kyselyyn. Tämän jälkeen voit jatkaa seuraavien kertaustehtävien parissa.
Tässä tehtävässä tehdään joukkueiden ja joukkueen pelaajien ylläpitoon tarkoitettuun ohjelmistoon tarvittavat ydinluokat.
Joukkue
Tee luokka Joukkue
, johon tallennetaan joukkueen nimi (String
). Tee luokkaan seuraavat metodit:
- konstruktori, jolle annetaan joukkueen nimi
-
getNimi
, joka palauttaa joukkueen nimen
Seuraava pääohjelma demonstroi luokan toimintaa:
Joukkue tapiiri = new Joukkue("FC Tapiiri");
System.out.println("Joukkue: " + tapiiri.haeNimi());
Ohjelman tulostus on seuraava:
Joukkue: FC Tapiiri
Pelaaja
Luo luokka Pelaaja
, johon tallennetaan pelaajan nimi ja tehtyjen maalien määrä. Tee luokkaan kaksi konstruktoria: yksi jolle annetaan vain pelaajan nimi, toinen jolle annetaan sekä pelaajan nimi että pelaajan tekemien maalien määrä. Lisää pelaajalle myös metodit:
-
getNimi
, joka palauttaa pelaajan nimen -
getMaalit
, joka palauttaa tehtyjen maalien määrän -
toString
, joka palauttaa pelaajan merkkijonoesityksen
Joukkue tapiiri = new Joukkue("FC Tapiiri");
System.out.println("Joukkue: " + tapiiri.getNimi());
Pelaaja matti = new Pelaaja("Matti");
System.out.println("Pelaaja: " + matti);
Pelaaja pekka = new Pelaaja("Pekka", 39);
System.out.println("Pelaaja: " + pekka);
Joukkue: FC Tapiiri Pelaaja: Matti, maaleja 0 Pelaaja: Pekka, maaleja 39
Pelaajat joukkueisiin
Lisää luokkaan Joukkue
seuraavat metodit:
-
lisaaPelaaja
, joka lisää pelaajan joukkueeseen -
tulostaPelaajat
, joka tulostaa joukkueessa olevat pelaajat
Tallenna joukkueessa olevat pelaajat Joukkue
-luokan sisäiseen ArrayList
-listaan.
Seuraava pääohjelma testaa luokan toimintaa:
Joukkue tapiiri = new Joukkue("FC Tapiiri");
Pelaaja matti = new Pelaaja("Matti");
Pelaaja pekka = new Pelaaja("Pekka", 39);
tapiiri.lisaaPelaaja(matti);
tapiiri.lisaaPelaaja(pekka);
tapiiri.lisaaPelaaja(new Pelaaja("Mikael", 1)); //vaikutus on sama kuin edellisillä
tapiiri.tulostaPelaajat();
Ohjelman tulostuksen tulisi olla seuraava:
Matti, maaleja 0 Pekka, maaleja 39 Mikael, maaleja 1
Joukkueen maksimikoko ja nykyinen koko
Lisää luokkaan Joukkue
seuraavat metodit:
-
setMaksimikoko(int maksimikoko)
, joka asettaa joukkueen maksimikoon (eli maksimimäärän pelaajia) -
getPelaajienLukumaara
, joka palauttaa pelaajien määrän (int
)
Joukkueen suurin sallittu pelaajamäärä on oletusarvoisesti 16 (lisää tämä luokan oliomuuttujaksi ja alusta muuttujan arvo konstruktorissa). Metodin setMaksimikoko
avulla tätä rajaa voi muuttaa. Muuta edellisessä osassa tehtyä metodia lisaaPelaaja
niin, että se ei lisää pelaajaa joukkueeseen, jos sallittu pelaajamäärä ylittyisi.
HUOM: muista lisätä oletusarvoinen maksimikoko koodiisi sillä muuten arvoksi tulee 0. Tämä aiheuttaa edellisen kohdan testien hajoamisen, sillä testit luovat oletusmaksimikokoisia joukkueita ja jos joukkueen maksimikoko on 0, ei joukkueeseen voi lisätä yhtään pelaajaa.
Seuraava pääohjelma testaa luokan toimintaa:
Joukkue tapiiri = new Joukkue("FC Tapiiri");
tapiiri.setMaksimikoko(1);
Pelaaja matti = new Pelaaja("Matti");
Pelaaja pekka = new Pelaaja("Pekka", 39);
tapiiri.lisaaPelaaja(matti);
tapiiri.lisaaPelaaja(pekka);
tapiiri.lisaaPelaaja(new Pelaaja("Mikael", 1)); //vaikutus on sama kuin edellisillä
System.out.println("Pelaajia yhteensä: " + tapiiri.getPelaajienLukumaara());
Pelaajia yhteensä: 1
Joukkueen maalit
Lisää luokkaan Joukkue
metodi:
-
yhteismaalit
, joka palauttaa joukkueen pelaajien tekemien maalien yhteismäärän.
Seuraava pääohjelma testaa luokan toimintaa:
Joukkue tapiiri = new Joukkue("FC Tapiiri");
Pelaaja matti = new Pelaaja("Matti");
Pelaaja pekka = new Pelaaja("Pekka", 39);
tapiiri.lisaaPelaaja(matti);
tapiiri.lisaaPelaaja(pekka);
tapiiri.lisaaPelaaja(new Pelaaja("Mikael", 1)); //vaikutus on sama kuin edellisillä
System.out.println("Maaleja yhteensä: " + tapiiri.yhteismaalit());
Maaleja yhteensä: 40
Tehtäväpohjan mukana tulee luokat Tavara
ja Laatikko
. Luokka Laatikko
on abstrakti luokka, jossa useamman tavaran lisääminen on toteutettu siten, että kutsutaan aina lisaa
-metodia. Yhden tavaran lisäämiseen tarkoitettu metodi lisaa
on abstrakti, joten jokaisen Laatikko
-luokan perivän laatikon tulee toteuttaa se. Tehtävänäsi on muokata luokkaa Tavara
ja toteuttaa muutamia erilaisia laatikoita luokan Laatikko
pohjalta.
Lisää kaikki uudet luokat pakkaukseen laatikot
.
package laatikot;
import java.util.Collection;
public abstract class Laatikko {
public abstract void lisaa(Tavara tavara);
public void lisaa(Collection<Tavara> tavarat) {
for (Tavara t: tavarat) {
lisaa(t);
}
}
public abstract boolean onkoLaatikossa(Tavara tavara);
}
Tavaran muokkaus
Lisää Tavara
-luokan konstruktoriin tarkistus, jossa tarkistetaan että tavaran paino ei ole koskaan negatiivinen (paino 0 hyväksytään). Jos paino on negatiivinen, tulee konstruktorin heittää IllegalArgumentException
-poikkeus. Toteuta Tavara
-luokalle myös metodit equals
ja hashCode
, joiden avulla pääset hyödyntämään erilaisten listojen ja kokoelmien contains
-metodia. Toteuta metodit siten, että Tavara-luokan oliomuuttujan paino
arvolla ei ole väliä. Voit hyvin hyödyntää NetBeansin tarjoamaa toiminnallisuutta equalsin ja hashCoden toteuttamiseen.
Maksimipainollinen laatikko
Toteuta pakkaukseen laatikot
luokka MaksimipainollinenLaatikko
, joka perii luokan Laatikko
. Maksimipainollisella laatikolla on konstruktori public MaksimipainollinenLaatikko(int maksimipaino)
, joka määrittelee laatikon maksimipainon. Maksimipainolliseen laatikkoon voi lisätä tavaraa jos ja vain jos tavaran lisääminen ei ylitä laatikon maksimipainoa.
MaksimipainollinenLaatikko kahviLaatikko = new MaksimipainollinenLaatikko(10);
kahviLaatikko.lisaa(new Tavara("Saludo", 5));
kahviLaatikko.lisaa(new Tavara("Pirkka", 5));
kahviLaatikko.lisaa(new Tavara("Kopi Luwak", 5));
System.out.println(kahviLaatikko.onkoLaatikossa(new Tavara("Saludo")));
System.out.println(kahviLaatikko.onkoLaatikossa(new Tavara("Pirkka")));
System.out.println(kahviLaatikko.onkoLaatikossa(new Tavara("Kopi Luwak")));
true true false
Yhden tavaran laatikko ja Hukkaava laatikko
Toteuta seuraavaksi pakkaukseen laatikot
luokka YhdenTavaranLaatikko
, joka perii luokan Laatikko
. Yhden tavaran laatikolla on konstruktori public YhdenTavaranLaatikko()
, ja siihen mahtuu tasan yksi tavara. Jos tavara on jo laatikossa sitä ei tule vaihtaa. Laatikkoon lisättävän tavaran painolla ei ole väliä.
YhdenTavaranLaatikko laatikko = new YhdenTavaranLaatikko();
laatikko.lisaa(new Tavara("Saludo", 5));
laatikko.lisaa(new Tavara("Pirkka", 5));
System.out.println(laatikko.onkoLaatikossa(new Tavara("Saludo")));
System.out.println(laatikko.onkoLaatikossa(new Tavara("Pirkka")));
true false
Toteuta seuraavaksi pakkaukseen laatikot
luokka HukkaavaLaatikko
, joka perii luokan Laatikko
. Hukkaavalla laatikolla on konstruktori public HukkaavaLaatikko()
. Hukkaavaan laatikkoon voi lisätä kaikki tavarat, mutta tavaroita ei löydy niitä etsittäessä. Laatikkoon lisäämisen tulee siis aina onnistua, mutta metodin onkoLaatikossa
kutsumisen tulee aina palauttaa false.
HukkaavaLaatikko laatikko = new HukkaavaLaatikko();
laatikko.lisaa(new Tavara("Saludo", 5));
laatikko.lisaa(new Tavara("Pirkka", 5));
System.out.println(laatikko.onkoLaatikossa(new Tavara("Saludo")));
System.out.println(laatikko.onkoLaatikossa(new Tavara("Pirkka")));
false false
Tässä tehtävässä demonstroit perinnän ja rajapintojen käyttöä. Toteuta kaikki luokat ja rajapinnat pakkaukseen perintaa
.
Eläin
Toteuta ensin abstrakti luokka Elain
. Luokalla Elain on konstruktori, jolle annetaan parametrina eläimen nimi. Luokalla Elain on lisäksi parametrittomat metodit syo ja nuku, jotka eivät palauta arvoa (void), sekä parametriton metodi getNimi, joka palauttaa eläimen nimen.
Metodin nuku tulee tulostaa "(nimi) nukkuu" ja metodin syo tulee tulostaa "(nimi) syo". Tässä (nimi) on eläimelle annettu nimi.
Koira
Toteuta luokan Elain perivä luokka Koira
. Luokalla Koira tulee olla parametrillinen konstruktori, jolla luotavalle koiraoliolle voi antaa nimen. Tämän lisäksi koiralla tulee olla parametriton konstruktori, jolla koiran nimeksi tulee "Koira" sekä parametriton metodi hauku, joka ei palauta arvoa (void). Koiralla tulee olla myös metodit syo ja nuku kuten eläimillä yleensä ottaen.
Alla on esimerkki luokan Koira odotetusta toiminnasta:
Koira koira = new Koira();
koira.hauku();
koira.syo();
Koira vuffe = new Koira("Vuffe");
vuffe.hauku();
Koira haukkuu Koira syo Vuffe haukkuu
Kissa
Toteuta seuraavaksi luokka Kissa
, joka perii luokan Elain. Luokalla Kissa tulee olla parametrillinen konstruktori, jolla luotavalle kissaoliolle voi antaa nimen. Tämän lisäksi kissalla tulee olla parametriton konstruktori, jolla kissan nimeksi tulee "Kissa" sekä parametriton metodi mourua, joka ei palauta arvoa (void). Kissalla tulee olla myös metodit syo ja nuku kuten ensimmäisessä osassa.
Alla on esimerkki luokan Kissa odotetusta toiminnasta:
Kissa kissa = new Kissa();
kissa.mourua();
kissa.syo();
Kissa karvinen = new Kissa("Karvinen");
karvinen.mourua();
Kissa mouruaa Kissa syo Karvinen mouruaa
Ääntelevä
Luo lopulta rajapinta Aanteleva
, joka maarittelee parametrittoman metodin aantele, joka ei palauta arvoa (void). Toteuta rajapinta luokissa Koira että Kissa. Rajapinnan tulee hyödyntää aiemmin määriteltyjä hauku ja mourua -metodeja.
Alla on esimerkki odotetusta toiminnasta:
Aanteleva koira = new Koira();
koira.aantele();
Aanteleva kissa = new Kissa("Karvinen");
kissa.aantele();
Kissa k = (Kissa) kissa;
k.mourua();
Koira haukkuu Karvinen mouruaa Karvinen mouruaa
Tee ohjelma, joka lukee käyttäjältä kirjoja ja niiden minimikohdeikiä. Minimikohdeiällä tarkoitetaan pienintä ikää vuosina, jolle kyseistä kirjaa suositellaan.
Ohjelma kysyy uusia kirjoja kunnes käyttäjä syöttää tyhjän merkkijonon kirjan nimen kohdalla (eli painaa rivinvaihtoa). Täämän jälkeen ohjelma tulostaa syötettyjen kirjojen lukumäärän sekä kirjat.
Kirjojen lukeminen ja tulostaminen
Toteuta ensin kirjojen lukeminen ja niiden listaaminen. Tässä vaiheessa kirjojen järjestyksellä ei ole vielä väliä.
Syötä kirjan nimi, tyhjä lopettaa: Soiva tuutulaulukirja Syötä kirjan pienin kohdeikä: 0 Syötä kirjan nimi, tyhjä lopettaa: Kurkkaa kulkuneuvot Syötä kirjan pienin kohdeikä: 0 Syötä kirjan nimi, tyhjä lopettaa: Lunta tupaan Syötä kirjan pienin kohdeikä: 12 Syötä kirjan nimi, tyhjä lopettaa: Litmanen 10 Syötä kirjan pienin kohdeikä: 10 Syötä kirjan nimi, tyhjä lopettaa: Yhteensä 4 kirjaa. Kirjat: Soiva tuutulaulukirja (0 vuotiaille ja vanhemmille) Kurkkaa kulkuneuvot (0 vuotiaille ja vanhemmille) Lunta tupaan (12 vuotiaille ja vanhemmille) Litmanen 10 (10 vuotiaille ja vanhemmille)
Kirjojen järjestäminen kohdeiän perusteella
Täydennä toteuttamaasi ohjelmaa siten, että kirjat järjestetään tulostuksen yhteydessä kohdeiän perusteella. Jos kahdella kirjalla on sama kohdeikä, näiden kahden kirjan keskinäinen järjestys saa olla mielivaltainen.
Syötä kirjan nimi, tyhjä lopettaa: Soiva tuutulaulukirja Syötä kirjan pienin kohdeikä: 0 Syötä kirjan nimi, tyhjä lopettaa: Kurkkaa kulkuneuvot Syötä kirjan pienin kohdeikä: 0 Syötä kirjan nimi, tyhjä lopettaa: Lunta tupaan Syötä kirjan pienin kohdeikä: 12 Syötä kirjan nimi, tyhjä lopettaa: Litmanen 10 Syötä kirjan pienin kohdeikä: 10 Syötä kirjan nimi, tyhjä lopettaa: Yhteensä 4 kirjaa. Kirjat: Soiva tuutulaulukirja (0 vuotiaille ja vanhemmille) Kurkkaa kulkuneuvot (0 vuotiaille ja vanhemmille) Litmanen 10 (10 vuotiaille ja vanhemmille) Lunta tupaan (12 vuotiaille ja vanhemmille)
Kirjojen järjestäminen kohdeiän ja nimen perusteella
Täydennä edellistä ohjelmaasi siten, että saman kohdeiän kirjat tulostetaan aakkosjärjestyksessä.
Syötä kirjan nimi, tyhjä lopettaa: Soiva tuutulaulukirja Syötä kirjan pienin kohdeikä: 0 Syötä kirjan nimi, tyhjä lopettaa: Kurkkaa kulkuneuvot Syötä kirjan pienin kohdeikä: 0 Syötä kirjan nimi, tyhjä lopettaa: Lunta tupaan Syötä kirjan pienin kohdeikä: 12 Syötä kirjan nimi, tyhjä lopettaa: Litmanen 10 Syötä kirjan pienin kohdeikä: 10 Syötä kirjan nimi, tyhjä lopettaa: Yhteensä 4 kirjaa. Kirjat: Kurkkaa kulkuneuvot (0 vuotiaille ja vanhemmille) Soiva tuutulaulukirja (0 vuotiaille ja vanhemmille) Litmanen 10 (10 vuotiaille ja vanhemmille) Lunta tupaan (12 vuotiaille ja vanhemmille)
Matkailijat tykkäävät ottaa valokuvia. Usein kuvissa sattuu kuitenkin olemaan ärsyttävä turisti, joka on esimerkiksi kuvatun kohteen edessä. Harmitus kasvaa erityisesti, jos samainen turisti esiintyy jokaisessa kuvassa.
Alla on kaksi kuvaa eräästä reissusta.
Täydennetään ohjelmaa, mikä mahdollistaa kuvan katsomisen ilman turistia. Apunamme meillä on iso nippu samasta kohteesta otettuja kuvia (turisti on harmittavasti kylläkin jokaisessa niistä...)
Tehtäväpohjassa on valmiina ohjelma, jolla voi tarkastella kuvia. Huomaat, että ohjelmassa käytetty kuvien näyttämistapa poikkeaa hieman edellisistä esimerkeistä -- kuten todettua, lähestymistapoja on useita. Kun ohjelma on käynnissä, painamalla numeronäppäintä saat näkyville kuvalistan tietyssä indeksissä olevan kuvan. Kun painat näppäintä "v", näet kuvan muodossa, missä jokaisen kuvan jokaisesta pikselistä on valittu vaaleimmat pikseliarvot.
Tummimman värin valinta
Muokkaa sovellusta siten, että kun käyttäjä painaa näppäintä "t", ohjelma näyttää kuvan, missä näkyy yhdistettävien kuvien tummimmat pikselit. Toteuta tummimman värin valinta luokan Yhdistin metodiin public WritableImage tummin(final ArrayList<Image> kuvat)
-- ota mallia metodista vaalein
.
Kun olet lisännyt tummennustoiminnallisuuden, tumman kuvan pitäisi näyttää kutakuinkin seuraavalta.
Värien mediaani
Muokkaa sovellusta siten, että kun käyttäjä painaa näppäintä "m", ohjelma näyttää kuvan, missä näkyy yhdistettävien kuvien väriarvojen mediaanit. Toteuta mediaanivärin valinta luokan Yhdistin metodiin public WritableImage mediaani(final ArrayList<Image> kuvat)
.
Mediaani on järjestettyjen lukujen keskimmäinen arvo. Esimerkiksi, jos viiden kuvan sinisten värien arvot ovat 211, 123, 17, 155, 8
, on niiden mediaani 123
. Saat mediaanin selville järjestämällä arvot, ja valitsemalla listan keskimmäisen arvon.
Toteutuksen pitäisi poistaa ärsyttävä turisti:
Tehtävän alkuperäinen versio: John Nicholson / Austin Peay State University
Netflix lupasi lokakuussa 2006 miljoona dollaria henkilölle tai ryhmälle, joka kehittäisi ohjelman, joka on 10% parempi elokuvien suosittelussa kuin heidän oma ohjelmansa. Kilpailu ratkesi syyskuussa 2009 (http://www.netflixprize.com/).
Rakennetaan tässä tehtävässä ohjelma elokuvien suositteluun. Alla on sen toimintaesimerkki:
ArvioRekisteri arviot = new ArvioRekisteri();
Elokuva tuulenViemaa = new Elokuva("Tuulen viemää");
Elokuva hiljaisetSillat = new Elokuva("Hiljaiset sillat");
Elokuva eraserhead = new Elokuva("Eraserhead");
Henkilo matti = new Henkilo("Matti");
Henkilo pekka = new Henkilo("Pekka");
Henkilo mikke = new Henkilo("Mikke");
Henkilo thomas = new Henkilo("Thomas");
arviot.lisaaArvio(matti, tuulenViemaa, Arvio.HUONO);
arviot.lisaaArvio(matti, hiljaisetSillat, Arvio.HYVA);
arviot.lisaaArvio(matti, eraserhead, Arvio.OK);
arviot.lisaaArvio(pekka, tuulenViemaa, Arvio.OK);
arviot.lisaaArvio(pekka, hiljaisetSillat, Arvio.HUONO);
arviot.lisaaArvio(pekka, eraserhead, Arvio.VALTTAVA);
arviot.lisaaArvio(mikke, eraserhead, Arvio.HUONO);
Suosittelija suosittelija = new Suosittelija(arviot);
System.out.println(thomas + " suositus: " + suosittelija.suositteleElokuva(thomas));
System.out.println(mikke + " suositus: " + suosittelija.suositteleElokuva(mikke));
Thomas suositus: Hiljaiset sillat Mikke suositus: Tuulen viemää
Ohjelma osaa suositella elokuvia niiden yleisen arvion perusteella, sekä henkilökohtaisten henkilön antaminen arvioiden perusteella. Lähdetään rakentamaan ohjelmaa.
Henkilo ja Elokuva
Luo pakkaus suosittelija.domain
ja lisää sinne luokat Henkilo
ja Elokuva
. Kummallakin luokalla on julkinen konstruktori public Luokka(String nimi)
, sekä metodi public String getNimi()
, joka palauttaa konstruktorissa saadun nimen.
Henkilo henkilo = new Henkilo("Pekka");
Elokuva elokuva = new Elokuva("Eraserhead");
System.out.println(henkilo.getNimi() + " ja " + elokuva.getNimi());
Pekka ja Eraserhead
Lisää luokille myös public String toString()
-metodi, joka palauttaa konstruktorissa parametrina annetun nimen, sekä korvaa metodit equals
ja hashCode
.
Korvaa equals
siten että samuusvertailu tapahtuu oliomuuttujan nimi
perusteella. Metodi hashCode kannattaa generoida automaattisesti seuraavan ohjeen mukaan:
Muistathan, että NetBeans tarjoaa metodien equals ja hashCode automaattisen luonnin. Voit valita valikosta Source -> Insert Code, ja valita aukeavasta listasta equals() and hashCode(). Tämän jälkeen NetBeans kysyy oliomuuttujat joita metodeissa käytetään.
Arvio
Luo pakkaukseen suosittelija.domain
lueteltu tyyppi Arvio
. Enum-luokalla Arvio
on julkinen metodi public int getArvo()
, joka palauttaa arvioon liittyvän arvon. Arviotunnusten ja niihin liittyvien arvosanojen tulee olla seuraavat:
Tunnus | Arvo |
---|---|
HUONO | -5 |
VALTTAVA | -3 |
EI_NAHNYT | 0 |
NEUTRAALI | 1 |
OK | 3 |
HYVA | 5 |
Luokkaa voi käyttää seuraavasti:
Arvio annettu = Arvio.HYVA;
System.out.println("Arvio " + annettu + ", arvo " + annettu.getArvo());
annettu = Arvio.NEUTRAALI;
System.out.println("Arvio " + annettu + ", arvo " + annettu.getArvo());
Arvio HYVA, arvo 5 Arvio NEUTRAALI, arvo 1
ArvioRekisteri, osa 1
Aloitetaan arvioiden varastointiin liittyvän palvelun toteutus.
Luo pakkaukseen suosittelija
luokka ArvioRekisteri
, jolla on konstruktori public ArvioRekisteri()
sekä seuraavat metodit:
public void lisaaArvio(Elokuva elokuva, Arvio arvio)
lisää arviorekisteriin parametrina annetulle elokuvalle uuden arvion. Samalla elokuvalla voi olla useita samanlaisiakin arvioita.public List<Arvio> annaArviot(Elokuva elokuva)
palauttaa elokuvalle lisätyt arviot listana.public Map<Elokuva, List<Arvio>> elokuvienArviot()
palauttaa hajautustaulun, joka sisältää arvioidut elokuvat avaimina. Jokaiseen elokuvaan liittyy lista, joka sisältää elokuvaan lisatyt arviot.
Testaa metodien toimintaa seuraavalla lähdekoodilla:
Elokuva hiljaisetSillat = new Elokuva("Hiljaiset sillat");
Elokuva eraserhead = new Elokuva("Eraserhead");
ArvioRekisteri rekisteri = new ArvioRekisteri();
rekisteri.lisaaArvio(eraserhead, Arvio.HUONO);
rekisteri.lisaaArvio(eraserhead, Arvio.HUONO);
rekisteri.lisaaArvio(eraserhead, Arvio.HYVA);
rekisteri.lisaaArvio(hiljaisetSillat, Arvio.HYVA);
rekisteri.lisaaArvio(hiljaisetSillat, Arvio.OK);
System.out.println("Kaikki arviot: " + rekisteri.elokuvienArviot());
System.out.println("Arviot Eraserheadille: " + rekisteri.annaArviot(eraserhead));
Kaikki arviot: {Hiljaiset sillat=[HYVA, OK], Eraserhead=[HUONO, HUONO, HYVA]} Arviot Eraserheadille: [HUONO, HUONO, HYVA]
ArvioRekisteri, osa 2
Lisätään seuraavaksi mahdollisuus henkilökohtaisten arvioiden lisäämiseen.
Lisää luokkaan ArvioRekisteri
seuraavat metodit:
public void lisaaArvio(Henkilo henkilo, Elokuva elokuva, Arvio arvio)
lisää parametrina annetulle elokuvalle tietyn henkilön tekemän arvion. Sama henkilö voi arvioida tietyn elokuvan vain kertaalleen. Henkilön tekemä arvio tulee myös lisätä kaikkiin elokuviin liittyviin arvioihin.public Arvio haeArvio(Henkilo henkilo, Elokuva elokuva)
palauttaa parametrina annetun henkilön tekemän arvion parametrina annetulle elokuvalle. Jos henkilö ei ole arvioinut kyseistä elokuvaa, palauta arvioArvio.EI_NAHNYT
.public Map<Elokuva, Arvio> annaHenkilonArviot(Henkilo henkilo)
palauttaa hajautustaulun, joka sisältää henkilön tekemät arviot. Hajautustaulun avaimena on arvioidut elokuvat, arvoina arvioituihin elokuviin liittyvät arviot. Jos henkilö ei ole arvioinut yhtään elokuvaa, palautetaan tyhjä hajautustaulu.public List<Henkilo> arvioijat()
palauttaa listan henkilöistä jotka ovat arvioineet elokuvia.
Henkilöiden tekemät arviot kannattanee tallentaa hajautustauluun, jossa avaimena on henkilö. Arvona hajautustaulussa on toinen hajautustaulu, jossa avaimena on elokuva ja arvona arvio.
Testaa paranneltua ArvioRekisteri
-luokkaa seuraavalla lähdekoodipätkällä:
ArvioRekisteri arviot = new ArvioRekisteri();
Elokuva tuulenViemaa = new Elokuva("Tuulen viemää");
Elokuva eraserhead = new Elokuva("Eraserhead");
Henkilo matti = new Henkilo("Matti");
Henkilo pekka = new Henkilo("Pekka");
arviot.lisaaArvio(matti, tuulenViemaa, Arvio.HUONO);
arviot.lisaaArvio(matti, eraserhead, Arvio.OK);
arviot.lisaaArvio(pekka, tuulenViemaa, Arvio.OK);
arviot.lisaaArvio(pekka, eraserhead, Arvio.OK);
System.out.println("Arviot Eraserheadille: " + arviot.annaArviot(eraserhead));
System.out.println("Matin arviot: " + arviot.annaHenkilonArviot(matti));
System.out.println("Arvioijat: " + arviot.arvioijat());
Arviot Eraserheadille: [OK, OK] Matin arviot: {Tuulen viemää=HUONO, Eraserhead=OK} Arvioijat: [Pekka, Matti]
Luodaan seuraavaksi muutama apuluokka arviointien helpottamiseksi.
HenkiloComparator
Luo pakkaukseen suosittelija.comparator
luokka HenkiloComparator
. Luokan HenkiloComparator
tulee toteuttaa rajapinta Comparator<Henkilo>
, ja sillä pitää olla konstruktori public HenkiloComparator(Map<Henkilo, Integer> henkiloidenSamuudet)
. Luokkaa HenkiloComparator
käytetään myöhemmin henkilöiden järjestämiseen henkilöön liittyvän luvun perusteella.
HenkiloComparator-luokan tulee mahdollistaa henkilöiden järjestäminen henkilöön liittyvän luvun perusteella.
Testaa luokan toimintaa seuraavalla lähdekoodilla:
Henkilo matti = new Henkilo("Matti");
Henkilo pekka = new Henkilo("Pekka");
Henkilo mikke = new Henkilo("Mikke");
Henkilo thomas = new Henkilo("Thomas");
Map<Henkilo, Integer> henkiloidenSamuudet = new HashMap<>();
henkiloidenSamuudet.put(matti, 42);
henkiloidenSamuudet.put(pekka, 134);
henkiloidenSamuudet.put(mikke, 8);
henkiloidenSamuudet.put(thomas, 82);
List<Henkilo> henkilot = Arrays.asList(matti, pekka, mikke, thomas);
System.out.println("Henkilöt ennen järjestämistä: " + henkilot);
Collections.sort(henkilot, new HenkiloComparator(henkiloidenSamuudet));
System.out.println("Henkilöt järjestämisen jälkeen: " + henkilot);
Henkilöt ennen järjestämistä: [Matti, Pekka, Mikke, Thomas] Henkilöt järjestämisen jälkeen: [Pekka, Thomas, Matti, Mikke]
ElokuvaComparator
Luo pakkaukseen suosittelija.comparator
luokka ElokuvaComparator
. Luokan ElokuvaComparator
tulee toteuttaa rajapinta Comparator<Elokuva>
, ja sillä pitää olla konstruktori public ElokuvaComparator(Map<Elokuva, List<Arvio>> arviot)
. Luokkaa ElokuvaComparator
käytetään myöhemmin elokuvien järjestämiseen niiden arvioiden perusteella.
ElokuvaComparator-luokan tulee tarjota mahdollisuus elokuvien järjestäminen niiden saamien arvosanojen keskiarvon perusteella. Korkeimman keskiarvon saanut elokuva tulee ensimmäisenä, matalimman keskiarvon saanut viimeisenä.
Testaa luokan toimintaa seuraavalla lähdekoodilla:
ArvioRekisteri arviot = new ArvioRekisteri();
Elokuva tuulenViemaa = new Elokuva("Tuulen viemää");
Elokuva hiljaisetSillat = new Elokuva("Hiljaiset sillat");
Elokuva eraserhead = new Elokuva("Eraserhead");
Henkilo matti = new Henkilo("Matti");
Henkilo pekka = new Henkilo("Pekka");
Henkilo mikke = new Henkilo("Mikke");
arviot.lisaaArvio(matti, tuulenViemaa, Arvio.HUONO);
arviot.lisaaArvio(matti, hiljaisetSillat, Arvio.HYVA);
arviot.lisaaArvio(matti, eraserhead, Arvio.OK);
arviot.lisaaArvio(pekka, tuulenViemaa, Arvio.OK);
arviot.lisaaArvio(pekka, hiljaisetSillat, Arvio.HUONO);
arviot.lisaaArvio(pekka, eraserhead, Arvio.VALTTAVA);
arviot.lisaaArvio(mikke, eraserhead, Arvio.HUONO);
Map<Elokuva, List<Arvio>> elokuvienArviot = arviot.elokuvienArviot();
List<Elokuva> elokuvat = Arrays.asList(tuulenViemaa, hiljaisetSillat, eraserhead);
System.out.println("Elokuvat ennen järjestämistä: " + elokuvat);
Collections.sort(elokuvat, new ElokuvaComparator(elokuvienArviot));
System.out.println("Elokuvat järjestämisen jälkeen: " + elokuvat);
Elokuvat ennen järjestämistä: [Tuulen viemää, Hiljaiset sillat, Eraserhead] Elokuvat järjestämisen jälkeen: [Hiljaiset sillat, Tuulen viemää, Eraserhead]
Suosittelija, osa 1
Toteuta pakkaukseen suosittelija
luokka Suosittelija
. Luokan Suosittelija
konstruktori saa parametrinaan ArvioRekisteri
-tyyppisen olion. Suosittelija käyttää arviorekisterissä olevia arvioita suositusten tekemiseen.
Toteuta luokalle metodi public Elokuva suositteleElokuva(Henkilo henkilo)
, joka suosittelee henkilölle elokuvia.
Toteuta metodi siten, että se suosittelee aina elokuvaa, jonka arvioiden arvosanojen keskiarvo on suurin. Vinkki: Tarvitset parhaan elokuvan selvittämiseen ainakin aiemmin luotua ElokuvaComparator
-luokkaa, luokan ArvioRekisteri
metodia public Map<Elokuva, List<Arvio>> elokuvienArviot()
, sekä listaa olemassaolevista elokuvista.
Testaa ohjelman toimimista seuraavalla lähdekoodilla:
ArvioRekisteri arviot = new ArvioRekisteri();
Elokuva tuulenViemaa = new Elokuva("Tuulen viemää");
Elokuva hiljaisetSillat = new Elokuva("Hiljaiset sillat");
Elokuva eraserhead = new Elokuva("Eraserhead");
Henkilo matti = new Henkilo("Matti");
Henkilo pekka = new Henkilo("Pekka");
Henkilo mikke = new Henkilo("Mikael");
arviot.lisaaArvio(matti, tuulenViemaa, Arvio.HUONO);
arviot.lisaaArvio(matti, hiljaisetSillat, Arvio.HYVA);
arviot.lisaaArvio(matti, eraserhead, Arvio.OK);
arviot.lisaaArvio(pekka, tuulenViemaa, Arvio.OK);
arviot.lisaaArvio(pekka, hiljaisetSillat, Arvio.VALTTAVA);
arviot.lisaaArvio(pekka, eraserhead, Arvio.VALTTAVA);
Suosittelija suosittelija = new Suosittelija(arviot);
Elokuva suositeltu = suosittelija.suositteleElokuva(mikke);
System.out.println("Mikaelille suositeltu elokuva oli: " + suositeltu);
Mikaelille suositeltu elokuva oli: Hiljaiset sillat
Nyt tekemämme ensimmäinen vaihe toimii oikein ainoastaan henkilöille, jotka eivät ole vielä arvostelleet yhtään elokuvaa. Heidän elokuvamaustaanhan on mahdoton sanoa mitään ja paras arvaus on suositella heille keskimäärin parhaan arvosanan saanutta elokuvaa.
Suosittelija, osa 2
Huom! Tehtävä on haastava. Kannattaa tehdä ensin muut tehtävät ja palata tähän myöhemmin. Voit palauttaa tehtäväsarjan TMC:hen vaikket saakaan tätä tehtävää tehdyksi, aivan kuten lähes kaikkien muidenkin tehtävien kohdalla.
Valitettavasti tämän osan virhediagnostiikkakaan ei ole samaa luokkaa kuin edellisissä kohdissa.
Jos henkilöt ovat lisänneet omia suosituksia suosituspalveluun, tiedämme jotain heidän elokuvamaustaan. Laajennetaan suosittelijan toiminnallisuutta siten, että se luo henkilökohtaisen suosituksen jos henkilö on jo arvioinut elokuvia. Edellisessä osassa toteutettu toiminnallisuus tulee säilyttää: Jos henkilö ei ole arvioinut yhtäkään elokuvaa, hänelle suositellaan elokuva arvosanojen perusteella.
Henkilökohtaiset suositukset perustuvat henkilön tekemien arvioiden samuuteen muiden henkilöiden tekemien arvioiden kanssa. Pohditaan seuraavaa taulukkoa, missä ylärivillä on elokuvat, ja vasemmalla on arvioita tehneet henkilöt. Taulukon solut kuvaavat annettuja arvioita.
Henkilo \ Elokuva | Tuulen viemää | Hiljaiset sillat | Eraserhead | Blues Brothers |
---|---|---|---|---|
Matti | HUONO (-5) | HYVA (5) | OK (3) | - |
Pekka | OK (3) | - | HUONO (-5) | VALTTAVA (-3) |
Mikael | - | - | HUONO (-5) | - |
Thomas | - | HYVA (5) | - | HYVA (5) |
Kun haluamme hakea Mikaelille sopivaa elokuvaa, tutkimme Mikaelin samuutta kaikkien muiden arvioijien kesken. Samuus lasketaan arvioiden perusteella: samuus on kummankin katsomien elokuvien arvioiden tulojen summa. Esimerkiksi Mikaelin ja Thomasin samuus on 0, koska Mikael ja Thomas eivät ole katsoneet yhtäkään samaa elokuvaa.
Mikaelin ja Pekan samuutta laskettaessa yhteisten elokuvien tulojen summa olisi 25. Mikael ja Pekka ovat katsoneet vain yhden yhteisen elokuvan, ja kumpikin antaneet sille arvosanan huono (-5).
-5 * -5 = 25
Mikaelin ja Matin samuus on -15. Mikael ja Matti ovat myös katsoneet vain yhden yhteisen elokuvan. Mikael antoi elokuvalle arvosanan huono (-5), Matti antoi sille arvosanan ok (3).
-5 * 3 = -15
Näiden perusteella Mikaelille suositellaan elokuvia Pekan elokuvamaun mukaan: suosituksena on elokuva Tuulen viemää.
Kun taas haluamme hakea Matille sopivaa elokuvaa, tutkimme Matin samuutta kaikkien muiden arvioijien kesken. Matti ja Pekka ovat katsoneet kaksi yhteistä elokuvaa. Matti antoi Tuulen viemälle arvosanan huono (-5), Pekka arvosanan OK (3). Elokuvalle Eraserhead Matti antoi arvosanan OK (3), Pekka arvosanan huono (-5). Matin ja Pekan samuus on siis -30.
-5 * 3 + 3 * -5 = -30
Matin ja Mikaelin samuus on edellisestä laskusta tiedetty -15. Samuudet ovat symmetrisia.
Matti ja Thomas ovat katsoneet Hiljaiset sillat, ja kumpikin antoi sille arvosanan hyvä (5). Matin ja Thomaksen samuus on siis 25.
5 * 5 = 25
Matille tulee siis suositella elokuvia Thomaksen elokuvamaun mukaan: suosituksena olisi Blues Brothers.
Toteuta yllä kuvattu suosittelumekanismi. Jos henkilölle ei löydy yhtään suositeltavaa elokuvaa, tai henkilö, kenen elokuvamaun mukaan elokuvia suositellaan on arvioinut elokuvat joita henkilö ei ole vielä katsonut huonoiksi, välttäviksi tai neutraaleiksi, palauta metodista suositteleElokuva
arvo null
. Edellisessä tehtävässä määritellyn lähestymistavan tulee toimia jos henkilö ei ole lisännyt yhtäkään arviota.
Älä suosittele elokuvia, jotka henkilö on jo nähnyt.
Voit testata ohjelmasi toimintaa seuraavalla lähdekoodilla:
ArvioRekisteri arviot = new ArvioRekisteri();
Elokuva tuulenViemaa = new Elokuva("Tuulen viemää");
Elokuva hiljaisetSillat = new Elokuva("Hiljaiset sillat");
Elokuva eraserhead = new Elokuva("Eraserhead");
Elokuva bluesBrothers = new Elokuva("Blues Brothers");
Henkilo matti = new Henkilo("Matti");
Henkilo pekka = new Henkilo("Pekka");
Henkilo mikke = new Henkilo("Mikael");
Henkilo thomas = new Henkilo("Thomas");
Henkilo arto = new Henkilo("Arto");
arviot.lisaaArvio(matti, tuulenViemaa, Arvio.HUONO);
arviot.lisaaArvio(matti, hiljaisetSillat, Arvio.HYVA);
arviot.lisaaArvio(matti, eraserhead, Arvio.OK);
arviot.lisaaArvio(pekka, tuulenViemaa, Arvio.OK);
arviot.lisaaArvio(pekka, eraserhead, Arvio.HUONO);
arviot.lisaaArvio(pekka, bluesBrothers, Arvio.VALTTAVA);
arviot.lisaaArvio(mikke, eraserhead, Arvio.HUONO);
arviot.lisaaArvio(thomas, bluesBrothers, Arvio.HYVA);
arviot.lisaaArvio(thomas, hiljaisetSillat, Arvio.HYVA);
Suosittelija suosittelija = new Suosittelija(arviot);
System.out.println(thomas + " suositus: " + suosittelija.suositteleElokuva(thomas));
System.out.println(mikke + " suositus: " + suosittelija.suositteleElokuva(mikke));
System.out.println(matti + " suositus: " + suosittelija.suositteleElokuva(matti));
System.out.println(arto + " suositus: " + suosittelija.suositteleElokuva(arto));
Thomas suositus: Eraserhead Mikael suositus: Tuulen viemää Matti suositus: Blues Brothers Arto suositus: Hiljaiset sillat
Miljoona käsissä? Ei ehkä vielä. Tietojenkäsittelytieteen tekoäly- ja koneoppimiskursseilla opitaan lisää tekniikoita oppivien järjestelmien rakentamiseen.
Hirsipuu on peli, jossa käyttäjä yrittää arvata piilossa olevan sanan. Normaalissa hirsipuussa tietokone valitsee sanan ja pitää sitä piilossa käyttäjän yrittäessä arvata sanaan liittyviä kirjaimia. Arvauskertoja on rajattu määrä: jos pelaaja arvaa kaikki sanaan liittyvän kirjaimet, hän voittaa pelin. Jos taas pelaaja ei arvaa sanoja, tietokone voittaa pelin.
Toteutetaan tässä palasia hieman ärsyttävämpään versioon hirsipuusta, missä tietokone pyrkii voittamaan pelin huijaamalla.
Huijauksen ideana on se, että tietokone voi vaihtaa valitsemansa sanan tarvittaessa lennosta. Pelin lopullinen toiminnallisuus on seuraava:
... Sinulla on 3 arvausta jäljellä. Olet käyttänyt merkit: [a, b, c, d, e, f, g, h, i, j] Sana: -a--a Arvaus: r Ei r-kirjaimia. Sinulla on 2 arvausta jäljellä. Olet käyttänyt merkit: [a, b, c, d, e, f, g, h, i, j, r] Sana: -a--a Arvaus: s Löytyi ainakin yksi s-kirjain. Sinulla on 2 arvausta jäljellä. Olet käyttänyt merkit: [a, b, c, d, e, f, g, h, i, j, r, s] Sana: -as-a Arvaus: p Ei p-kirjaimia. Sinulla on 1 arvaus jäljellä. Olet käyttänyt merkit: [a, b, c, d, e, f, g, h, i, j, p, r, s] Sana: -as-a Arvaus: t Löytyi ainakin yksi t-kirjain. Sinulla on 1 arvaus jäljellä. Olet käyttänyt merkit: [a, b, c, d, e, f, g, h, i, j, p, r, s, t] Sana: -asta Arvaus: v Ei v-kirjaimia. Parempaa onnea ensi kerralla! Sana oli: rasta
Ohjelman tekstikäyttöliittymä on toteutettu valmiiksi Main-luokkaan.
Sanalista
Tässä toteutettavaa luokkaa Sanalista
käytetään käytettävissä olevien sanojen rajaamiseen. Luokkaan Sanalista
on määritelty merkkijonolistan parametrina ottavan konstruktorin sekä seuraavat metodit.
public List<String> sanat()
- palauttaa sanalistalla olevat sanat.public Sanalista sanatJoidenPituusOn(int pituus)
- palauttaa uuden sanalista-olion, jossa on vain ne sanat, joiden pituus on parametrina annetun muuttujan arvo.public Sanalista sanatJoissaEiEsiinnyKirjainta(char kirjain)
- palauttaa uuden sanalista-olion, jossa on vain ne sanat, joissa ei esiinny parametrina annettua kirjainmerkkiä.public Sanalista sanatJoissaMerkit(String merkkijono)
- palauttaa uuden sanalista-olion, jossa on vain ne sanat, joissa on merkit parametrina annetun merkkijonon määräämissä kohdissa. Annettu merkkijono on muotoa--d-
, missä viivat kuvaavat mitä tahansa merkkiä ja kirjaimet merkkejä, joiden täytyy olla sanassa juuri annetulla paikalla.public int koko()
- palauttaa sanalistan sisältämien sanojen määrän.
Toteuta edelliset metodit luokassa Sanalista
oleviin metodirunkoihin.
Hirsipuu, osa 1
Luokka Hirsipuu
pitää kirjaa hirsipuu-pelin tilanteesta. Hirsipuulla on konstruktori, joka saa parametrinaan sanalistan sekä arvausten määrän. Hirsipuu valitsee konstruktorissa myös arvattavan sanan annetulta sanalistalta.
Hirsipuu tarjoaa lisäksi ainakin seuraavat metodit.
public boolean arvaa(Character merkki)
- arvaa parametrina annettua merkkiä. Lisää arvauksen arvauslistalle. Jos merkki löytyy arvattavasta sanasta, palauttaa true. Jos merkkiä taas ei löydy, vähentää arvausten määrää yhdellä, ja palauttaa false.public List<Character> arvaukset()
- palauttaa tehdyt arvaukset listaoliona.public int arvauksiaJaljella()
- kertoo jäljellä olevien arvausten määrän.public String sana()
- kertoo arvattavan sanan siten, että kirjaimet, joita ei ole vielä arvattu, peitetään merkillä-
.public String oikeaSana()
- kertoo arvattavan sanan ilman peittelyä.public boolean onLoppu()
- kertoo onko peli loppu. Peli on loppu jos kaikki arvattavan sanan merkit on arvattu.
Toteuta edelliset metodit. Kun edelliset metodit on toteutettu, voit jo pelata hirsipuuta.
Tarkastele toteutuksen avuksi Test Packages
-kansiossa sijaitsevaa luokkaa BHirsipuuTest
. Voitko päätellä mitä luokassa olevat metodit tekevät?
Hirsipuu, osa 2
Jatka hirsipuun kehitystä siten, että hyödynnät sanalistaa ja pyrit tekemään hirsipuu-pelistä sellaisen, että se välttelee pelaajan arvauksia mahdollisimman hyvin. Kannattaa aloittaa arvaa-metodin parantamisesta.
Tähän osioon ei ole testejä -- palauta peli kun hirsipuu välttelee arvauksia mielestäsi tarpeeksi hyvin.
2048 on suosittu peli. Peliä pelataan 4x4 -kokoisessa lukuja sisältävässä ruudukossa, ja siinä on neljä mahdollista siirtoa: (o)ikealle, (a)las, (v)asemmalle ja (y)lös. Jokainen siirto siirtää kaikkia ruudukossa olevia arvoja niin paljon haluttuun suuntaan kuin mahdollista. Jos kahdessa vierekkäisessä ruudussa on sama arvo, yhdistetään ruutujen arvot yhteen. Esimerkiksi:
2 0 2 0 0 0 0 1 0 1 0 0 0 0 0 0 > o 0 0 0 4 0 0 0 1 0 0 0 1 0 1 0 0
Aina kun pelaaja tekee siirron, satunnaiseen nolla-arvoiseen kohtaan arvotaan uusi luku. Peli loppuu kun yhdessä ruuduista on luku 2048 tai siirtäminen ei enää onnistu. Alla esimerkki pelin kulusta.
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 > o 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 > o 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 > a 0 0 0 0 0 0 0 0 1 0 0 2 0 0 0 1 > a 1 0 0 0 0 0 0 0 0 0 0 2 1 0 0 1 > v 1 0 0 0 0 0 0 0 2 0 0 0 2 1 0 0 > y 1 1 0 0 4 0 0 0 0 0 0 0 0 1 0 0 > v 2 0 0 0 4 0 0 0 0 0 0 0 1 0 1 0 > v 2 0 0 0 4 1 0 0 0 0 0 0 2 0 0 0 >
Tässä tehtävässä rakennat pelin toimintaan tarvittua ydintoiminnallisuutta. Tehtävässä kerrataan myös toistolauseiden ja indeksien käyttöä.
Peliruudukko
Luo pakkaukseen sovellus luokka Peliruudukko. Luokalla tulee olla parametriton konstruktori, joka luo 4x4-kokoisen ruudukon, ja jonka vasemmassa yläkulmassa on arvo 1. Oleta, että kaksiulotteisen taulukon ensimmäinen indeksi kuvaa y-koordinaattia, ja toinen indeksi x-koordinaattia. Oleta lisäksi, että y-koordinaatti kasvaa alaspäin. Vasen yläkulma on siis kohdassa taulukko[0][0] ja vasen alakulma kohdassa taulukko[3][0] -- olettaen, että taulukon koko on 4.
Lisää luokalle myös metodit public int[][] getTaulukko(), joka palauttaa pelin sisäisen tilan, ja public void setTaulukko(int[][] taulukko), jolla voi asettaa pelin sisäisen tilan.
Siirrä oikealle
Tee tämän jälkeen peliruudukolle metodi public void siirraOikealle(), joka siirtää jokaisen rivin palat oikealle. Metodi yhdistää tarvittaessa myös samanarvoiset muuttujat. Alla muutamia esimerkkeja.
1 1 1 1 1 1 0 1 1 1 1 0 1 0 1 1 > o 0 0 0 4 0 0 1 2 0 0 1 2 0 0 1 2
1 0 0 1 0 1 0 1 2 2 4 0 0 1 0 0 > o 0 0 0 2 0 0 0 2 0 0 0 8 0 0 0 1
Siirrä ylös ja siirrä alas
Tee seuraavaksi peliruudukolle metodit public void siirraYlos(), joka siirtää jokaisen rivin palat ylös, ja public void siirraAlas(), joka siirtää jokaisen rivin palat alas. Metodi yhdistää tarvittaessa myös samanarvoiset muuttujat.
Siirrä vasemmalle ja pelin loppuminen
Tee seuraavaksi peliruudukolle metodi public void siirraVasemmalle(), joka siirtää jokaisen rivin palat vasemmalle. Kun metodi siirraVasemmalle on valmis, toteuta sovellukseen metodi public boolean peliKaynnissa(), joka palauttaa tiedon pelin jatkumisesta.
Peli jatkuu jos (1) pelissä on yksikin ruutu, jossa on arvo 0, tai (2) kaksi pelin vierekkaista (vaaka- tai pystytasossa) ruutua ovat samanarvoiset.
Tekstikayttoliittyma ja uuden luvun arpominen
Tee lopulta pelille tekstikäyttöliittymä. Pelin tulee käynnistyä kun luokassa Peli olevaa main-metodia kutsutaan. Pelaajalle tulee tarjota vaihtoehdot o, v, y, a, x, missä o on oikealle, v on vasemmalle, y on ylös, a on alas, ja x on lopeta. Jokaisen siirron -- paitsi pelin lopettavan x:n -- jälkeen taulukon satunnaiseen tyhjään kohtaan tulee lisätä luku 1. Alla on esimerkki tekstikäyttöliittymän toiminnasta.
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 > o 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 > y 0 0 0 2 1 0 0 0 0 0 0 0 0 0 0 0 > v 2 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 > o 0 0 2 1 0 0 0 1 0 1 0 0 0 0 0 0 > y 0 1 2 2 0 0 0 0 0 0 0 0 0 0 1 0 > o 0 0 1 4 0 0 0 0 0 0 0 1 0 0 0 1 > x