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

(Tää näyttää nyt vähän häröltä, kun kesäopen kotitietokoneesta tuli kahvinkeitin takuumiesten poistuttua virtalähteen tuulettimesta. Savun hälvettyä tarkastamme kytkennät ja katsomme, onko paluuta kotitietokoneen käyttöön opetuksessa.)

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

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

Kaikkiin lähdekoodeihin Sunin suosituksen mukainen asemointi ja javadoc-kommentit: vähintään yksi lause yleiskuvausta jokaiselle luokalle ja metodille sekä kentät @author, @version (luokille) ja @param, @return (metodeille). Näiden lisäksi saa etsiä omaa keskitietään kommentoinnin määrässä...

Perustehtävät

1:

(Javan kielioppi, ohjelman suoritus)

Mitä ovat muuttujien arvot seuraavien ohjelmanpätkien jälkeen? Sisennä (ja selvennä) ohjelmanpätkät "oikein"!

/* 1 */
a=4; b=2; c=0;
if ( a-b != 0 ) c++; a=1;
b=3;

/* 2 */
a=4; b=2; c=0;
if ( c != 0 )
c--; else b=1;
a = b-2;

/* 3 */
a=4; b=2; c=0;
if ( a > 0 ) if ( b > 1 )
  c=9;
else if ( c == 1 ) ;
else b = 0;
a = 3;

/* 4 */
a=4; b=2; c=0;
if ( c++ != 0 ) if ( a-- != 0);
else b-=3; else c+=8;
2:

(Päivän pöytätesti; Javan bittioperaattorit)

Selvitä pöytätestillä, mitä tapahtuu seuraavassa ohjelmanpätkässä:

/* 01 */  int a=23, b=13, c=17;
/* 02 */  char m = 'b';
/* 03 */  if ( ( a = b ) != 0 ) c+=0x0f;
/* 04 */  if ( ( a & ~b ) != 0 ) c--;
/* 05 */  m ^= 1 << 5;
/* 06 */  if (m == 'B') b &= c;
/* 07 */  System.out.print("a=" + a + " b=" + b + " c=" + c + " m=" + m);
3:

(Ohjelmakoodin yleistämisharjoite; taulukon käyttö)

Viime viikon guru-tehtävän mallivastauksessa pelin voitto tarkistetaan "copy-paste"-koodilla, mikä on yleensä huono asia. Toteuta vastaava tarkistus yhteen metodiin, jonka esittely on seuraava:

int montakoJonossa(int row, int col, int rowPlus, int colPlus)

tarkoittaen sitä, että aloitetaan kohdasta [row][col] ja edetään askelilla rowPlus ja colPlus taulukkoa eteenpäin ja vastakkaiseen suuntaan. Käyttö kutsuvassa ohjelmassa siis tähän tapaan:

if ((montakoJonossa(rivi,sarake,1,0) >= voittorivi)
        || (montakoJonossa(rivi,sarake,0,1) >= voittorivi)
        || (montakoJonossa(rivi,sarake,1,1) >= voittorivi)
        || (montakoJonossa(rivi,sarake,1,-1) >= voittorivi))
    voittaja = pelaaja;

En väitä, että mallivastaus ylipäätään on lähellä järkevintä tapaa toteuttaa kyseinen peli :-)

4:

(Ohjelmakoodin yleistämistä vielä)

Olipa kerran Korppi-järjestelmä, jonka koodissa oli kymmenittäin seuraavanlaisia riviyhdistelmiä:

String beginHour = request.getParameter("beginHour");
String endHour = request.getParameter("endHour");
if (beginHour == null) beginHour="";
if (endHour == null) endHour="";

Ohjelmoi uudelleen siten, että rivimäärä puolittuu alkuperäisestä (jos siis on kymmennittäin vastaavia neljän rivin pätkiä). (request viittaa HttpServletRequest-luokan olioon).

5:

(Oliosuunnittelua)

Mallinna olioluokkina shakkinappulat ja pelilauta. Tee jokaisesta nappulatyypistä (sotilas, ratsu, lähetti...) eri aliluokka. Mieti, mikä olisi pelaamisen kannalta hyvä rajapinta kaikille nappuloille (=yliluokan rajapinta). Mitkä ominaisuudet pitäisi toteuttaa eri tavoin perityille, eriytetyille nappulatyypeille. Millainen konstruktori nappulalla voisi olla, ja millaisia attribuutteja/metodeja. Miten lauta-olio suhtautuisi nappulaolioihin?

(Ei tarvitse ohjelmoida. Nyt suunnitellaan.)

6:

(Olioiden toteutusta)

Muuta edellisen demon vastausta Henkilo.java seuraavasti:

  • lisää metodi toString, joka palauttaa henkilön tiedot tolppamerkeillä | erotetussa muodossa.
  • lisää metodi parse, joka selvittää henkilön tiedot tolppa-erotetusta muodosta.

Toiminta lisäysten jälkeen:

hlo.parse("Mister|Lordi|1974");
hlo.tulosta();
System.out.println(hlo);  // kutsuu hlo.toString();

Tulostaisi:

Mister Lordi 1974
Mister|Lordi|1974
7:

(Olioiden toteutusta)

Esittele luokka, jolla kuvataan päivämäärä. Kirjoita ainakin sopiva muodostaja ja metodi toString, jolla päivämäärä saadaan merkkijonoksi. Tee myös testipääohjelma.

8-9:

(Oman harjoitustyön vaihe 4)

Toteuta harjoitustyösi vaihe 4, eli etsi tarvittavat oliot ja suunnittele niiden välinen yhteistyö: mikä luokka hoitaa mitäkin tehtäviä, mitä muita luokkia se tarvitsee avuksi. Erityisesti: kun luokista on tehty olioita, millaisia viitteitä ja kuinka paljon mikäkin olio tarvitsee toisiin olioihin. Nimeä luokat oman sovelluksesi mukaisesti. Ompelutarviketietokannassa voisi olla luokkia Lanka, Neula, Ompelutarvikkeisto sekä metodeja kuten Lanka.getVäri() jne. Sovella. Ja se käyttöliittymähän me halutaan omaksi luokakseen joka tapauksessa...

Luokkasuunnitelmaksi käy UML-notaatio tai CRC-kortit (käydään läpi luennoilla tällä viikolla). Lisäksi (ehdottomasti) piirtele myös oliokaaviot, joissa suorituksenaikaiset viitteet näkyvät. Tällainen on suunnittelussa tarpeen, vaikkei se silmiinpistävästi sisälly UML- tai CRC-menetelmiin.

Mallia voit ottaa malliharjoitustyön vaiheesta 4. Tarkastele erityisesti kuvaa suorituksenaikaisista olioista ja mieti mitä vastaavaa omaan harkkaan tarvitaan. Harjoituksen vuoksi teemme ohjelmat niin, että suorituksen aikana koko tietorakenne on olioina koneen muistissa; levyllä pidetään "jäädytettyä" versiota, joka tallennetaan/ladataan ohjelman sulkemisen/käynnistyksen yhteydessä.

Bonusosio

Nyt on vähän helppoja bonustehtäviä...

B1:

(Math)

Toteuta yleinen noppaluokka, josta voi instantoida 4-sivuisen, 6-sivuisen, 8-sivuisen ja niin edelleen (tietotekniikan vapauttamana myös vaikkapa "7-sivuisen") nopan. Toteuta metodi heitä, joka arpoo yhden kokonaisluvun väliltä 1-N, missä N on noppailmentymän tahkojen määrä. Toteuta myös int[] heitäSarja(int montako) joka heittää parametrilla montako annettavan määrän peräkkäisiä heittoja ja palauttaa niistä taulukon. Tee pääohjelma, joka sata kertaa laskee monennellako heitolla tulee ykkösjatsi (Sarja 1-1-1-1-1 nopalla jossa on 6 tahkoa), ja laskee lukumääristä keskiarvon.

B2-3:

(liukuluvut, oliot)

Suunittele ja toteuta Vali-tyyppi (eli luokka), joka tallettaa suljetun reaalilukuvälin. Kirjoita metodit kysy ja compareTo(vali). kysy kelpuuttaa seuraavat syötöt:

Anna väli (0-5) >[ret]       => 0-5
Anna väli (0-5) >3[ret}      => 3-3
Anna väli (0-5) >3-[ret]     => 3-5
Anna väli (0-5) >-3[ret]     => 0-3
Anna väli (0-5) >1-3[ret]    => 1-3

Testiohjelma kysyy kaksi väliä ja sitten compareTo palauttaa tiedon siitä osuuko toinen väli itse olioon. Testiohjelma voisi olla esimerkiksi:

public static void main(String[] args)  {
  Vali v1 = new Vali(1,3), v2 = new Vali(2,4);
  v1.kysy(); v2.kysy();
  System.out.println(v1); System.out.println(v2);
  int osuman_laatu = v1.compareTo(v2); // vastaa "vähennyslaskua" ol = v1 - v2;
  if ( osuman_laatu == 0 )
    System.out.println("Välit osuvat toisiinsa");
  else if ( osuman_laatu == 1 )
    System.out.println("Jälkimmäisen välin arvot pienempiä kuin ensimmäisen!");
  else if ( osuman_laatu == -1 )
    System.out.println("Jälkimmäisen välin arvot suurempia kuin ensimmäisen!");
}

Pohdi onko mielekästä, että compareTo palauttaa 0 jos välit osuvat toisiinsa. Vihje: Piirrä kuva, miten kaksi väliä käyttäytyy toisiinsa nähden.

G1:

(liukuluvut, oliot)

Lisää tehtävään B2-3 vielä tarvittavat metodit ja määrittele tyhjä väli, jotta seuraavat kutsut toimivat:

Vali v3 = v1.leikkaus(v2);
System.out.println(v3);
if ( v1.leikkaus(v2) == tyhja )
  System.out.println("Välit eivät osu");

Voitaisiinko tehdä välien yhdiste ja mitä ongelmia siitä seuraisi?