⌛⌛ Sanan arvaus

Tehtävään on tarjolla valmista materiaalia etätietovarastossa:

  • Materiaali on varaston round5/wordgame-hakemistossa.

  • WordGameTest.java: valmis testiohjelma toteutuksesi testaamiseen.

  • words.txt: ohjelman tuntemat sanat.

  • input1.txt ja output1.txt: testisyöte ja sitä vastaava tuloste.

  • input2.txt ja output2.txt: testisyöte ja sitä vastaava tuloste.

Aseta vastauksesi tiedostoihin WordGame.java ja GameStateException.java hakemistossa round5/wordgame.

Johdanto

Eräs klassinen sanan arvauspeli etenee alla kuvatulla tavalla. Pelissä on osapuolina pelinjohtaja, joka voi olla esimerkiksi tietokone sekä pelaaja.

  1. Pelinjohtaja valitsee jonkin sanan näyttämättä sitä pelaajalle, ja lisäksi on määritetty suurin sallittu virheiden (virheellisten arvausten) määrä. Tämän jälkeen askelia 2 ja 3 toistetaan vuorotellen niin kauan, kunnes joko pelaaja arvaa koko sanan, tai pelaajan tekemien virheiden määrä ylittää suurimman sallitun määrän.

  2. Pelinjohtaja näyttää pelaajalle valitsemansa sanan nykytilanteen niin, että jokaisen toistaiseksi oikein arvaamattoman kirjaimen kohdalla on merkki ‘_’.

  3. Pelaajan vuoro. Pelaaja arvaa joko yksittäisen kirjaimen tai koko sanan.

    1. Jos pelaaja päättää arvata koko sanan, pitää arvauksen mennä täsmälleen oikein.

      1. Ellei pelaajan arvaus ole täsmälleen oikein, tulkitaan arvaus virheeksi. Tällöin virheiden määrää kasvatetaan yhdellä eikä sanasta paljasteta mitään lisätietoa ellei peli pääty (katso alla).

      2. Jos arvattu sana oli täsmälleen oikein, peli päättyy pelaajan voittoon.

    2. Jos pelaaja arvaa yksittäisen kirjaimen, niin:

      1. Jos kirjain esiintyy pelinjohtajan sanassa, pelinjohtaja paljastaa kaikki kyseisen kirjaimen esiintymät sanasta. Jos sana tulee oikein arvatun kirjaimen myötä kokonaan arvatuksi, peli päättyy pelaajan voittoon.

      2. Jos kirjainta ei esiinny sanassa tai kirjain oli jo aiemmin arvattu, on kyseessä virhe. Tällöin virheiden määrää kasvatetaan yhdellä.

    3. Jos pelaajan virheiden määrä ylittää suurimman sallitun määrän, loppuu peli pelaajan häviöön. Samalla pelinjohtaja paljastaa valitsemansa sanan kokonaisuudessaan pelaajalle.

Pelin toteutus

Toteuta sanan arvauspeli luokkana WordGame, jolla on seuraavat julkiset ominaisuudet:

  • Sisäinen staattinen luokka WordGameState, jonka olioon voi tallettaa pelin tilanteen: sanan, tehtyjen virheiden lukumäärän, suurimman sallitun virheiden lukumäärän sekä sanan toistaiseksi tuntemattomien kirjainten (paljastamattomien merkkien ‘_’) lukumäärän. Staattinen sisäinen luokka poikkeaa hieman tavallisesta sisäisestä luokasta. Tärkein ero on se, että staattisen sisäisen luokan saatavilla ovat ulkoisen luokan staattiset piirteet. Tästä ei tarvitse huolestua, koska WordGameState-luokan ei tässä tehtävässä pitäisi käsitellä ulkoista luokkaansa WordGame millään tavalla. Muista vain lisätä sisäisen luokan otsikkoon static-määre.

    • Tilaan talletetaan sana sellaisena, kuin se näytettäisiin pelaajalle: arvaamattomat kirjaimet esitetään merkeillä ‘_’.

    • Julkiset funktiot String getWord(), int getMistakes(), int getMistakeLimit() ja int getMissingChars(), jotka palauttavat asianomaiset arvot.

    • Tee WordGame-luokkaan kätketty WordGameState-tyyppinen attribuutti, jos haluat hyödyntää WordGameState-luokkaa pelin logiikan toteuttamiseen tarvittavien tietojen säilyttämiseen. Jos toimit näin, niin palauta attribuutin (päivitetty) arvo, kun jostain WordGame-luokan metodista on tarpeen palauttaa pelin tila. Toinen vaihtoehto on tehdä WordGame-luokkaan lisäattribuutteja, joissa on samoja tietoja kuin WordGameState-luokassa ja luoda WordGameState-luokasta olio lisäattribuuttien arvojen avulla aina, kun on tarpeen palauttaa pelin tila.

    • Ei yhtään julkista rakenninta! Tee kätketty rakennin, jotta Java ei tee automaattisesti julkista oletusrakenninta.

  • Rakennin WordGame(String wordFilename), joka lukee pelissä käytettävissä olevat sanat parametrin ilmoittamasta tiedostosta.

    • Tiedoston oletetaan sisältävän yhden sanan per rivi ilman ylimääräistä tyhjää tilaa.

    • Tee WordGame-luokalle säiliötyyppinen kätketty attribuutti sanojen tallentamiseen. Taulukkolista ArrayList<String> lienee tähän tehtävään sopivin säiliö. Luo rakentajassa säiliöolio ja liitä se attribuutin arvoksi. Lisää sanat rakentajassa säiliöön samassa järjestyksessä kuin ne ovat tiedostossa.

    • Alempana viitataan sanan indeksiin. Ensimmäisen luetun sanan indeksi on 0, toiseksi luetun sanan indeksi on 1 ja niin edelleen. Lisäksi alempana oletetaan, että sanojen kokonaislukumäärä on N.

    • Tee WordGame-luokalle kätketty attribuutti, jonka arvo ilmaisee onko peli käynnissä (aktiivinen) vai pysähdyksissä (passivinen). Aseta tälle attribuutille rakentajassa arvo, joka kertoo pelin olevan pysähdyksissä. Attribuutin luontevin tyyppi lienee boolean.

  • Jäsenfunktio void initGame(int wordIndex, int mistakeLimit) aloittaa uuden pelin. Rakentajan ensimmäinen parametri määrää arvattavan sanan siten, että sanojen säiliöstä valitaan sana, jonka indeksiarvo on wordIndex % N. Aseta valittu sana WordGame-luokan kätketyn attribuutin arvoksi. Toinen parametri mistakeLimit kertoo sallittujen virheiden maksimimäärän. Tämän tiedon voi säilöä vaihtoehtoisesti pelin tilalle tehtyyn WordGameState-tyyppisen attribuutin olioon, kun nyt luot ja asetat attribuutille arvon tai jonkin toisen WordGameState-attribuutin arvoksi. Alusta samalla muut tarvittavat attribuutit, jos toteutat WordGame-luokan ilman WordGameState-attribuuttia. Uusi peli aloitetaan välittömästi riippumatta siitä, oliko aiempi peli mahdollisesti vielä käynnissä. Aseta siksi pelin käynnissäolon tuntevalle attribuutille arvoksi suoraan tieto siitä, että peli on käynnissä.

  • Jäsenfunktio boolean isGameActive(), joka palauttaa tiedon, onko peli parhaillaan käynnissä.

  • Jäsenfunktio WordGameState getGameState(), joka palauttaa pelin tämänhetkisen tilanteen kuvaavan WordGameState-olion.

    • Heittää poikkeuksen GameStateException("There is currently no active word game!"), ellei peli ole parhaillaan käynnissä.

    • Palauta joko WordGameState-tyyppisen attribuutin arvo tai palauta WordGame-luokan attribuuttien arvojen avulla luotu WordGameState-tyyppinen olio.

  • Jäsenfunktio WordGameState guess(char c), joka päivittää pelin tilan vastaamaan kirjaimen c arvausta ja palauttaa päivitetyn tilan kuvaavan WordGameState-olion.

    • Tarkista aivan aluksi onko peli käynnissä. Heitä poikkeus GameStateException("There is currently no active word game!"), jos peli on pysäytetty.

    • Vertaile arvattua kirjainta arvattavan sanan kirjaimiin siten, että aakkoston kokoa ei huomioida. Esimerkiksi suuraakkonen A ja pienaakkonen a katsotaan samaksi merkiksi.

    • Peli pysähtyy, jos sana on arvauksen myötä arvattu kokonaan oikein tai väärien arvausten lukumäärä ylittyy. Päivitä tarvittaessa pelin käynnissäolon tuntevalle attribuutille arvoksi tieto siitä, että peli on pysähtynyt.

    • Palauta joko WordGameState-tyyppisen attribuutin päivitetty arvo tai palauta WordGame-luokan attribuuttien arvojen avulla luotu WordGameState-tyyppinen olio.

  • Jäsenfunktio WordGameState guess(String word), joka päivittää pelin tilan vastaamaan arvausta word ja palauttaa päivitetyn tilan kuvaavan WordGameState-olion. Funktio toimii vertailua lukuun ottamatta aivan kuin WordGameState guess(char c)-funktio. Tässä funktiossa verrataan merkkien asemasta kokonaista arvattua sanaa arvattavaan sanaan.

Edellä viitattiin tyyppiä GameStateException oleviin poikkeuksiin. Tällaista poikkeusluokkaa ei ole valmiina vaan sekin pitää toteuttaa erikseen. Toteuta siis edellisten lisäksi luokka GameStateException, joka perii Javan luokkakirjaston luokan Exception ja jonka ainoa jäsen on julkinen muotoa GameStateException(String msg) oleva rakennin, joka ainoastaan välittää parametrin “msg” yliluokan rakentimelle. Kyseessä on siis varsin yksinkertainen luokka.

Alla tarjottu testimateriaali selventänee luokalta WordGame odotettua toimintaa.

Toteutuksen testaus

Voit testata luokkiasi tiedostossa WordGameTest.java annetun valmiin testiohjelman, tiedostoissa words.txt, input1.txt ja input2.txt annettujen testidatojen ja tiedostoissa output1.txt ja output2.txt annettujen esimerkkitulosteiden avulla. Aseta nämä tiedostot sekä omat luokkatoteutuksesi samaan hakemistoon, käännä ohjelma esimerkiksi komennolla javac *.java ja suorita ensimmäinen testi komennolla java WordGameTest words.txt input1.txt ja toinen testi komennolla java WordGameTest words.txt input2.txt. Suoritusten pitäisi tuottaa tiedostoissa output1.txt ja output2.txt kuvatut tulosteet. Huomaa, että kaikki tulostukset tapahtuvat testiohjelmassa. Luokan WordGame funktiot eivät tulosta mitään.

A+ esittää tässä kohdassa tehtävän palautuslomakkeen.