Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Expand
titleDel 2 - <tema> (xx%)
Oppgave a)

 

Expand
titleLF

 

Oppgave b)

 

Introduksjon til del 2

Denne deloppgaven handler om poengberegning basert på et sett terningverdier. Felles for mange terningspill er at man kaster terninger og så finner ut hvor mange poeng en får basert på terningverdiene. Visse kombinasjoner gir mer elle mindre poeng, og noen gir ingen. I Yatzy har en mange poenggivende kombinasjoner, f.eks. ett par (to like), to par, tre og fire like, liten (1-5) og stor (2-6) straight, hus (ett par og tre like) og Yatzy, og poengene en får er stort sett summen av terningverdiene som inngår i kombinasjonen. I Farkle, derimot, så får en 100 poeng for enere, 50 poeng for femmere, og for de andre får en bare poeng hvis en får tre eller flere i slengen (se vedlegg for detaljene).

For å støtte (minst) begge disse spillene, så introduseres et DiceScorer-grensesnitt, som representerer en poengregel generelt, og én implementasjonsklasse for hver (type) regel. DiceScorer-grensesnittet har kun én metode, getScore, som tar inn et Dice-objekt med alle terningverdiene som skal vurderes samlet og returnerer et nytt Dice-objekt med akkurat de terningverdiene som dekkes av regelen og med poengverdien satt riktig for akkurat disse terningverdiene:

Code Block
/**
* Interface for scoring rules, i.e.
* logic for computing a score for a subset of dice in a Dice
*/
public interface DiceScorer {
   /**
   * Computes a score for (a subset of) the dice in the Dice argument.
   * The return value includes those dice that gives the score, and
   * of course the score itself.
   * @param dice
   * @return The dice for which the rule computes a score, and the score itself, or
   * null, if this rule isn't applicable
   */
   Dice getScore(Dice dice);
}

En implementasjon av DiceScorer som tilsvarer "tre like"-regelen i Yatzy, vil altså returnere et Dice-objekt med de tre like terningverdiene den finner i Dice-argumentet, eller null hvis den ikke finner tre like verdier. I tillegg settes poengene i Dice-objektet som returneres til riktig verdi. Hvis f.eks. argumentet er [1, 2, 2, 2, 5] så vil den iht. Yatzy-logikk returnere [2, 2, 2] = 6. En tilsvarende implementasjon for Farkle vil ha samme logikk for å finne tre like, men ha annen logikk for å sette poengene ( = 2 * 100).

Oppgave a) - Tre eller flere like (6 poeng)

Skriv kode for klassen ThreeOrMoreOfAKind (tre eller flere like), som implementerer DiceScorermed følgende logikk:

For et Dice-argument uten tre eller flere like returneres null. Ellers returneres et (nytt) Dice-objekt med alle de like terningverdiene, altså tre eller flere like verdier. For tre like får en 100 ganger verdien det er tre eller flere like av, f.eks. 300 poeng for tre 3-ere. For hver ekstra terning med samme verdi så doblespoengene, f.eks. får en 1200 (= 300 * 2 * 2) poeng for fem 3-ere.

Merk at hvis en har mange nok terninger, så kan en få tre eller flere like for flere terningverdier. En skal da velge den terningverdien som gir flest poeng. Hvis en f.eks. har terningene [2, 2, 2, 2, 5, 5, 5] så skal en velge de tre 5-erne, siden de gir 500 poeng, mens de fire 2-erne gir bare 400. Hvis flere terningverdier gir samme, høyeste poengverdi, så skal den med flest like terninger velges.

Expand
titleLF
Code Block
public class ThreeOrMoreOfAKind implements DiceScorer {


   // hjelpemetode som beregner poengsum for count antall av value
   private int getScore(final int value, int count) {
      int score = value * 100;
      while (count > 3) {
         score = score * 2;
         count--;
      }
      return score;
      // Samme som: return value * 100 * (int) Math.pow(count - 3, 2);
   }

   // går gjennom hver mulige verdi 1-6 og finner den med nok like som gir flest poeng
   protected int getBestValue(final Dice dice) {
      int value = 0, max = 0;
      for (int i = 1; i <= 6; i++) {
         int count = dice.getValueCount(i);
         int score = getScore(i, count);
         if (count >= 3 && score > max) {
            value = i;
            max = score;
         }
      }
      return value;
   }

   @Override
   // finner den beste og lager et nytt Dice-objekt med riktig antall terningverdier og poengsum
   public Dice getScore(final Dice dice) {
      int best = getBestValue(dice);
      if (best == 0) {
         return null;
      }
      int count = dice.getValueCount(best);
      Collection<Integer> dieValues = new ArrayList<Integer>(count);
      for (int i = 0; i < count; i++) {
         dieValues.add(best);
      }
      return new Dice(dieValues, getScore(best, count));
   }
}
Oppgave b) - Beregning av total poengsum (6 poeng)

Hvis en har mange terninger og er heldig, så kan én eller flere DiceScore-regler kombineres flere ganger. En får da summen av poengene som hver bruk av en regel gir. Én terning kan selvsagt ikke være med i mer enn én kombinasjon. Hvis en f.eks. har "tre eller flere like"-regelen implementert av ThreeOrMoreOfAKind-klassen og får fire 3-ere og tre 4-ere så vil en få 600 poeng for 3-erne og 400 poeng for 4-erne og dermed 1000 til sammen. 

Det blir mer komplisert hvis flere regler "konkurrerer" om de samme terningene. F.eks. vil jo de samme fire 3-ere og tre 4-ere utgjøre hus (to 3-ere og tre 4-ere) og ett par (to 3-ere), hvis tilsvarende poengregler var med.

Poengberegningen for et spesifikt spill gjøres generelt som følger:

  • En har en oversikt over alle DiceScorer-objektene som gjelder, f.eks. i en tabell eller liste. Gjør nødvendige antagelser om hvor disse er lagret og kan hentes ut.
  • En prøver alle DiceScorer-objektene etter tur og det som gir flest poeng brukes først. Terningene som er i den tilsvarende kombinasjonen fjernes, og så gjentar en dette til alle poenggivende terninger er "brukt opp". Resultatet er (en Collection med) alle Dice-objektene som tilsvarer de kombinasjonene som ble brukt med poengverdien satt.

For eksemplet over, med bare ThreeOrMoreOfAKind-regelen og terningene [1, 3, 3, 3, 3, 4, 4, 4, 5] så vil en få som resultat (en Collection med) Dice-objektene [3, 3, 3, 3] = 600og [4, 4, 4] = 400. To av terningene, 1 og 5, ble i dette tilfellet ikke poenggivende og dermed ikke med i resultatet.

Code Block
/**
* Computes a set of Dice with scores for the provided Dice.
* @param dice
* @return the set of Dice with die values and corresponding scores.
*/
public Collection<Dice> computeDiceScores(Dice dice) {
   ...
}
Expand
titleLF

Her antar vi at metoden computeDiceScores ligger i en klasse, som også har et felt for DiceScore-objektene

Code Block
private Collection<DiceScorer> diceScorers;

public Collection<Dice> computeDiceScores(Dice dice) {
   Collection<Dice> result = new ArrayList<>();
   // Vi følger algoritmen gitt over:
   // Så lenge det er terninger igjen, så
   //   finner vi regelen som gir flest poeng og sparer på de terningene den "brukte" og
   //   fjerner dem fra gjenværende terninger
   while (dice.getDieCount() > 0) {
      Dice best = null;
      for (DiceScorer diceScorer : diceScorers) {
         Dice score = diceScorer.getScore(dice);
         if (score != null && (best == null || score.getScore() > best.getScore())) {
            best = score;
         }
      }
      if (best == null) {
         break;
      } else {
         result.add(best);
         dice = dice.remove(best);
      }
   }
   return result;
}
Expand
titleLF
 
Oppgave c)

 

Expand
titleLF
 
Oppgave d)

 

Expand
titleLF
 
Oppgave e)

 

Expand
titleLF
 
Oppgave f)

 

Expand
titleLF
 
Expand
titleDel 3 - <tema> (xx%)
Oppgave a)

 

Expand
titleLF

 

Oppgave b)

 

Expand
titleLF
 
Oppgave c)

 

Expand
titleLF
 
Oppgave d)

 

Expand
titleLF
 
Oppgave e)

 

Expand
titleLF
 
Oppgave f)

 

Expand
titleLF