Denkanstoß - Array von Objekten mit Ints

  • Themenstarter Themenstarter jDennis79
  • Beginndatum Beginndatum
J

jDennis79

Gast
Hallo Forum. Ich glaube, ich brauche gerade mal einen kleinen Denkanstoß.

Szenario: Ich habe eine Spielerklasse. Die Klasse verwaltet unter anderem ein Array mit drei Würfelobjekten. Jedes Würfelobjekt verwaltet seine Augenzahlen in einer int-Variablen und gibt seine aktuelle Augenzahl über einen Getter zurück.

In der Spielerklasse gibt es nun eine Methode calculateResult(), innerhalb derer je nach Kombination der drei Augenzahlen ein Ergebnis ermittelt wird.

Java:
public class Player {
    // Code
    private Die[] setOfDice;
    // Code
}

Java:
public class Die {
    // Code
    private int pipsOfDie;
    // Code
}

Meine erste Idee war jetzt eine verschachtelte If-Abfrage:

Java:
if (setOfDice[0].getPipsOfDie() == 1) {
    if (setOfDice[1].getPipsOfDie() == 1) {
        if (setOfDice[2].getPipsOfDie() == 1) {
            // Code
        } else ... usw.

Aufgrund der Menge an möglichen Kombinationen wird das natürlich ziemlich mächtig und unübersichtlich.

Meine zweite Idee war, alle Augenzahlen in eine ArrayList oder eine andere Collection einzulesen und mit irgendeiner Methode der entsprechenden Collection zu arbeiten.

Java:
ArrayList<Integer> combination = new ArrayList<Integer>();
    for (int i = 0; i < setOfDice.length; i++) {
        combination.add(setOfDice[i].getPipsOfDie());
}

Ich habe aber in keiner Klasse, die ich in der API gefunden habe, eine geeignete Methode gefunden. Die contains()-Methoden zum Beispiel ermitteln ja nur, ob eine Augenzahl überhaupt vorkommt, aber nicht, wie oft.

Mir fehlt gerade die zündende Idee, wie ich das vereinfachen könnte. Hat jemand Vorschläge oder einen Denkanstoß?
 
Zuletzt bearbeitet von einem Moderator:
Ich hatte gerade noch eine Idee.

Ich könnte die ArrayList aufsteigend sortieren, die drei Augenzahlen zu einem String verketten und diesen dann mit den möglichen Ergebnissen vergleichen. Das hätte zwei Vorteile:

1. Es würde die Menge der Kombinationen deutlich reduzieren, weil ich zum Beispiel nur noch "156" überprüfen muss, aber nicht mehr "165", "516", "561" usw.

2. Es würde mir die Verschachtelung ersparen, weil ich nicht mehr die einzelnen Augenzahlen gegeneinander prüfen muss, sondern nur noch die gesamte Dreier-Kombination.

Für noch bessere Vorschläge bin ich natürlich trotzdem offen.
 
Wenn du statt der Code Tags die Java Tags verwendest (siehe die große Rote schrift) dann kann dein Code etwas leichter gelesen werden....
 
Damit ich dich richtig verstanden habe. Du hast 1 Spieler mit drei Würfeln. Wenn der Spieler nun würfelt willst du die Anzahl Augen berechnen?
 
Das mit dem Sortieren und dem String klingt... erstmal... komisch, KÖNNTE(!) aber eine in diesem ganz speziellen Fall geeigenete Lösung sein. Die entscheidende Frage ist, auf basis welcher "Kriterien" was passieren soll. Also Beispiel: Wenn NUR die Summe der Augenzahlen relevant wäre, wäre das mit dem Sortieren natürlich blöd - wenn aber alle Entscheidungen auf Basis dieses "Musters" wie "156" getroffen werden können, wäre es vielleicht OK. Beschreib' diese Kriterien vielleicht nochmal genauer.
 
@ Sonnec - sorry, da steht es schon so schön abgesetzt und fett da, und ich übersehe es trotzdem...

@ Upriser - nein, es kommt auf die Kombinationen an, nicht auf die Summen.

@ Marco:

In dem Spiel gibt es verschiedene Level von Wertigkeiten.

- Der höchste Wurf ist 1, 1, 1.

Danach kommen Würfe, die aus zwei 1-en und einer dritten Zahl bestehen, die dritte Zahl bestimmt die Rangfolge.

- 1, 1, 6 ist demnach der zweithöchste Wurf
- 1, 1, 5 der dritthöchste
- 1, 1, 4 der vierthöchste usw.

Als nächstes kommen die Dreierpaschs, absteigend nach Rangfolge also

- 6, 6, 6
- 5, 5, 5
- usw.

Direkt darunter liegen die Straßen, also

- 1, 2, 3
- 2, 3, 4
- usw.

Als letztes in der Hierarchie kommen die "normalen" Zahlwürfe, die als dreistellige Zahlen gelesen werden, also absteigend:

- 6, 6, 5
- 6, 6, 4
- (...)
- 5, 5, 4
- 5, 5, 3
- usw.

Es kommt also auf die Kombination an. Die String-Lösung ist bisher die beste, die mir eingefallen ist. :noe:
 
Zuletzt bearbeitet von einem Moderator:
Funktionieren tut es, übersichtlich(er) als mit Verschachtelungen ist es auch - aber es sind immer noch über 50 If-Abfragen. Glücklich bin ich damit nicht. Vielleicht fällt ja noch jemandem eine gute Lösung ein.
 
aber es sind immer noch über 50 If-Abfragen

Du kannst mit kategorien arbeiten.
1. Kat: 111
2. Kat: alle mit zwei einser
3. Kat: Pasch
4. Kat: Straßen
5. Kat: sonsttige.

dann hat du 5 logiken anahnd du die Kategoire ermitellst und innerhalb der Katergorie kannst du dann nochmal die jeweilige Wertigkeit bestimmen..
 
Ich habe bisher noch nichts von Kategorien gelesen - aber das klingt zumindest schonmal wie etwas, das ich gesucht habe. 🙂 Wie gut, dass die Insel hier noch liegt...
 
Kategorien ... naja das ist jetzt nichts was es schon gibt... da brauchst du die insel gar nicht bemühen...
schreib dir deine methode die dir anhand des setOfDice den Typ/Kategorie zurück gibt und anhand dieser Kategorie ruft du immer eine andere Methode auf die dir die Würfle bewertet...
 
Dazu wirst du in der Insel nichts finden, das ist nur so ein abstrakter Begriff....

Hab' mal die Mittagspause genutzt...
Java:
import java.util.*;

class DiceCheck
{
    public static void main(String args[])
    {
        System.out.println(check(1,1,1));

        System.out.println(check(1,1,2));
        System.out.println(check(1,3,1));
        System.out.println(check(4,1,1));

        System.out.println(check(2,2,2));
        System.out.println(check(4,4,4));

        System.out.println(check(2,3,4));
        System.out.println(check(4,5,6));

        System.out.println(check(1,5,6));
        System.out.println(check(6,5,2));
    }

    private static String check(int ... values)
    {
        List<Integer> list = new ArrayList<Integer>();
        for (int i=0; i<values.length; i++)
        {
            list.add(values[i]);
        }
        return "For "+list+": "+check(list);
    }


    private static int count(List<Integer> list, Integer element)
    {
        int counter = 0;
        for (Integer value : list) if (value.equals(element)) counter++;
        return counter;
    }


    private static int sequence(List<Integer> list, int delta)
    {
        Collections.sort(list);
        for (int i=0; i<list.size()-1; i++)
        {
            Integer v0 = list.get(i);
            Integer v1 = list.get(i+1);
            if (v1 != v0+delta) return 0;
        }
        return list.get(0);
    }

    private static int straight(List<Integer> list)
    {
        return sequence(list, 1);
    }

    private static int value(List<Integer> list)
    {
        Collections.sort(list);
        int value = 0;
        int n = 1;
        for (int i=list.size()-1; i>=0; i--)
        {
            Integer v = list.get(i);
            value += v * n;
            n *= 10;
        }
        return value;
    }

    private static Integer nOfAKind(List<Integer> list)
    {
        return sequence(list, 0);
    }

    private static String check(List<Integer> list)
    {
        int ones = count(list, 1);
        if (ones == 3) return "Three times one";
        if (ones == 2)
        {
            Integer max = Collections.max(list);
            return "Two ones and "+max;
        }
        int minStraight = straight(list);
        if (minStraight != 0) return "Straight starting at "+minStraight;

        int nOf = nOfAKind(list);
        if (nOf != 0) return "Three of "+nOf;

        return "Nothing "+value(list);
    }
}
 
@ Marco: Vielen Dank erstmal!

Auf den ersten Blick sieht deine Lösung jetzt nicht viel kompakter aus als meine, nur viel eleganter natürlich. Ich werde sie mir aber nachher nochmal in Ruhe ansehen und überlegen, ob sie sinnvoller ist. Unter welcher Lizenz steht deine Lösung? 😀

Meine sieht jetzt so aus:

Java:
public String calculateResult() {
		String result = "";
		ArrayList<Integer> pipsArray = new ArrayList<Integer>();
		String combination = "";
		for (int i = 0; i < setOfDice.length; i++) {
			pipsArray.add(setOfDice[i].getPipsOfDie());
		}
		Collections.sort(pipsArray);
		for (int i = (setOfDice.length - 1); i >= 0; i--) {
			combination = combination + (pipsArray.get(i));
		}
		if ("111".equals(combination)) {
			result = "shockout";
		} else if ("611".equals(combination)) {
			result = "6shock";
		} else if ("511".equals(combination)) {
			result = "5shock";
		} else if ("411".equals(combination)) {
			result = "4shock";
		} else if ("311".equals(combination)) {
			result = "3shock";
		} else if ("211".equals(combination)) {
			result = "2shock";
		} else if ("666".equals(combination)) {
			result = "6general";
		} else if ("555".equals(combination)) {
			result = "5general";
		} else if ("444".equals(combination)) {
			result = "4general";
		} else if ("333".equals(combination)) {
			result = "3general";
		} else if ("222".equals(combination)) {
			result = "2general";
		} else if ("654".equals(combination)) {
			result = "6straight";
		} else if ("543".equals(combination)) {
			result = "5straight";
		} else if ("432".equals(combination)) {
			result = "4straight";
		} else if ("321".equals(combination)) {
			for (int i = 0; i < setOfDice.length; i++) {
				if (setOfDice[i].isLocked()) {
					result = combination;
				} else {
					result = "3straight";
				}
			}	
		} else {
			result = combination;
		}  
		return result;
	}

Die Idee war, dass ich die normalen Zahlwürfe ja direkt als Ergebnis zurückliefern kann, weil der Aufrufer sowieso die Wertigkeiten aller Spielerergebnisse noch gegeneinander prüfen muss.
 
Die Lizenz für die Lösung ist die WTFPL.

Tatsächlich sind die if-Abfragen in diesem Fall kompakter, einfacher und übersichtlicher - ich hätte im Voraus nicht gedacht, dass es so wenig Fälle sind... da hätte man mal nachdenken müssen (du hattest was von 50 gesagt ???:L ). Zumindest eine "akademische" Rechtfertigung habe ich: Wenn man das ganze jetzt auf 4 Würfel erweitern müßte... ... ... ... ... 😉
 
@Marco - ja, über 50 wären es, wenn ich jeden "normalen" Zahlwurf einzeln auch noch prüfen würde. Aber dann habe ich, wie gesagt, ja überlegt, dass der Aufrufer sowieso die Ergebnisse aller Spieler gegeneinander prüfen muss, und ich dann die Zahlwürfe auch einfach im letzten else-Zweig "as is" zurückgeben kann.

Aber wie du schon sagst - falls man den Mechanismus erweitern müsste, wäre deine Lösung einfacher auszubauen - da bin ich ja dann mittendrin im Thema OOP. 🙂 Deshalb nochmal Danke für den Hinweis!

P.S.: WTFPL... :lol: Kannte ich noch gar nicht. Grandios! :lol:
 
Die Hauptfrage die sich mir gerade stellt ist, was du nach dem Vergleich tun willst.

Ich weiß jetzt leider nicht wieviele Werte du unterscheidest, aber vielleicht geht ja folgendes:

Die gewürfelten Zahlen sortierst du, wie du oben gesagt hast, nach ihrer Augenzahl. So dass sie
immer aufsteigend von links nach rechts angeordnet werden (Bsp.: 114, 123, 145). Somit hast
du eine definierte Menge an Kombinationen.

Den einzelnen Ergebnissen weißt du in einer HashMap einen Wert zu. Bsp.:
111 ist das Höchste, also erhält es den Wert 1000;
116 ist das zweit Höhcste, erhält den Wert 999;
-->
Java:
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put (String.valueOf(111), 1000); 
map.put (String.valueOf(116), 999);

Eventuell musst du Integer in der Map speichern (new Integer(1000))

Würfeln nun 3 leute, kannst du ihre drei Ergebnisse wiefolgt vergleichen:
Java:
int score1 = map.get(String.valueOf(111)).intValue();
int score2 = map.get(String.valueOf(116)).intValue();
....

Soll nur der Titel des Ergebnisses ausgegeben werden (Straße, 6Pasch)... kann man
auch diesen dort speichern. Wird beides gebraucht kann man sich eine Übersetzerklasse
erstellen, die zum Punktestand die entsprechende Übersetzung zurück liefert.
 
Zuletzt bearbeitet:
Die Vorteile der Objektorientierten Programmierung ist nunmal, dass man sowas machen kann.
Java ist auch nichtmehr wirklich langsam im Vergleich zur Anfangszeit.

Natürlich kann man das auch mit Spagetticode programmieren und vielleicht ne 10. Sekunde herausschlagen, aber da stellt sich mir die Frage, was wartungsfreundlicher und leichter erweiterbar ist.

Außerdem erstellt man die Map ja nur einmal und hat dann immer darauf Zugriff.
 
Natürlich hat eine Map unschätzbare Vorteile, aber in diesem Fall ist es eher ein "Umweg", und so eine Map oder ein "bedenkenloses" String.valueOf haben ja nichts mit OOP zu tun. Es spielt in diesem Fall vielleicht keine Rolle, aber falls das doch schnell ausgewertet werden muss, hieße es von einigen vielleicht wieder "boah, Java is woll lahm". Niemand würde auf die Idee kommen, für die Sortierung eines dreielementigen Arrays Quicksort zu Implementieren, und auch nicht darauf, es nur zu verwenden selbst wenn es schon fertig implementiert ist. Aber so ein Arrays.sort(...) geht eben schneller von der Hand als eine handvoll if-Abfragen. Vielleicht ist das aber auch alles unwichtig.
 

Zurück
Oben