Facebook
From j, 3 Years ago, written in Plain Text.
Embed
Download Paste or View Raw
Hits: 77
  1. package o1.peeveli
  2.  
  3. import GameState.Unrevealed
  4. import o1._
  5.  
  6.  
  7. /** Kukin luokan `GameState` ilmentymä kuvaa yhtä Peeveli-hirsipuupelin peliGameStatetta:
  8.   * Minkä näköinen on guessLetterjalle näytettävä (osin paljastettu) visibleWord? Montako
  9.   * arvausta on jäljellä? Mitä arvauksia on jo tehty? Sekä huijaavalle Peevelille
  10.   * tärkeä tieto: Mitkä kaikki sanat ovat edelleen mahdollisia vastauksia?
  11.   *
  12.   * Peeveli-pelin toiminta on selitetty tarkemmin kurssimateriaalin luvussa 10.1.
  13.   *
  14.   * Vaikka pelin aikana peliGameState vaihteleekin, on kukin `GameState`-olio tilaltaan täysin
  15.   * muuttumaton. Uusi peliGameState muodostetaan uutena `GameState`-oliona kutsumalla vanhalle
  16.   * tilanteelle `guessLetter`-metodia. (Tämä luokka edustaa funktionaalista ohjelmointityyliä.)
  17.   *
  18.   * @param missesAllowed  se määrä vääriä arvauksia, joka vielä sallitaan ennen pelin päättymistä.
  19.   *                         Negatiivinen luku tarkoittaa, että peli on päättynyt.
  20.   * @param previousGuesses          merkkijono, joka sisältää järjestyksessä kaikki toistaiseksi previousGuesses merkit
  21.   * @param visibleWord        merkkijono, jossa on visibleWordn guessLetterjalle näkyvä muoto. Pelin alussa
  22.   *                         visibleWordssa on vain piilossa olevia merkkejä (ks. []]),
  23.   *                         mutta merkkejä paljastuu vähitellen.
  24.   * @param possibleSolutions     kaikki ne käytetyn vocabularyn sanat, jotka sopivat yhteen `visibleWord`-parametrin
  25.   *                         kanssa eli ovat mahdollisia oikeita vastauksia */
  26. class GameState(val missesAllowed: Int, val previousGuesses: String, val visibleWord: String, val possibleSolutions: Vector[String])  {
  27.  
  28.  
  29.   /** Luo uuden `GameState`-olion, joka kuvaa juuri alkaneen uuden `Peeveli`-pelin tilaa.
  30.     * Pelin alkaessa koko visibleWord on vielä piilossa ja kaikki annetun vocabularyn sopivan
  31.     * mittaiset sanat ovat mahdollisia oikeita ratkaisuja.
  32.     *
  33.     * Lisätieto opiskelijoille: Huomaa, miten tämä '''toinen konstruktori''' on määritelty
  34.     * annetussa ohjelmakoodissa. Tällä tavoin voidaan määritellä vaihtoehtoinen tapa luoda
  35.     * `GameState`-olio sen "oletustavan" lisäksi, joka on määritelty luokan otsikkorivillä.
  36.     * Voidaan siis luoda GameStateolio joko käskyllä `new GameState(arvauksia, previousGuesses, visibleWord, sopivat)`
  37.     * (oletustapa) tai käskyllä `new GameState(arvauksia, length, vocabulary)`.
  38.     *
  39.     * @param missesAllowed  se määrä vääriä arvauksia, joka yhteensä sallitaan ennen pelin päättymistä
  40.     * @param length                  uuden visibleWordn length
  41.     * @param vocabulary                 vocabulary, jonka `length`-mittaiset sanat ovat mahdollisia oikeita vastauksia */
  42.   def this(missesAllowed: Int, length: Int, vocabulary: Vector[String]) = {
  43.     // Seuraava tarkoittaa: luo olio käyttäen "oletustapaa" ja antaen seuraavat konstruktoriparametrit:
  44.     this(missesAllowed, "", Unrevealed.toString * length, vocabulary.map( _.toUpperCase ))
  45.   }
  46.  
  47.   private def eiPiilokirjaimia: Boolean = {
  48.     this.visibleWord.find { x => x == Unrevealed }.isEmpty
  49.   }
  50.  
  51.  
  52.   /** Palauttaa visibleWordn pituuden. */
  53.   def wordLength = this.visibleWord.length
  54.  
  55.  
  56.   /** Palauttaa niiden käytetystä vocabularysta löytyvien sanojen lukumäärän, jotka ovat
  57.     * (edelleen) mahdollisia ratkaisuja visibleWordan. */
  58.   def numberOfSolutions = this.possibleSolutions.size
  59.  
  60.  
  61.   /** Palauttaa `true` jos guessLetterja on arvannut väärin jo enemmän kertoja kuin sallittiin
  62.     * ja on siis hävinnyt pelin; palauttaa `false`, jos näin ei ole. */
  63.   def isLost = if(this.missesAllowed < 0) true else false
  64.  
  65.  
  66.   /** Palauttaa `true`, jos guessLetterja on voittanut pelin eli ei ole arvannut liian monta kertaa väärin
  67.     * ja kaikki visibleWordn kirjaimet ovat näkyvissä; muutoin palauttaa `false`. */
  68.   def isWon = if(!this.isLost && eiPiilokirjaimia ) true else false
  69.  
  70.  
  71.   /** Palauttaa visibleWordsta sellaisen version, josta on paljastettu osoitetut merkit. Esimerkiksi
  72.     * jos visibleWord on `"K___A"` ja parametrimerkkijono on `"__SS_"`, palauttaa `"K_SSA"`. */
  73.   private def reveal(paljastettavat: String) = {
  74.     var uusivisibleWord = ""
  75.     for (indeksi <- this.visibleWord.indices) {
  76.       if (paljastettavat(indeksi) != Unrevealed) {
  77.         uusivisibleWord += paljastettavat(indeksi)
  78.       } else {
  79.         uusivisibleWord += this.visibleWord(indeksi)
  80.       }
  81.     }
  82.     uusivisibleWord
  83.   }
  84.  
  85.  
  86.   /** Palauttaa uuden pelitilanteen, joka seuraa nykyisestä, kun guessLetterja guessLetter annetun merkin.
  87.     * Uusi peliGameState valitaan periaatteella, joka on selostettu kurssimateriaalin luvussa 10.1.
  88.     * Uudessa tilanteessa on ainakin yksi tehty arvaus enemmän kuin nykyisessä; lisäksi siinä saattaa
  89.     * olla enemmän näkyviä merkkejä visibleWordssa, vähemmän vääriä arvauksia jäljellä ja/tai vähemmän
  90.     * mahdollisia oikeita vastauksia.
  91.     * @param arvaus  viimeksi arvattu merkki; voi olla iso tai pieni kirjain, mutta tulkitaan aina isoksi.
  92.     * @return uusi peliGameState */
  93.   def guessLetter(arvaus: Char) = {
  94.     import scala.collection.mutable.Buffer
  95.     val arvausIsona = arvaus.toUpper
  96.  
  97.     //Kertoo arvatun kirjaimen indeksit sanassa
  98.     def indeksit(sana: String): Vector[Int] = {
  99.       var indeksit: Buffer[Int] = Buffer()
  100.       var indeksi = sana.indexOf(arvausIsona)
  101.       while(indeksi >= 0){
  102.         indeksit += indeksi
  103.         indeksi = sana.indexOf(arvausIsona, indeksi + 1 )
  104.       }
  105.       indeksit.toVector
  106.     }
  107.  
  108.     val(sisaltaaKirjaimen, eiKirjainta) = this.possibleSolutions.partition( _.contains(arvausIsona))
  109.  
  110.     //Palauttaa sanalistan, jossa previousGuesses kirjaimet ensin jaotellaan sanalistoihin sen mukaan, montako kertaa niissä
  111.     //esiintyy arvattu kirjain. Listoista valitaan suurin.
  112.     var isoinLista = this.possibleSolutions.groupBy(x => x.count(_ == arvausIsona) ).values.maxBy( _.size)
  113.  
  114.     //Järjestää sanalistan indeksien mukaan, valitsee joukon, joka on suurin
  115.     val isoinSijainninMukaan = isoinLista.groupBy(x => indeksit(x) ).values.maxBy(_.size)
  116.  
  117.     val ratkaisu: String= {
  118.  
  119.       if(isoinSijainninMukaan.size > eiKirjainta.size) {
  120.  
  121.        var sana = isoinSijainninMukaan.head
  122.        var sijainnit = indeksit(sana)
  123.        var paljastettavat = visibleWord
  124.        var test = paljastettavat.toBuffer
  125.        var paljastettavaSana = ""
  126.  
  127.        for(i <- sijainnit){
  128.          test(i) = arvausIsona
  129.        }
  130.  
  131.        for(k <- 0 until test.size){
  132.          paljastettavaSana += test(k)
  133.        }
  134.  
  135.        paljastettavaSana
  136.  
  137.       }else{
  138.         visibleWord
  139.       }
  140.  
  141.     }
  142.     isoinLista = if(isoinSijainninMukaan.size > eiKirjainta.size) isoinSijainninMukaan else eiKirjainta
  143.     if(isoinSijainninMukaan.size > eiKirjainta.size){
  144.       new GameState(this.missesAllowed, this.previousGuesses + arvausIsona, ratkaisu, isoinLista)
  145.     }else{
  146.       new GameState(this.missesAllowed - 1, this.previousGuesses + arvausIsona, ratkaisu, isoinLista)
  147.     }
  148.  
  149.  
  150.   }
  151.  
  152.  
  153.   /** Palauttaa tekstimuotoisen kuvauksen tästä pelitilanteesta. */
  154.   override def toString =
  155.     this.visibleWord + ", " +
  156.     "vääriä sallitaan vielä: " + this.missesAllowed + ", " +
  157.     "previousGuesses: " + (if (this.previousGuesses.isEmpty) "ei ole" else this.previousGuesses) + ", " +
  158.     "vaihtoehtoja: " + this.numberOfSolutions
  159.  
  160. }
  161.  
  162.  
  163. /** Tämä `GameState`-luokan kumppaniolio vain tarjoaa yhden vakioarvon.
  164.   * @see [[GameState]]-luokka */
  165. object GameState {
  166.  
  167.   /** merkki, jota käytetään piilossa olevien kirjainten merkitsemiseen Peeveli-pelissä */
  168.   val Unrevealed = '_'
  169.  
  170. }