Tehtävät viikolle 3

Pakolliset tehtävät on merkitty harmalla taustavärillä. Punaisella taustavärillä merkatut ovat kontrollitehtäviä, jotka näytetään ohjaajalle harjoitustilaisuudessa!

HUOM: nimeä tiedostot otsikossa olevan sanan mukaan

Aakkoset

A

Toteuta luokka A, joka tulostaa konstruktorissaan tekstin Luokan A konstruktori!. Lisäksi luokalla on metodi String a(), joka palauttaa tekstin "a".

public class Aakkoset {

   public static void main(String[] args) {

       A a = new A();
       System.out.println("---");

       System.out.println(a.a());

   }

}	

Ohjelma tulostaa:

Luokan A konstruktori!
---
a

Ab

Toteuta luokka Ab, joka tulostaa konstruktorissaan tekstin Luokan Ab konstruktori!. Lisäksi luokalla on metodi String b(), joka palauttaa tekstin "b".

Luokka Ab perii luokan A. Toteuta konstuktori siten, että ensin kutsutaan yläluokan konstuktoria ja sitten vasta tulostetaan oma teksti.

public class Aakkoset {

    public static void main(String[] args) {

        A a = new A();
        System.out.println("---");

        Ab ab = new Ab();
        System.out.println("---");


        System.out.println(a.a());

        System.out.print(ab.a());
        System.out.println(ab.b());

    }

}	
Luokan A konstruktori!
---
Luokan A konstruktori!
Luokan Ab konstruktori!
---
a
ab

Abc

Toteuta luokka Abc samalla tavalla. Käytä oheista testiohjelmaa ja varmista, että tulostus on oikein.

public class Aakkoset {

    public static void main(String[] args) {

        A a = new A();
        System.out.println("---");

        Ab ab = new Ab();
        System.out.println("---");

        Abc abc = new Abc();
        System.out.println("---");



        System.out.println(a.a());

        System.out.print(ab.a());
        System.out.println(ab.b());

        System.out.print(abc.a());
        System.out.print(abc.b());
        System.out.println(abc.c());

    }

}
Luokan A konstruktori!
---
Luokan A konstruktori!
Luokan Ab konstuktori!
---
Luokan A konstruktori!
Luokan Ab konstuktori!
Luokan Abc konstruktori!
---
a
ab
abc

Sillanrakentaja

Rajapinta Laskuri

Lisää projektiin rajapinta Laskuri.

public interface Laskuri {
	public void kasvataArvoa();
	public void vahennaArvoa();
	public int getArvo();
}

Silta ja Testaaja

Toteuta luokka Silta, joka tietää pituutensa kokonaislukuna. Lisäksi lisää projektiin luokka Testaaja.

Seuraavat testit käyttävät luokkaa Testaaja. Tehtävää tehdessä varmista, että Testaaja.onkoValmis(); on aina pääohjelman viimeinen rivi.

Silta s = new Silta(10);

if (s.getPituus() != 10)
    Testaaja.virhe("Pituus ei ole 10");

Testaaja.vaadiRajapinta(Silta.class, Laskuri.class);
Testaaja.tarkistaAttribuutit(Silta.class);

if (s.getArvo() != 0)
    Testaaja.virhe("Sillan arvo ei ole 0");

// Viimeinen rivi ohjelmassa
Testaaja.onkoValmis();

Onnistunut toteutus tuottaa seuraavan tulosteen:

--[ Testaaja ]---------------------------------
Ei virheitä, tehtävä valmis!

Rautatiesilta

Toteuta luokka Rautatiesilta, joka periytyy luokasta Silta.

Rautatiesilta rs = new Rautatiesilta(100);

if (rs.getPituus() != 100 )
    Testaaja.virhe("Pituus ei ole 100");

if (rs.getArvo() != 0)
    Testaaja.virhe("Laskuri ei palauta 0");

Testaaja.vaadiPerinta(rs, Silta.class);
Testaaja.tarkistaAttribuutit(Rautatiesilta.class);

Juna

Toteuta luokka Juna, joka tietää vaunujen määränsä kokonaislukuna

Juna pitkaJuna = new Juna(28);
Juna lyhytJuna = new Juna(10);

if (pitkaJuna.getVaunut() != 28)
    Testaaja.virhe("Pitkän junan vaunujen lukumäärä ei ole 28");

if (lyhytJuna.getVaunut() != 10)
    Testaaja.virhe("Lyhyen junan vaunujen lukumäärä ei ole 10");

Testaaja.tarkistaAttribuutit(Juna.class);

Juna ylittää sillan

Kun juna ylittää sillan, kasvaa sillan laskurin arvo ylittäneen junan vaunujen mukaan.

if (!pitkaJuna.ylita(rs))
    Testaaja.virhe("Pitkä juna ei ylita siltaa");

if (!lyhytJuna.ylita(rs))
    Testaaja.virhe("Lyhyt juna ei ylitä siltaa");

if (rs.getArvo() != 38 )
    Testaaja.virhe("Rautatiesillan ylittäneiden vaunujen määrä on: "+rs.getArvo()+", eikä ole 38, vaikka kaksi junaa (28 ja 10 vaunua) ylittivät sillan");

Maantiesilta

Toteuta luokka Maantiesilta, joka periytyy luokasta Silta.

Maantiesilta ms = new Maantiesilta(50);

if (ms.getPituus() != 50)
    Testaaja.virhe("Pituus ei ole 50");

Testaaja.vaadiPerinta(ms, Silta.class);
Testaaja.tarkistaAttribuutit(Maantiesilta.class);

Matti

Toteuta luokka Matti, joka tietää painonsa sukunimen char-arvon perusteella

Matti mattiP = new Matti('P');
Matti mattiV = new Matti('V');

if (mattiP.getPaino() != 80)
    Testaaja.virhe("Matti P:n paino ei ole 80");

if (mattiV.getPaino() != 86)
    Testaaja.virhe("Matti V:n paino ei ole 86");

Testaaja.tarkistaAttribuutit(Matti.class);

Matti ylittää sillan

Kun Matti ylittää maantiesillan, kasvaa sillan laskurin arvo kasvaa Matin painon mukaan.

	
if (!mattiP.ylita(ms) )
    Testaaja.virhe("Matti P. ei ylitä siltaa!");

if (!mattiV.ylita(ms) )
    Testaaja.virhe("Matti V. ei ylitä siltaa!");

if (ms.getArvo() != 166)
    Testaaja.virhe("Maantiesillan ylittänyt paino on: "+ms.getArvo()+", eikä 166");

Auto ja ylitys

Toteuta luokka Auto, joka ylittäessään siltaa kasvattaa arvoa aina tuhannella.

Auto audi = new Auto();

if (!audi.ylita(ms))
    Testaaja.virhe("Audi ei ylitä maantiesiltaa");

if (ms.getArvo() != 1166)
    Testaaja.virhe("Maantiesillan ylittänyt paino on: "+ms.getArvo()+", eikä 1166");	

Tilastot kuntoon

Pelaajalistan tulostus

Tee luokka Pelaaja, johon voidaan tallettaa pelaajan nimi, joukkue, maalimäärä, syöttömäärä ja plusmiinustieto.

Talleta seuraavat pelaajat ArrayList:iin

pisteporssi.add(new Pelaaja("Nicklas Backstrom", "WAS", 29, 60, 33));
pisteporssi.add(new Pelaaja("Marian Gaborik", "NYR", 37, 39, 8));
pisteporssi.add(new Pelaaja("Henrik Sedin", "VAN", 28, 71, 35));
pisteporssi.add(new Pelaaja("Sidney Crosby", "PIT", 45, 44, 8));
pisteporssi.add(new Pelaaja("Martn St.Louis", "TBL", 27, 60, -4));
pisteporssi.add(new Pelaaja("Steven Stamkos", "TBL", 43, 40, 0));
pisteporssi.add(new Pelaaja("Joe Thorton", "SJS", 19, 66, 16));
pisteporssi.add(new Pelaaja("Alexander Ovechkin", "WSH", 45, 53, 44));
pisteporssi.add(new Pelaaja("Patrick Kane", "NJD", 28, 54, 18));
pisteporssi.add(new Pelaaja("Brad Richards", "DAL", 21, 61, -13));

Tulosta pelaajalistan sisältö. Huomaa, että tulostukseen tulee mukaan myös kokonaispistemäärä eli maalien ja syöttöjen summa:

	
Nicklas Backstrom WAS 29+60 = 89 33
Marian Gaborik NYR 37+39 = 76 8
Henrik Sedin VAN 28+71 = 99 35
Sidney Crosby PIT 45+44 = 89 8
Martn St.Louis TBL 27+60 = 87 -4
Steven Stamkos TBL 43+40 = 83 0
Joe Thorton SJS 19+66 = 85 16
Alexander Ovechkin WSH 45+53 = 98 44
Patrick Kane NJD 28+54 = 82 18
Brad Richards DAL 21+61 = 82 -13

Pistepörssin tulostus

Lisää luokalle Pelaaja rajapinta Comparable<Pelaaja>, jonka avulla pelaajat voidaan järjestää kokonaispistemäärän mukaiseen järjestykseen. Järjestä pelaajat Collections-luokan avulla ja tulosta pistepörssi:

NHL pistepörssi
1. Henrik Sedin VAN 28+71 = 99 35
2. Alexander Ovechkin WSH 45+53 = 98 44
3. Nicklas Backstrom WAS 29+60 = 89 33
4. Sidney Crosby PIT 45+44 = 89 8
5. Martn St.Louis TBL 27+60 = 87 -4
6. Joe Thorton SJS 19+66 = 85 16
7. Steven Stamkos TBL 43+40 = 83 0
8. Patrick Kane NJD 28+54 = 82 18
9. Brad Richards DAL 21+61 = 82 -13
10. Marian Gaborik NYR 37+39 = 76 8

Ohjeita tähän tehtävään viime viikon materiaalissa.

Maali ja syöttöpörssi, plusmiinustilasto

Haluamme tulostaa myös maalintekijäpörssin eli pelaajien tiedot maalimäärän mukaan järjestettynä sekä syöttöpörssin ja plusmiinustilaston. NHL:n kotisivu tarjoaa tämänkaltaisen toiminnallisuuden, eli selaimessa näytettävä lista on mahdollista saada järjestettyä halutun kriteerin mukaan.

Edellinen tehtävä määritteli pelaajien suuruusjärjestyksen perustuvan kokonaispistemäärään. Luokalla voi olla vain yksi compareTo-metodi, joten joudumme muunlaisia järjestyksiä saadaksemme turvautumaan muihin keinoihin.

Vaihtoehtoiset järjestämistavat toteutetaan erillisten luokkien avulla. Pelaajien vaihtoehtoisten järjestyksen määräävän luokkien tulee toteuttaa Comparator<Pelaaja>-rajapinta. Järjestyksen määräävällä luokalla on ainoastaan yksi metodi compareTo(Pelaaja p1, Pelaaja p2), jonka tulee palauttaa negatiivinen arvo, jos p1 on järjestyksessä ennen p2:sta, positiivinen arvo jos p2 on järjestyksessä ennen p1:stä ja 0 muuten.

Periaatteena on luoda jokaista järjestämistapaa varten oma vertailuluokka, esim. maalipörssin järjestyksen määrittelevä luokka:

import java.util.Comparator;
 
public class Maali implements Comparator<Pelaaja> {
  public int compare(Pelaaja p1, Pelaaja p2) {
    // koodi tänne
  }
}

Järjestäminen tapahtuu edelleen luokan Collections metodin sort avulla. Metodi saa nyt toiseksi parametrikseen järjestyksen määräävän luokan olion:

Maali maalintekijat = new Maali();
Collections.sort(pisteporssi, maalintekijat);
System.out.println("\nNHL parhaat maalintekijät");
tulosta(pisteporssi);

Järjestyksen määrittelevä olio voidaan luoda suoraan sort-kutsun yhteydessä:

Collections.sort(pisteporssi, new Maali());
System.out.println("\nNHL parhaat maalintekijät");
tulosta(pisteporssi);

Kun sort-metodi saa järjestyksen määrittelevän olion parametrina, se käyttää olion compareTo()-metodia pelaajia järjestäessään.

Tarkempia ohjeita vertailuluokkien tekemiseen täällä

Tee seuraaviin tilanteisiin sopivat vertailufunktiot ja tulosta tilastot ohjelmassasi:

NHL parhaat maalintekijät
1. Alexander Ovechkin WSH 45+53 = 98 44
2. Sidney Crosby PIT 45+44 = 89 8
3. Steven Stamkos TBL 43+40 = 83 0
4. Marian Gaborik NYR 37+39 = 76 8
5. Nicklas Backstrom WAS 29+60 = 89 33
6. Henrik Sedin VAN 28+71 = 99 35
7. Patrick Kane NJD 28+54 = 82 18
8. Martn St.Louis TBL 27+60 = 87 -4
9. Brad Richards DAL 21+61 = 82 -13
10. Joe Thorton SJS 19+66 = 85 16

NHL eniten syöttöjä
1. Alexander Ovechkin WSH 45+53 = 98 44
2. Sidney Crosby PIT 45+44 = 89 8
3. Steven Stamkos TBL 43+40 = 83 0
4. Marian Gaborik NYR 37+39 = 76 8
5. Nicklas Backstrom WAS 29+60 = 89 33
6. Henrik Sedin VAN 28+71 = 99 35
7. Patrick Kane NJD 28+54 = 82 18
8. Martn St.Louis TBL 27+60 = 87 -4
9. Brad Richards DAL 21+61 = 82 -13
10. Joe Thorton SJS 19+66 = 85 16

NHL plusmiinustilasto
1. Alexander Ovechkin WSH 45+53 = 98 44
2. Henrik Sedin VAN 28+71 = 99 35
3. Nicklas Backstrom WAS 29+60 = 89 33
4. Patrick Kane NJD 28+54 = 82 18
5. Joe Thorton SJS 19+66 = 85 16
6. Sidney Crosby PIT 45+44 = 89 8
7. Marian Gaborik NYR 37+39 = 76 8
8. Steven Stamkos TBL 43+40 = 83 0
9. Martn St.Louis TBL 27+60 = 87 -4
10. Brad Richards DAL 21+61 = 82 -13

Pelaajatietojen lukeminen tiedostosta

Haluamme ohjelmaamme seuraavien pelaajien tiedot:

 Henrik Sedin       VAN 74 28 71 99  35
 Alex Ovetshkin     WSH 64 45 53 98  44
 Sidney Crosby      PIT 73 45 44 89   8
 Nicklas Backstrom  WSH 74 29 60 89  33
 Martin St.Louis    TBL 74 27 60 87  -4
 Steven Stamkos     TBL 74 45 41 86   0
 Joe Thornton       SJS 74 19 66 85  16
 Patrick Kane       CHI 73 28 54 82  18
 Brad Richards      DAL 72 21 61 82 -13
 Marian Gaborik     NYR 68 39 40 79  10
 Patrick Marleau    SJS 74 41 35 76  18
 Dany Heatley       SJS 74 38 37 75  13
 Anze Kopitar       LAK 73 33 42 75   4
 Ilja Kovaltshuk    NJD 67 38 37 75   6
 Daniel Sedin       VAN 56 22 52 74  34
 Aleksander Semin   WSH 65 35 38 73  29
 Zach Parise        NJD 72 35 38 73  21
 Paul Stastny       COL 73 18 55 73   8
 Mike Green         WSH 69 17 54 71  33
 Corey Perry        ANA 74 26 44 70   0
 

Tietojen syöttäminen käsin on hankalaa. Luo tiedosto, johon copypastaat pelaajalistan. Lue tiedosto ohjelmassasi ja luo jokaiselle pelaajalle oma olio. Listalla ensimmäinen luku on pelaajan ottelumäärä. Sitä, eikä toiseksi viimeistä (kokonaispistemäärä) ei oteta mukaan pelaajaolioita luotaessa.

Tiedoston lukeminen kannattaa hoitaa kahden eri metodin avulla. Metodilla next() voidaan lukea tiedoston seuraava merkkijono joka rajoittuu välilyöntiin, tabulaattoriin tai enteriin. Metodilla nextInt() voidaan lukea tiedostossa olevat kokonaisluvut.

Tiedoston jokainen rivi on samanlainen: String String String int int int int int, joten kutsumalla metodeita next() ja nextInt() riviltä on helppo lukea oikeat tiedot. Metodilla hasNext() voidaan testata pitääkö tiedoston lukemista vielä jatkaa:

Scanner lukija = lukija = new Scanner(new File("pelaajat.txt"));
while ( lukija.hasNext() ){ // vieläkö jatketaan
    String nimi = lukija.next()+" "+lukija.next();
    String joukkue = lukija.next();
    lukija.nextInt();   // hypätään ottelumäärän yli
    int maalit = lukija.nextInt();
    int syotot = lukija.nextInt();
    lukija.nextInt();   // hypätään kokonaispistemäärän yli yli
    int plusMinus = lukija.nextInt();
    pisteporssi.add(new Pelaaja(nimi, joukkue, maalit, syotot, plusMinus));
}

Lue tiedostosta pelaajatiedot ja tulosta pistepörssi, maalipörssi, syöttöpörssi ja plusmiinustilasto.

Olutmuistioiden lukeminen tiedostosta

Olemme viime viikkoina toteuttaneet olutmuistiot, jotka syötetään käsin. Lisätään tässä tehtävässä olutmuistioihin toiminnallisuutta, joka mahdollistaa niiden lukemisen tiedostosta.

Olutmuistiot on tallennettu seuraavassa muodossa tiedostoon. Voit copy-pasteta seuraavan tekstin omaan tiedostoon.

Matti L
Stone Brewery: Arrogant Bastard Ale
Ballast Point: Panzer Imperial Pils

Matti P
Celebration Ale

Matti V
Franzis Kristal Weissbier
Paderborner Pilsener

Toteuta seuraavat tehtävät lisänä ensimmäisellä viikolla olleeseen olutmuistioon. Kun olutmuistiot on luettu, voidaan uusia vielä luoda.

Olutmuistioiden omistajat

Luo olutmuistioiden omistajat tiedostoa lukemalla. Ylläolevalla tiedostolla luodaan kolme olutmuistiota, joiden omistajat ovat "Matti L", "Matti P" ja "Matti V". Olutmuistioiden tulostuksen pitäisi näyttää tässä vaiheessa seuraavalta:

Alkuperäiset muistiot:
Olutmuistion omistaja: Matti L
Oluita yhteensa 0 kpl

Olutmuistion omistaja: Matti P
Oluita yhteensa 0 kpl

Olutmuistion omistaja: Matti V
Oluita yhteensa 0 kpl

Lisätään muistioita
Anna muistion omistaja: 
...

Oluet olutmuistioihin

Muokkaa edellistä toteutusta siten, että olutmuistioihin luetaan myös juodut oluet. Tulostuksen tulee olla muutoksen jälkeen seuraavanlainen:

Alkuperäiset muistiot:
Olutmuistion omistaja: Matti L
Oluita yhteensa 2 kpl
  Stone Brewery: Arrogant Bastard Ale
  Ballast Point: Panzer Imperial Pils

Olutmuistion omistaja: Matti P
Oluita yhteensa 1 kpl
  Celebration Ale

Olutmuistion omistaja: Matti V
Oluita yhteensa 2 kpl
  Franzis Kristal Weissbier
  Paderborner Pilsener
  
Lisätään muistioita
Anna muistion omistaja: 
...

MunString

MunString

Toteutaan oma yksinkertainen String-luokka: MunString

Vinkki toString()-metodiin: Stringin voi luoda char-taulukosta new String(chartaulukko).

Testiohjelma:

MunString tervehdys = new MunString("Kokeillaan MunStringia");
MunString lisays = new MunString(", lisäkokeilu.");

MunString kymmenen = new MunString("0123456789");

System.out.println("tervehdys: " + tervehdys);
System.out.println("   pituus: " + tervehdys.length());
System.out.println("   kolmas: " + tervehdys.charAt(2));

tervehdys.lisaa(lisays);
                                
System.out.println("tervehdys: " + tervehdys);

tervehdys.lisaa(kymmenen);
tervehdys.lisaa(kymmenen);
tervehdys.lisaa(kymmenen);
tervehdys.lisaa(kymmenen);
tervehdys.lisaa(kymmenen);
tervehdys.lisaa(kymmenen);
tervehdys.lisaa(kymmenen);
tervehdys.lisaa(kymmenen);
tervehdys.lisaa(kymmenen);
tervehdys.lisaa(kymmenen);
tervehdys.lisaa(kymmenen);
tervehdys.lisaa(kymmenen);
tervehdys.lisaa(kymmenen);


System.out.println("tervehdys: " + tervehdys);
System.out.println("   pituus: " + tervehdys.length());

Tulostus

tervehdys: Kokeillaan MunStringia
   pituus: 22
   kolmas: k
tervehdys: Kokeillaan MunStringia, lisäkokeilu.
tervehdys: Kokeillaan MunStringia, lisäkokeilu.012345678901234567890123456789012345678901234567890123456789
   pituus: 96

Sokkelo jatkuu

Muokataan olemassaolevaa toteutustamme. Jos et ole tehnyt Sokkelo-tehtäviä tähän mennessä, tutustu viimeisen viikon mallivastauksiin!

Esine

Luokalla Esine on sijainti, ja se toteuttaa viime viikolla nähdyn Sijaitseva-rajapinnan. Muuta viime viikon Sijaitseva-rajapintaa siten, että se toteuttaa tällä viikolla nähdyt get- ja set-nimeämissäännöt. Toteuta luokka Esine. Peri myös luokka Aarre luokasta Esine.

Hahmo

Luokka Hahmo perii luokan Esine, ja lisää sinne liikkumistoiminnallisuuden. Luokalla Hahmo on siis metodi liiku(), jolla hahmoa voi liikuttaa. Toteuta luokka Hahmo. Peri luokat Morko ja Pelaaja luokasta Hahmo.

Reitti pelaajan luo

Mörkömme on tähän asti vain kävellyt sokkelossa satunnaisesti. Muutetaan mörön liikkumistoimintoa siten, että se pyrkii pelaajaa kohti. Mörkö tietää pelaajan sijainnin Sokkelo-olion avulla.

Muuta mörön liiku()-metodia siten, että se pyrkii aina pelaajaa kohti. Jos mörön ja pelaajan etäisyys toisistaan on suurempi y-akselilla kuin x-akselilla, pyri liikkumaan y-akselilla, muulloin x-akselilla. Alla olevissa tilanteissa ensimmäisessä mörön kannattaa liikkua vasemmalle, kun taas toisessa ylös.

O


  M
O

     M

Kannattaa tutkia haluttua liikkumissuuntaa mörön ja pelaajan x- ja y-koordinaattien erotuksena.

Portaali

Lisätään kartalle vielä portaali, mihin kävelemällä pelaaja päätyy toisen portaalin sijaintiin. Portaali merkitään numerolla 4 kartalle.

int[][] taulukko = {
  {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
  {1, 2, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 4, 1, 0, 1, 0, 0, 1, 1},
  {1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1},
  {1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1},
  {1, 0, 1, 3, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1},
  {1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1},
  {1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, -1},
  {1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1},
  {1, 4, 1, 0, 0, 99, 1, 0, 1, 3, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1},
  {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
};

Toteuta portaali-toiminnallisuus. Jos portaaleja on enemmän kuin kaksi, portaali mihin päädytään arvotaan portaalien joukosta.