Ohjelmointi 2 -- kesä 2006 -- Demo 6/11

Demonumero:6/11
Palautus:tiistaina 13.6.2006 klo 18 mennessä.
Laskennallinen tehtävämäärä:
 9 kpl.
Pisteitä saa korkeintaan:
 11 kpl.

(esim. 12 tehtyä kohtaa -> 11 pistettä Korppiin)

1:

(Oliot, kapselointi)

Kirjoita luokkaan Pvm (tehtäväpaperin lopussa) saantimetodit päivälle, kuukausille ja vuosille.

2:

(Oliot, keskinäinen vertailu)

Kirjoita tavallinen funktio (siis staattinen metodi) compareTo(pv1,pv2), joka palauttaa -1, mikäli päivämäärä pv1 on ennen päivämäärää pv2, 0 jos päivämäärät ovat samoja ja 1 muuten (pv1 ja pv2 ovat tyyppiä Pvm, tarvitseeko luokka Pvm muutoksia jos staattinen metodi compareTo siirrettäisiin toisessa tiedostossa olevaan luokkaan?).

3:

(Oliot, keskinäinen vertailu)

Tee edellistä funktiota vastaava metodi, eli lisää päivämäärä-luokkaan Pvm metodi compareTo(pv2), joka palauttaa kuten edellä (-1,0 tai 1) kun verrataan oliota itseään ja päivämäärää pv2. Lisää nyt vielä equals-metodi. (Huom! jos et osannut 1&2. tehtävää, voi tämän tehdä silti).

// Käyttöesimerkki 2&3:een kun compareTo-metodit ovat Pvm-luokassa
Pvm pv1 = new Pvm(1,2),pv2 = new Pvm(3,3);
if ( compareTo(pv1,pv2) < 0 ) System.out.println(pv1 + " < " + pv2);
if ( pv1.compareTo(pv2) != 0 ) System.out.println(pv1 + " != " + pv2);
4:

(Oliot, perintä)

Kirjoita yliluokka Fani, jolla on metodit kannata ja mollaa jotka tulostavat tekstiä parametrina annettavaan virtaan. Toteuta perimällä erilaiset fanit siten, että seuraava pääohjelma:

public class FaniTesti{
    public static void main(String[] args){
        BrittiFani f1 = new BrittiFani("John");
        RuotsiFani f2 = new RuotsiFani("Birgit");
        SaksaFani  f3 = new SaksaFani("Jürgen");
        SuomiFani  f4 = new SuomiFani("Velmu Virtanen");

        f1.kannata(System.out);
        f2.kannata(System.out);

        f1.nauti();

        f1.mollaa(System.out);
        f2.mollaa(System.out);

        f3.kannata(System.out);
        f4.kannata(System.out);
    }
}

tulostaa:

John (0.0 promillea): Go, go!
Birgit (0.0 promillea): Heja!
John (0.5 promillea): [raivokas vihellys]
Birgit (0.0 promillea): [raivokas vihellys]
Jürgen (0.0 promillea): Bravo Podolski!
Velmu Virtanen (1.5 promillea): Hard rock hallelujah!
5:

(Oliot, poikkeukset)

Toteuta luokka FaniKatsomo, jossa:

  • on polymorfinen taulukko Faneista
  • on metodi lisaaFani
  • heitetaan poikkeus KatsomoTaynnaException jos ei mahtunut enempaa katsojia.
  • on metodi meteli, jossa jokainen katsoja kannustaa kertaalleen ohjelman ulostulovirtaan.

Toteuta pääohjelma, jossa laitetaan katsomoon 7 erimaalaista ja erinimistä fania ja kutsutaan kertaalleen metodia meteli.

6:

(oliot, rajapinta)

Toteuta tehtävän 4 erimaalaiset fanit rajapinnan (eli Javan interfacen) avulla eikä perimällä. Toteuta myös polymorfinen katsomo siten, että katsomoon tulee rajapinnan FaniRajapinta toteuttavia faneja. Huomaa, että pääohjelmat eivät tarvitse muutoksia.

Mitä rajapinnalla voittaa? Mitä häviää?

Lisää vielä kummassakin toteutustavassa jonkun muun maalainen fani.

7:

(Oliot, perintä)

Kirjoita luokka Kulkuneuvo, jossa on ainakin nopeus ja matkustajien lukumäärä. Peri tästä luokat Laiva ja Lentokone joissa kummassakin on jokin oma erikoisominaisuus yleiseen kulkuneuvoon verrattuna. Kirjoita myös pieni testipääohjelma.

8:

(Algoritmit)

Tee aliohjelma pienimman_paikka, joka palauttaa kokonaislukutaulukon pienimmän alkion paikan (indeksin). Esim. taulukosta:

>                 /* ta,he,ma,hu,to,ke,he,el,sy,lo,ma,jo */
>int k_pituudet[] = {31,28,31,30,31,30,31,31,30,31,30,31};
>
>i = pienimman_paikka(k_pituudet); /* => i=1 */

Tee edellistä aliohjelmaa käyttäen aliohjelma pienin, joka palauttaa kokonaislukutaulukon pienimman alkion arvon:

n = pienin(k_pituudet);         // => n = 28 
9:

(Algoritmeja)

Monisteen luvussa 10.5.2 on esimerkki funktiosta postimaksu. Tee tätä matkien funktio suurin_kirjeen_paino, joka palauttaa suuriman kirjeen painon, jonka voi lähettää tietyllä rahasummalla. Toteuta näytön vuoksi kahdella eri tavalla: if-ehtoja käyttämällä sekä taulukkoa käyttäen. Pyri saamaan postimaksuhinnaston muuttaminen mahdollisimman helpoksi. Kummassa tavassa se on helpompaa?

Bonus-osio

[Bonus-tehtävät tulevat taas jälkijunassa. Koetan keksiä jotain mielekkäitä...]

:B1-3: (Vanhan koodin korjailua)

Korjaa pudottelupeliä (mallivastauksen tiedostot
http://www.cc.jyu.fi/~nieminen/oh2/demot/demo4/malli/index.html) 
seuraavin tavoin:

  - Refaktoroi siten, että peliä hoitavan luokan nimeksi tulee ``Pudottelupeli``
    eikä ``Pelialue``

  - ``Pudottelupeli``n vastuulle tuntea pelitilanne, eli kumpi pelaaja on vuorossa
    vai voittiko jompikumpi vai onko taulu täynnä (tasapeli).

  - konstruktoriin parametriksi pelaajien määrä

  - konstruktorista sopivien poikkeusten heitto, jos parametrit ovat 
    järjettömiä tai ylittävät määräämäsi kapasiteetin (esim. pelaajien määrä)

  - ``pudota`` -metodi pudottamaan aina kulloinkin vuorossa olevan pelaajan
    nappula.

  - Saantimetodit pelitilanteelle siten, että käyttöliittymän hoito voi 
    tapahtua niitä käyttäen toisaalla.

  - Pääohjelmasta pelitilanteen tietäminen pois, ja käytetään 
    ``Pudottelupelin`` saantimetodeja.

  - Voiton tarkistusmetodi käyttämään edellisen demon mallivastausta, 
    joka on `tämän linkin päässä <http://www.cc.jyu.fi/~nieminen/oh2/malli6.txt>`_.

  - saantimetodi taulukon alkioille, jotta luokan 
    käyttäjä voisi halutessaan tehdä tulosteesta erinäköisen
    tai vaikka graafisen (ilman perintää tai alkuperäisen lähdekoodin muokkausta)

  - muuta luokka siten, että sitä voisi sopivassa määrin laajentaa perimällä. 
    (kiinnitä huomiota mm. suojaustasoihin)

Muista testata toimivuus! Tee yksi pieni muutos kerrallaan, 
ja sitten taas kääntäminen ja toimivuuden testaus. Sehän on 
pääsääntö aina...

Pvm -listaus

Pvm.java:

import fi.jyu.mit.ohj2.*;

/**
 * Alustava luokka päivämäärää varten
 * @author Vesa Lappalainen
 * @version 1.0, 07.02.2003
 */
public class Pvm {
  private int pv,kk,vv;

  public void paivays() { pv = 17; kk = 2; vv = 2003; }

  public void alusta(int pv, int kk, int vv) {
    paivays();
    if ( pv > 0 ) this.pv = pv;
    if ( kk > 0 ) this.kk = kk;
    if ( vv > 0 ) this.vv = vv;
    if ( this.vv < 50 ) this.vv += 2000;
    if ( this.vv < 100 ) this.vv += 1900;
  }

  public Pvm()                     { alusta(0,0,0);    }
  public Pvm(int pv)               { alusta(pv,0,0);   }
  public Pvm(int pv,int kk)        { alusta(pv,kk,0);  }
  public Pvm(int pv,int kk,int vv) { alusta(pv,kk,vv); }

  public String toString() {
    return pv + "." + kk + "." + vv;
  }

  public void parse(String s) {
    int p=0,k=0,v=0;
    StringBuffer sb = new StringBuffer(s);
    p = Mjonot.erotaInt(sb,0); Mjonot.erotaChar(sb,'.');
    k = Mjonot.erotaInt(sb,0); Mjonot.erotaChar(sb,'.');
    v = Mjonot.erotaInt(sb,0); Mjonot.erotaChar(sb,'.');
    alusta(p,k,v);
  }

  public static void main(String[] args)  {
    Pvm tammi2003 = new Pvm(1,1), maalis97 = new Pvm(1,3,97), tanaan = new Pvm();

    System.out.println(tammi2003 + " " + maalis97 + " " + tanaan);

    Pvm pvm = new Pvm();

    pvm.parse("12.1.1995"); System.out.println(pvm);
    pvm.parse("15.3");      System.out.println(pvm);
    pvm.parse("14");        System.out.println(pvm);
  }
}