Tämä kurssi on jo päättynyt.

⌛⌛ 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.

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 tuntemattoman 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

Tehtävän palautus koostuu Maven-projektista. Sijoita pom.xml-tiedosto paikallisen tietovarastosi round5/wordgame-hakemistoon ja tee tähän hakemistoon src/main/java-niminen alihakemisto. Tee luokkatiedostot WordGame.java ja GameStateException.java ja liitä ne fi.tuni.prog3.wordgame-nimiseen pakkaukseen. Tiedostojesi tulee olla siten hakemistossa round5/wordgame/src/main/java/fi/tuni/prog3/wordgame.

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 ulkoisesta luokasta ainoastaan sen 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.

Automaattiset sekä alla kuvatut testit olettavat, että teet projektitiedostoosi pom.xml seuraavat määritykset:

  • artifactId-elementin arvo on wordgame.

  • version-elementin arvo on 1.0.

  • maven.compiler.source ja maven.compiler.target -elementtien arvo on 17 tai pienempi. Tarkistimella on asennettuna Java 17, joten tätä uudempaa versiota ei voi käyttää.

  • Onejar-liitännäisen määritys, jonka mainClass-elementin arvo on WordGameTest, joka on alla kuvattu valmiina annettu testiluokka.

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 WordGameTest.java Maven-projektisi alihakemiston src/main/java juureen ja muut tiedostot Maven-projektisi juurihakemistoon pom.xml tiedoston seuraksi. Edellä on huomattava, että WordGameTest.java ei sisällä pakkausmääritystä, joten sitä ei siksi aseteta syvempään alihakemistoon.

Voit tämän jälkeen kääntää ohjelman komennolla mvn package ja suorittaa testin X antamalla komennon java -jar target/wordgame-1.0.one-jar.jar words.txt inputX.txt projektin juurihakemistossa. Numeroa X käyttävän suorituksen pitäisi tuottaa vastaavassa tiedostossa outputX.txt kuvattu tuloste. Huomaa, että kaikki tulostukset tapahtuvat testiohjelmassa. Luokan WordGame funktiot eivät tulosta mitään.

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

Palautusta lähetetään...