Slot Machine


theqwe

Grünschnabel
Hallo Community,

ich möchte mich zum üben an ein neues Projekt ran trauen. Es geht nämlich um eine Slot Machine oder auch bekannt als Einarmiger Bandit.
Das Grundgerüst habe ich schon klar im Kopf. Das Problem ist eher die Mathematik (Stochastik). Ich möchte gerne für die verschiedenen Symbole (Kirsche, Orange, BAR, etc...) Wahrscheinlichkeiten angeben und in Variblen speichern. So soll z.B. die Kirsche eine Wahrscheinlichkeit von 40% haben und Orange und Zitrone 25%.

Java:
//...
Random random = new Random();
String symbols = new String[2];
double cherry = 0.4;
double orange = 0.25;
double citrone = 0.25;
//..
for(int i = 0; i <= 3; i++) {
    double number = random.nextDouble();
    if(number == ) {
        symbols[i] = "Kirsche";
    }
    else if(number == ) {
        symbols[i] = "Zitrone";
    }
    //und so weiter
}
Ich habe leider keine Ahnung, wie ich das genau in den if-Anweisungen machen soll. Da Orange und Zitrone die gleiche Wahrscheinlichkeit habe, würde bei 0,25 beides der Fall sein.

Wie setze ich das für ein Anfänger am besten um? Muss ich irgendwie mit Wertebereichen prozentual umgehen?
 

Sempervivum

Erfahrenes Mitglied
Interessante Frage. Ich hatte mal das selbe Problem und habe es so gelöst, dass ich ein Array angelegt habe, in dem die einzelnen Elemente mit der betr. Wahrscheinlichkeit eingetragen werden. Etwa so:
Code:
int j = 0;
for (int i = 0; i < cherry * 100; i++, j++) {
    symbols[j] = "Kirsche";
}
for (int i = 0; i < orange * 100; i++, j++) {
    symbols[j] = "Orange";
}
// usw.
Wenn Du dann mit einem zufälligen Index auf dieses Array zugreifst, bekommst Du das Element mit der betr. Wahrscheinlichkeit.
Alternative, die ich noch nicht getestet habe:
Bereiche definieren, für Kirsche 0 ... <0.4, für Orange 4 ... <0.65, für Zitrone 0.65 ... <0.9
Dann Zufallswert zwischen 0 und <1 erzeugen und prüfen, in welchem Bereich er liegt..
 

theqwe

Grünschnabel
Code:
int j = 0;
for (int i = 0; i < cherry * 100; i++, j++) {
    symbols[j] = "Kirsche";
}
for (int i = 0; i < orange * 100; i++, j++) {
    symbols[j] = "Orange";
}
// usw.
Das verstehe ich nicht so ganz. Wie kann i < cherry * 100 geprüft werden und was macht es genau?
Kann ich mir das so vorstellen:
Java:
double[] symbols = new double[2][2];
symbols[][] = { {1, 0.40}, //cherry
{2, 0.25} } //orange ...

Alternative, die ich noch nicht getestet habe:
Bereiche definieren, für Kirsche 0 ... <0.4, für Orange 4 ... <0.65, für Zitrone 0.65 ... <0.9
Dann Zufallswert zwischen 0 und <1 erzeugen und prüfen, in welchem Bereich er liegt..
Das hatte ich kurz auch in Betracht gezogen. Nur bin ich mir nicht sicher, ob das dann noch Wahrscheinlichkeit ist:
0.00 - 0.40 = Kirsche
<0.40 - 65 = Orange
<65 - 90 = Zitrone
... usw.
 

Sempervivum

Erfahrenes Mitglied
Zu der ersten Alternative: Die Idee ist, ein Array mit 100 Elementen anzulegen, entspr. 100%. Da Du die Wahrscheinlichkeiten von 0 ... 1 definiert hast, muss man den Wert mit 100 multiplizieren um die Anzahl der Elemente zu bekommen. Die Elemente sollen dann mehrfach vorkommen entspr. ihrer Wahrscheinlichkeit, d. h. Kirsche 40 Mal.

Zur zweiten Alternative: Ich denke schon, dass man dann ein Element entspr. seiner Wahrscheinlichkeit heraus bekommt.
 

theqwe

Grünschnabel
Ach jetzt habe ich es verstanden. Also die Bedingung in der for-Schleife ist also i kleiner als cherry (0.25 * 100 = 25), somit werden die ersten 25 Felder mit Cherry belegt?

Wenn das richtig ist, was hälst Du von der Idee die Symbole zufällig in das array legen zu lassen? Macht das einen Unterschied?

Java:
for(int i = 0; i < cherry * 100; i++) {
    arrayset = zufall.nextInt(100);
    if(symbols[arrayset] == null)
        symbols[arrayset] == "Kirsche";
    else
        i--;
}

for(int i = 0; i < orange * 100; i++) {
    arrayset = zufall.nextInt(100);
    if(symbols[arrayset] == null)
        symbols[arrayset] == "Orange";
    else
        i--;
}
Wenn es keinen Unterschied macht, hatte ich wenigstens Spaß am programmieren :)

Als Herausforderung versuche ich beide Varianten umzusetzen.
 

Sempervivum

Erfahrenes Mitglied
Wenn das richtig ist, was hälst Du von der Idee die Symbole zufällig in das array legen zu lassen? Macht das einen Unterschied?
Dürfte auch gehen aber bei deinem Code erwarte ich, dass Plätze im Array leer bleiben, denn wenn Du auf einen belegten triffst, suchst Du keine freie Alternative, somit fällt das Eintragen unter den Tisch.
 

theqwe

Grünschnabel
Okay, der ist nicht wirklich effizient. Bei Algorithmen bin ich noch nicht so weit.
Trotzdem wird die Schleife doch so lange ausgeführt, bis 25 Einträge gesetzt sind oder nicht?
 

Sempervivum

Erfahrenes Mitglied
Würde sagen nein: Die Schleife wird 25 mal ausgeführt, aber es kann sein, dass das Eintragen unterbleibt, weil der Platz schon belegt ist. Ich würde es eher so machen, dass ich die Werte fortlaufend eintrage und am Ende das Array mische (shuffle), damit die Reihenfolge zufällig wird. Weiß nicht, ob es dafür in Java etwas vorgefertigtes gibt, wenn nicht findet man problemlos Algorithmen.
 

theqwe

Grünschnabel
Ich lasse es lieber weg. Sehr effektiv ist sie ja nicht.
Es gibt tatsächlich eine Shuffle Funktion für Arrays.

Vielen Dank für die Hilfe. Mein Projekt funktioniert soweit. Jetzt kommen die Feinabstimmungen.
 

Technipion

Erfahrenes Mitglied
Eigentlich braucht man für sowas kein Array. Hier ist ein Minimalbeispiel:

Java:
import java.util.Random;


public class SlotMachine {
    static String fruits[]      = {"Cherry", "Orange", "Lemon", "Banana"};
    static double probability[] = {    0.40,     0.25,    0.25,     0.10};
    static double total = Double.NaN;
    
    static Random rgen = new Random();
    
    public static void main(String[] args) {
        int counters[] = {0, 0, 0, 0};
        
        for (int i = 0; i < 1000; i++) {
            String fruit = getRandomFruit();
            
            if (fruit.equals("Cherry")) {
                counters[0]++;
            } else
            if (fruit.equals("Orange")) {
                counters[1]++;
            } else
            if (fruit.equals("Lemon")) {
                counters[2]++;
            } else
            if (fruit.equals("Banana")) {
                counters[3]++;
            }
        }
        
        System.out.println("Cherry: " + counters[0] + " / " + (counters[0] / 10.0) + "%");
        System.out.println("Orange: " + counters[1] + " / " + (counters[1] / 10.0) + "%");
        System.out.println("Lemon: " + counters[2] + " / " + (counters[2] / 10.0) + "%");
        System.out.println("Banana: " + counters[3] + " / " + (counters[3] / 10.0) + "%");
    }
    
    public static String getRandomFruit() {
        if (Double.isNaN(total)) {
            total = 0.0;
            for (double p : probability) {
                total += p;
            }
        }
        
        double r = rgen.nextDouble() * total;
        for (int i = 0; i < fruits.length; i++) {
            r = r - probability[i];
            if (r <= 0.0) {
                return fruits[i];
            }
        }
        return fruits[fruits.length - 1]; // failsafe
    }
}
Gruß Technipion