581325-0 Ohjelmoinnin perusteet Koe 13.11.2000 Tehtävän 4 arvosteluperusteet ============================= Tehtävässä pyydettiin kirjoittamaan luokka Ehdokas ja tätä käyttävä ohjelma. Arvostelu on tämän vuoksi jaettu kahteen osaan: Ehdokas-luokan toteutuksen osuus on viisi pistettä ja ohjelman toteutuksen yhdeksän pistettä. Ehdokas-luokasta sai pisteitä seuraavin perustein: a) "kenttien määrittely" +2 Kaikki luokan kentät ovat yksityisiä (private). +1 Vain tehtävänannossa määritellyt kentät ovat yksityisiä, omat eivät. +1 Kaikki luokan kentät ovat yksityisiä, mutta vertailuluku ei ole double-tyyppiä. -1 Luokan kenttiä ei ole määritelty Java-kielen syntaksin mukaisesti tai kenttien määrittely puuttuu kokonaan. b) "aksessorit" +2 Luokka sisältää kaikille kentille aksessorit, myös vertailuluvulle. +1 Luokka sisältää joillekin kentille aksessorit, ei kaikille. +0 Luokka ei sisällä lainkaan aksessoreja. c) "syötteen tarkistus" +2 Luokka tarkistaa syöttöarvot. Virheelliset arvot ilmaistaan palauttamalla totuusarvo tai tietty int-lukuarvo jostakin metodista. +0 Syöttöarvot tarkistetaan, mutta virhetilanteissa luokka kommunikoi suoraan käyttäjän kanssa. +0 Syöttöarvoja yritetään tarkistaa, mutta invariantit ovat väärin koodattu. -1 Syöttöarvoja ei tarkisteta tai tarkistukset ovat huomattavan puuttelliset. -1 Syöttöarvot tarkistetaan, mutta virhetilanteissa niihin tehdään automaattisesti jotain korjauksia. Kohdista a, b ja c valitaan kuvauksen perusteella pienin pisteluku. Luvut lasketaan yhteen ja summasta huomioidaan korkeintaan viisi pistettä, alarajana on kuitenkin nolla pistettä. Tämä pisteytys pyrkii mittaamaan vastaajan oliomallinuksen taitoja. Luokan kenttien tulee olla yksityisiä jo siitä syystä, että tätä pyydettiin tehtävänannossa. Koska kentät ovat yksityisiä, niille tarvitaan aksessorit. Syöttöarvojen tarkistaminen pitää toteuttaa Ehdokas-luokassa, koska tehtävänannossa eri kentille oli määritelty ehtoja. Luokan on valvottava, että annettuja ehtoja noudatetaan, esimerkisi ehdokkaan nimi ei saanut olla tyhjä. Ehdokas-luokan arvostelu oli lempeä, sillä kohtien a, b ja c yhteenlaskettu pistemäärä on kuusi pistettä - kun tästä kuitenkin huomioidaan korkeintaan viisi, jokainen saa anteeksi yhden pisteen virheen. Tehtävän toinen osa, vaaliohjelma, arvosteltiin seuraavasti: Arvosteluun valittiin lähtökohta riippuen siitä, miten pitkälle vastauksessa oli toteutettu vaaliohjelmaa. Tämän jälkeen lähtöpisteisiin tehtiin vähennyksiä ohjelmassa esiintyneiden virheiden perusteella. Arvostelun lähtökohdaksi sai yhdeksän pistettä, jos ohjelma oli loppuun asti tehty ja valittu toteutusalgoritmi oli toimiva. Korkeintaan seitsemän pistettä sai, mikäli ohjelma oli jäänyt kesken, mutta oli esittänyt toimivan suunnitelman puuttuvasta osasta. Seitsemän pistettä sai myös, mikäli vastauksessa oli jokin pieni puute (esimerkiksi jos ratkaisussa unohdettu valittujen ehdokkaiden tulostaminen). Neljä pistettä sai, mikäli ohjelma toimi oikein ensimmäiseen järjestämiseen asti. Kaksi pistettä sai, mikäli syötteen lukeminen toimi. Jos ohjelma oli jäänyt kesken, eikä alkuosan koodi näyttänyt vakuuttavalta, nolla pistettä. Vastaus, jossa oli pelkästään ulkoa opeteltuja koodinpätkiä (kuten esimerkiksi jokin järjestämisalgoritmi) oli myös nolla pistettä. Tämän lähtöpisteytyksen jälkeen suoritettiin vähennyksiä seuraavin perustein: 5 pistettä: Molemmat järjestysalgoritmit toimivat väärin. Järjestäminen on tärkeä tietojenkäsittelyn tehtävä, ja se on syytä osata. 3 pistettä: Saman äänimäärän tai vertailuluvun tapauksessa ei käytetä Math.random-metodia järjestyksen arpomiseksi. On väärin olettaa, että ehdokkaat syötettäisiin satunnaisessa järjestyksessä. 3 tai 2 pistettä: Ratkaisu oikein suunniteltu, mutta kooditasolla toteutus ei vastaa suunnitelmaa. (Eli tehnyt tehtävän loppuun asti, koodi ei toimi, mutta kommenteista käy ilmi että on yrittänyt oikeaa asiaa) 3 pistettä: Toinen järjestysalgoritmeista toimii väärin. 2 pistettä: Taulukon ylivuotovirheitä. 2 pistettä: Toistuvia syntaksivirheitä. Yksittäisten sulkeiden tai puolipisteiden unohtaminen annettiin anteeksi, mikäli niiden puuttuminen ei oleellisesti häirinnyt ohjelmakoodin ymmärtämistä. 1 tai 2 pistettä: Kohtuuttomasti ylimääräisiä apumuuttujia. Tämä on merkki huonosta suunnittelutaidosta - esimerkiksi kymmentä vaaliliittoa varten kannattaa tehdä kymmenalkioinen taulukko, ei kymmentä apumuuttujaa. 1 piste: Ehdokkaita ei 903, tai vaalilittoja ei 10. Arviointia ========== Tehtävä oli yleisesti ottaen osattu erittäin heikosti. Huomattava osa vastauksista sisälsi pelkästään jonkinlaisen Ehdokas-luokan toteutuksen sekä ohjelman, joka osasi vain lukea ehdokkaiden tiedot muistiin. Monet eivät olleet edes yrittäneet ehdokkaiden järjestämistä. Kuitenkin tehtävän oikea ratkaisu on varsin yksinkertainen: luetaan ehdokkaiden tiedot taulukkoon, järjestetään taulukko äänimäärän mukaan laskevaan järjestykseen, jonka jälkeen vertailulukujen laskeminen on helppoa. Sen jälkeen järjestetään taulukko vielä kerran, mutta vertailulukujen perusteella. Lopuksi tulostetaan vaalien voittajat taulukon alkupäästä. (Oheinen malliratkaisu toimii näin.) Monissa ratkaisuissa oli turhaan jaoteltu ehdokasolioita erillisiin aputaulukoihin. Arvostelussa tämä miellettiin tyyliseikaksi, joten siitä ei vähennetty pisteitä. Malliratkaisu ============= /*** Ehdokas.java ***/ public class Ehdokas { private String nimi; private int vaaliliitto; private int äänienLkm; private double vertailuluku; private boolean tiedotOikein; public Ehdokas(String nimi, int vaaliliitto, int ääniä) { this.nimi = nimi; this.äänienLkm = ääniä; this.vaaliliitto = vaaliliitto; tiedotOikein = (!nimi.equals("") && ääniä >= 0 && vaaliliitto > 0 && vaaliliitto <= 10); } public String annaNimi() { return nimi; } public int annaÄänet() { return äänienLkm; } public int annaVaaliliitto() { return vaaliliitto; } public void asetaVertailuluku(double luku) { vertailuluku = luku; } public double annaVertailuluku() { return vertailuluku; } public boolean ok() { return tiedotOikein; } public String toString() { return nimi + " (ääniä " + äänienLkm + ", vertailuluku " + vertailuluku + ")"; } } /*** Vaalit.java ***/ public class Vaalit { public static void main(String[] args) { Ehdokas[] ehdokkaat = new Ehdokas[903]; int[] liitonÄänimäärä = new int[10]; // kysytään ehdokkaiden tiedot sekä lasketaan liittojen tiedot for (int i = 0; i < ehdokkaat.length; i++) { do { System.out.print("Anna ehdokkaan " + (i + 1) + " nimi: "); String nimi = Lue.rivi(); System.out.print(" ehdokkaan vaaliliitto: "); int liitto = Lue.kluku(); System.out.print(" ehdokkaan äänimäärä: "); int äänimäärä = Lue.kluku(); ehdokkaat[i] = new Ehdokas(nimi, liitto, äänimäärä); if (!ehdokkaat[i].ok()) { System.out.println("Tiedoissa on jotain vikaa."); System.out.println("Yritä uudelleen."); } } while (!ehdokkaat[i].ok()); int liittoNro = ehdokkaat[i].annaVaaliliitto() - 1; liitonÄänimäärä[liittoNro] += ehdokkaat[i].annaÄänet(); } // järjestetään äänimäärän mukaan (vaihtojärjestäminen) for (int i = 0; i < ehdokkaat.length - 1; i++) { for (int j = i + 1; j < ehdokkaat.length; j++) { int äänet1, äänet2; äänet1 = ehdokkaat[i].annaÄänet(); äänet2 = ehdokkaat[j].annaÄänet(); if (äänet1 < äänet2 || (äänet1 == äänet2 && Math.random() < 0.5) ) { Ehdokas apu = ehdokkaat[i]; ehdokkaat[i] = ehdokkaat[j]; ehdokkaat[j] = apu; } } } // lasketaan vertailuluvut int[] liittoJakaja = new int[10]; for (int i = 0; i < ehdokkaat.length; i++) { int liittoNro = ehdokkaat[i].annaVaaliliitto() - 1; ++liittoJakaja[liittoNro]; ehdokkaat[i].asetaVertailuluku(liitonÄänimäärä[liittoNro] / liittoJakaja[liittoNro]); } // järjestetään vertailuluvun mukaan for (int i = 0; i < ehdokkaat.length - 1; i++) { for (int j = i + 1; j < ehdokkaat.length; j++) { double vertailu1 = ehdokkaat[i].annaVertailuluku(); double vertailu2 = ehdokkaat[j].annaVertailuluku(); if (vertailu1 < vertailu2 || (vertailu1 == vertailu2 && Math.random() < 0.5)) { Ehdokas apu = ehdokkaat[i]; ehdokkaat[i] = ehdokkaat[j]; ehdokkaat[j] = apu; } } } // tulostetaan valitut int n = 0; System.out.println("Valitut ehdokkaat ovat seuraavat:"); for (int i = 0; i < 85; i++) { System.out.println(i + 1 + ": " + ehdokkaat[n]); n++; } System.out.println("Varalle valitut:"); for (int i = 0; i < 85; i++) { System.out.println(i + 1 + ": " + ehdokkaat[n]); n++; } } }