Drei Zahlen eines Würfelspiels auswerten

prog6d

Mitglied
Hallo zusammen,

ich versuche meinem Sohn bei der Lösung einer in der Schule gestellten Programmieraufgabe zu helfen. Leider sind meine Programmierkenntnisse bereits etwas in die Jahre gekommen und hoffe auf Eure Hilfe. 🙂

Und zwar programmieren sie gerade ein Würfelspiel. Das meiste davon hat er lösen können, jedoch noch nicht folgendes.

Gegeben sind drei int-Werte (vorher generierte Zufallszahl), die nun wie folgt ausgewertet werden müssen:
  1. Paar: Wenn zwei Würfelzahlen übereinstimmen, multipliziert man die übereinstimmende Augenzahl mal 10.
  2. Straße: Wenn die Augenzahlen der Würfel aufeinander folgen (z.B. [1, 2, 3], [4, 5, 6] usw.), ist die Punktzahl immer 100.
  3. Pasch: Wenn alle Würfel im Becher die gleiche Zahl haben, wird diese Zahl mit 100 multipliziert.
  4. Nichts: In allen anderen Fällen werden die Augenzahlen einfach summiert.

Das Problem sind nicht die einzelnen Rechnungen, sondern die grundsätzliche Struktur.

Wir haben wie folgt angefangen...

[CODE lang="java" title="Code"]public int werteAus(int w1, int w2, int w3) {
if (getPaar(w1, w2, w3) != 0) {
return getPaar(w1, w2, w3);
}
// ... usw.
}

private int getPaar(int w1, int w2, int w3) {
if (w1 == w2 || w1 == w3) {
return w1 * 10;
} else if (w2 == w3) {
return w2 * 10;
} else {
return 0;
}
}[/CODE]

... dann aber festgestellt, dass dieser Weg vermutlich einen zu komplexen Spaghetticode ergeben würde, würde man das so für die anderen Auswertungen fortsetzen. Das lässt sich doch bestimmt eleganter lösen. 😉

Wie würdet Ihr logisch vorgehen? Erst mal überprüfen (boolean) und dann, in separaten Methoden rechnen oder alles in einem? Über etwas Beispielcode würden wir uns auch sehr freuen. Wie gesagt, ich bitte um Nachsicht, da mein Wissen etwas eingerostet ist und ich die Aufgabe für einen Schüler doch recht anspruchsvoll finde.

Wir bedanken uns im Voraus! 👍
 
Zuerst würde ich daruaf achten, dass Pasch (3) Paar (2) impliziert.

Ansonsten sehe ich nicht viele Möglichkeiten zur Verbesserung.

Eventuell könnte man die Prüfung der Bedingungen in einzelne Methoden auslagern, was diesen einen Namen (Selbstdokumentation) und eine Abgrenzung vom restlichen Code gibt.

Die im Code vorhandene Verbindung von Prüfung und Berechnung über tricky != 0 halte ich für nicht so gut.
 
Das Problem sind nicht die einzelnen Rechnungen, sondern die grundsätzliche Struktur.
Hier ein Beispiel für eine Würfelbecherklasse mit fünf Würfeln.

1624549701490.png
Die verwendete Struktur ......
[CODE lang="java" title="Teste die Klasse Würfelbecher" highlight="2-8"]public class start {
public static void main(String[] args) {
DiceCup cup = new DiceCup();
for (int i = 0; i < 10; i++) {
cup.rollDice();
printResult(cup);
}
}

private static void printResult(DiceCup cup) {
System.out.println(cup + "\t" + cup.getResult());
}
}[/CODE]
[CODE lang="java" title="DiceCup"]import java.util.Random;

public class DiceCup {
private static Random rnd = new Random(System.currentTimeMillis());

public enum RESULT {
NONE, FOUR_OF_KIND, FIVE_OF_KIND, THREE_OF_KIND, STREET_SMALL, STREET_BIG, FULLHOUSE
}

private int[] cntResult = new int[5]; // counts resulted eyes of dice
private final int NUM_DICES = cntResult.length;
private RESULT result = RESULT.NONE;
private int cntRoll = NUM_DICES; // counts number of rolled dice

public void checkEyeRange(int eyes) {
if (eyes < 1 || eyes > NUM_DICES)
throw new IllegalArgumentException("Eyes not withing allowed range [1-" + NUM_DICES + "]");
}

public void clear() {
cntRoll = NUM_DICES;
for (int i = 0; i < cntResult.length; i++)
cntResult = 0;
}

public boolean containsEyes(int eyes) throws IllegalAccessError {
checkEyeRange(eyes);
return cntResult[eyes - 1] != 0;
}

public int getEyeValue(int eyes) throws IllegalAccessError {
checkEyeRange(eyes);
return cntResult[eyes - 1] * eyes;
}

private RESULT getNewResult() {
if (hasDiceFactor(5))
return RESULT.FIVE_OF_KIND;
if (hasDiceFactor(4))
return RESULT.FOUR_OF_KIND;
if (hasDiceFactor(3) && hasDiceFactor(2))
return RESULT.FULLHOUSE;
if (hasDiceFactor(3))
return RESULT.THREE_OF_KIND;
if (isConnectedCount(5))
return RESULT.STREET_BIG;
if (isConnectedCount(4))
return RESULT.STREET_SMALL;
return RESULT.NONE;
}

public RESULT getResult() {
return result;
}

private boolean hasDiceFactor(int num) {
for (int i = 0; i < cntResult.length; i++) {
if (cntResult == num)
return true;
}
return false;
}

private boolean isConnectedCount(int num) {
int cnt = 0;
for (int i = 0; i < cntResult.length; i++) {
cnt = (cntResult == 0) ? 0 : cnt + 1;
if (cnt == num)
return true;
}
return false;
}

/**
* Puts a dice back into the cup.
*
* @param eyes
* @throws IllegalAccessError
*/
public void putEyesBack(int eyes) throws IllegalAccessError {
checkEyeRange(eyes);
int id = eyes - 1;
if (cntResult[id] == 0)
throw new IllegalAccessError("Cant' put back non occured eyes result |" + eyes + "|");
if (cntRoll < NUM_DICES) {
cntResult[id]--;
cntRoll++;
}
}

public void rollDice() {
if (cntRoll == 0)
clear();
while (cntRoll > 0) {
cntResult[Math.abs(rnd.nextInt() % NUM_DICES)]++;
cntRoll--;
}
result = getNewResult();
}

@Override
public String toString() {
StringBuffer tmp = new StringBuffer();
for (int i = 0; i < cntResult.length; i++) {
int cnt = cntResult;
while (cnt > 0) {
tmp.append("[" + (i + 1) + "] ");
cnt--;
}
}
return tmp.toString();
}
}[/CODE]
 
Du wirst um mehrere Verkettete if Bedingungen nicht herum kommen.
Wobei du für die Prüfung von pasch und paar etwas intelligent vorgehen kannst, ich hätte es wohl so gelöst:

Java:
if((a==b)||(b==c)||(c==a)){
//mind. ein Paar vorhanden
  if ((a==b)&&(b==c)){
  //Code für Pasch
  //wegen Transitivität muss (a==c) nicht auch mit getestet werden
  }
  else{
  //Code für nur Paar
  }
}
else if {
  //Code um aufsteigende Reihe zu testn
  // am sinnvollsten die zahlen aufsteigend sortieren und dann auf aufsteigende Folge testen
}
else{
  //Code für Nichts
}
 
Naja, Spaghetti-Code... kann man auch so machen:
Java:
public int werteAus(int w1, int w2, int w3) {
    return istPasch(w1, w2, w3) ? w1 * 100
        : istPaar(w1, w2, w3) ? 10 * (w1 == w3 ? w1 : w2)
        : istStrasse(w1, w2, w3) ? 100
        : w1 + w2 + w3;
}

private boolean istPasch(int w1, int w2, int w3) {
    return w1 == w2 && w2 == w3;
}
private boolean istPaar(int w1, int w2, int w3) {
    return w1 == w2 || w2 == w3 || w1 == w3;
}
private boolean istStrasse(int w1, int w2, int w3) {
    if (w1 > w2) { int tmp = w1; w1 = w2; w2 = tmp; }
    if (w1 > w3) { int tmp = w1; w1 = w3; w3 = tmp; }
    if (w2 > w3) { int tmp = w2; w2 = w3; w3 = tmp; }
    return w1+1 == w2 && w2+1 == w3;
}
 
Habt vielen, herzlichen Dank für die Beiträge! Die Codebeispiele haben tatsächlich sehr geholfen und wir waren nun in der Lage es zu lösen. Wir haben uns dabei an der Struktur von @mihe7 orientiert, die Auswertung der Straße jedoch mit einem sortierten Array implementiert.

Ich finde leider keine Möglichkeit das Thema als gelöst zu markieren. Sofern die Admins das können, kann das Thema abgehakt werden. 😉

Nochmals vielen Dank! 🙂
 

Neue Themen


Zurück
Oben