Spiele-App „Reactions“ – Teil 4: Zufallsgenerator

Spiele-App „Reactions“ – Teil 4: Zufallsgenerator

Auf dieses Video habe ich mich schon die ganze Woche gefreut. Wir bauen weiter an unserem Reaktionstest-Spiel und werden heute einen Meilenstein schaffen. Es fehlt nämlich nicht mehr viel, um wirklich spielen zu können.

ColorShuffler Klasse

Wir haben einen 1-Spieler-Modus und einen 2-Spieler-Modus. Bei beiden brauchen wir einen Zufallsgenerator, um zufällig Farben für den Spiel-Button zu erzeugen. Wir können also große Teile des Codes wiederverwenden. Deswegen, und auch um die Übersichtlichkeit zu verbessern, erstellen wir für den Zufallsgenerator eine neue Klasse. Die nennen wir „ColorShuffler“.

Wir deklarieren 4 Variablen. Die erste nennen wir colorMap. Das ist eine eine Liste, jede Zeile enthält zwei Werte. Der eine Wert ist der Name der Farbe, das nennen wir Schlüssel (Key), und der andere Wert ist die Farbe als hexadezimaler Farbcode, das nennen wir Wert (Value). Dann haben wir einen String für den Namen der zufällig ausgewählten Farbe und einen weiteren String für den Farbcode der zufällig ausgewählten Farbe. Name und Hex-Code können zusammenpassen, oder eben nicht. Damit wir wissen, ob die Kombination aus Name der Farbe und Farb-Code korrekt ist, haben wir noch eine vierte Variable, die wir isCorrect nennen. Die ist vom Typ boolean, kann also wahr (true) oder falsch (false) sein.

Farben definieren

Als nächstes definieren wir alle Farben, die in unserem Spiel vorkommen können. Das machen wir im Konstruktor unserer Klasse. Du kannst natürlich auch andere Farben verwenden und die Liste noch erweitern.

Wahrscheinlichkeit der richtigen Kombination

Als nächstes definieren wir eine Konstante, die angibt, mit welcher Wahrscheinlichkeit unsere zufällig ausgewählte Kombination aus Name der Farbe und Farb-Code übereinstimmen soll. Diese Konstante nennen wir MATCH_CHANCE. Ich habe sie mit 40% definiert. Der Typ ist int, also eine ganze Zahl, und der Wert ist einfach 40.

public final static int MATCH_CHANCE = 40;

Zufallsgenerator

Nun kommen wir zu wichtigsten Methode. Sie heißt „shuffle“ und wird eine Kombination zufällig auswählen unter Berücksichtigung unserer eben definierten Konstante.

Gehen wir die Methode mal Zeile für Zeile durch.

Wir erzeugen eine neue Instanz der Random-Klasse. Die ist in Java für die Erzeugung von Zufallszahlen zuständig. In der zweiten Zeile erzeugen wir dann eine zufällige Zahl zwischen 0 und der Anzahl aller Farben in unserer colorMap. Dazu rufen wir random.nextInt auf und übergeben die Obergrenze in Klammern als Argument an. Mit colorMap.size ermitteln wir die Anzahl der Zeilen in unserer colorMap. Die Zufallszahl merken wir uns in der Variablen colorIndex.

Random random = new Random();
int colorIndex = random.nextInt(colorMap.size());

Als nächstes nehmen wir aus der colorMap den Schlüssel (key) der zufällig ausgewählten Zeile mit dem Befehl colorMap.keyAt. Das ist der Name der Farbe. Auch den hexadezimalen Code der Farbe nehmen wir uns aus der colorMap. Dazu nutzen wir die Methode colorMap.valueAt.

colorName = colorMap.keyAt(colorIndex);
color = colorMap.valueAt(colorIndex);

Dann erzeugen wir eine zweite zufällige Zahl, diesmal zwischen 0 und 100. Wir übergeben also 100 als Obergrenze. Diese Zahl nutzen wir, um zufällig zu bestimmen, ob die Kombination aus Name der Farbe und Farb-Code im Spiel korrekt sein wird oder eben nicht. Wenn unsere zufällig erzeugte Zahl kleiner oder gleich der oben definierten Konstante (40) ist, dann soll die Kombination korrekt sein, ansonsten soll sie falsch sein.

int randomNumber = random.nextInt(100);
isCorrect = randomNumber <= MATCH_CHANCE;

Wenn die Kombination falsch sein soll, müssen wir sie überarbeiten. Dabei würde es reichen, wenn wir den Namen der Farbe ändern. Dieser darf dann aber nicht mehr mit der Farbe übereinstimmen. Dazu erzeugen wir eine neue zufällige Zahl zwischen 0 und der Anzahl aller Farben in unserer colorMap. Diese neue zufällige Zahl nennen wir wrongColorIndex. Sie entspricht wieder einer Zeile in der colorMap. Wir nehmen den Schlüssel dieser Zeile und weisen sie der Variable colorName zu. So ändern wir den Namen der Farbe. Das ganze umschließen wir mit einem Schleifenaufruf. Warum? Weil wir sicherstellen müssen, dass am Ende der Name der Farbe und der Farb-Code nicht zusammenpassen. Das prüfen wir in der Schleifenbedingung mit while (colorIndex == wrongColorIndex). Das heißt, wir wiederholen den Vorgang so lange wie colorIndex und wrongColorIndex gleich sind.

if (!isCorrect) {
    int wrongColorIndex;
    do {
        wrongColorIndex = random.nextInt(colorMap.size());
        colorName = colorMap.keyAt(wrongColorIndex);
    } while (colorIndex == wrongColorIndex);
}

Das nennen wir fußgesteuerte Wiederholung. Das ist eine Schleife, bei der die Bedingung am Ende steht. Die Schleife wird also mindestens einmal durchlaufen. Dann wird geprüft, ob die Bedingung wahr wird. Falls ja, wird die Schleife noch einmal wiederholt. Dann wird wieder geprüft. Das passiert so lange bis die Bedingung falsch wird. Dann endet die Wiederholung. Also genau dann, wenn wrongColorIndex anders ist als colorIndex, endet die Schleife. Dann ist sichergestellt, dass der Name der Farbe nicht dem Farb-Code entspricht. Und genau das wollen wir, wenn die Kombination falsch sein soll.

Getter hinzufügen

Damit wir unseren ColorShuffler auch überall richtig benutzen können, sollten wir noch öffentliche Methoden hinzufügen, um Name der Farbe, Farb-Code und das boolean abrufen zu können. Diese Methoden nennt man Getter. Das kommt vom englischen Wort „get“, also etwas holen.

ColorShuffler in SinglePlayerActivity nutzen

Als nächstes müssen wir noch unsere SinglePlayerActivity anpassen und dort den ColorShuffler nutzen. Den ColorShuffler deklarieren wir ganz oben. Dabei erstellen wir auch gleich eine neue Instanz.

ColorShuffler colorShuffler = new ColorShuffler();

Dann implementieren wir die changeColor-Methode. Dabei rufen wir die shuffle-Methode auf dem ColorShuffler auf, so dass er zufällig eine Farbkombination erzeugt. Wir setzen anschließend die Hintergrundfarbe des Spiel-Buttons, setzen den Text des Spiel-Buttons und setzen einen OnClickListener auf den Spiel-Button, um zu reagieren, sobald der Nutzer auf den Button gedrückt hat.

Beim Setzen der Button-Hintergrundfarbe gibt es eine Besonderheit. Schauen wir uns die Zeile mal genauer an, von innen nach außen bzw. von rechts nach links.

button.setBackgroundColor(Color.parseColor(colorShuffler.getColor()));

Wir holen den Farb-Code aus dem ColorShuffler mit getColor. Wir erhalten einen String mit dem hexadezimalen Farb-Code. Die Methode setBackgroundColor verlangt allerdings eine Farbe in Form einer ganzen Zahl. Daher wandeln wir mit dem Aufruf Color.parseColor unseren String in ein Integer um.

Button-Click auswerten

Was soll passieren, wenn der Nutzer den Button geklickt hat? Das bestimmen wir in der Methode onButtonClick.

Wir prüfen zunächst, ob die Farbkombination auf dem Button korrekt ist. Falls ja, erhöhen wir die Punktzahl und rufen eine neue Methode auf, die wir updateScore nennen. In dieser Methode aktualisieren wir die ScoreView im Layout, um den neuen Punktestand anzuzeigen. Falls die Farbkombination nicht korrekt ist, soll das Spiel beenden. Daher rufen wir im else-Fall die Methode stopGame auf. Die haben wir ja schon im letzten Video implementiert.

Und so sieht updateScore aus:

Wir setzen den neuen Punktestand als Text auf die ScoreView. Dabei müssen wir die ganze Zahl des Punktestands in einen String umwandeln, da TextViews nur Strings anzeigen können. Das machen wir mit String.valueOf.

Denk auch daran in der restartGame-Methode die ScoreView zu aktualisieren, nachdem du den Punktestand dort auf 0 gesetzt hast. Hier muss also auch updateScore aufgerufen werden.

Das war’s schon! Viel Spaß beim Zocken! 🙂