studyklar
GdI 2 · Übungsblatt 10 · Aufgabe 3

Schere, Stein, Papier im Fenster mit ComboBox

Schere, Stein, Papier kennen wir schon als Konsolenprogramm. Jetzt bekommt das Spiel ein Fenster: Man wählt in einer Auswahlliste, das Fenster zeigt die Wahl des Computers, den Gewinner und den Spielstand. Rechts steht das ganze Programm, die Zeilen zum aktuellen Schritt sind hervorgehoben. Mit Weiter geht es Schritt für Schritt voran.

Die Aufgabe

Aufgabe 3

Zu einer Aufgabe in Übungsblatt 2 wurde bereits das Spiel „SchnickSchnackSchuck“ programmiert, wobei die Ein- und Ausgaben in der Konsole erfolgte. Nun soll das Spiel als JavaFX-Anwendung über ein Fenster bedient werden.

Hierzu wird die bereitgestellte Klasse SchnickSchnackSchnuck verwendet.

Das von der Anwendung erstellte Fenster soll mit der erforderlichen Funktionalität versehen werden. Der Benutzer wählt in der ComboBox Schere, Stein oder Papier aus. Daraufhin wird die zufällige Wahl des Computers angezeigt, sowie der Gewinner und der aktualisierte Spielstand. Drückt man „Noch einmal“, so werden die Auswahl-ComboBox ebenso wie die Anzeige der Computer-Wahl und des Gewinners zurückgesetzt, und man kann eine weitere Runde spielen.

Schnick Schnack Schnuck

das Fenster als Skizze
Spalte 0Spalte 1
Deine Wahl:[ Auswahlliste ▾ ]
Wahl des Computers:***
Gewinner:(leer)
SpielstandComputer: 0, Du: 0
[ Noch einmal ] (unter dem Raster)

Hinweise: Um auf den Klick auf die gewünschte Wahl in der ComboBox zu reagieren, kann man – wie bei einem Button – die Methode setOnAction verwenden. Den vom Benutzer in der ComboBox ausgewählten Wert erhält man mit Hilfe der Methode „getValue“.

Nach getroffener Wahl und der Anzeige des Ergebnisses soll die ComboBox zunächst deaktiviert werden. Dies erreicht man mittels comboBox.setDisable(true).

Drückt man den Button „Noch einmal“, so wird die comboBox wieder aktiviert (mittels comboBox.setDisable(false)). Zudem wird der gewählte Wert auf null gesetzt (comboBox.setValue(null)).

Für die zufällige Auswahl des Computers und die Ermittlung des Gewinners können Sie den Code aus Ihrer Lösung aus dem Übungsblatt 2 kopieren.

Das Fenster ist vorgegeben, ihm fehlt nur das Verhalten. Die vorgegebene Klasse liegt uns nicht vor; das Fenster hier (Zeilen 21 bis 55) stammt aus der Musterlösung. Neu zu schreiben sind die Attribute (Zeilen 14 bis 16), die beiden Reaktionen (57 bis 74) und die zwei Methoden für Zufall und Gewinner (77 bis 117).

Die Spiellogik übernehmen wir aus Blatt 2, wie die Aufgabe erlaubt. Die Musterlösung nimmt dort eine kürzere Variante mit einer einzigen Bedingung; wir bleiben bei der Fassung mit einer Regel je Fall, die Blatt 2 Schritt für Schritt erklärt.

Merke: Ein Fensterprogramm wartet auf Ereignisse. Statt einer Schleife wie in Blatt 2 gibt es Lambdas, die JavaFX bei jedem Ereignis aufruft: hier bei einer Wahl in der Liste und beim Drücken von „Noch einmal“.
  1. Das vorgegebene Fenster lesen.
  2. Spielstand als Attribute, Zufall und Gewinner als Methoden aus Blatt 2.
  3. Auf die Wahl reagieren, dann auf „Noch einmal“.
  4. Ein Probelauf.

Das vorgegebene Fenster lesen

        VBox root = new VBox(15);        root.setPadding(new Insets(15));         GridPane gridPane = new GridPane();        gridPane.setPadding(new Insets(15));        gridPane.setHgap(10);        gridPane.setVgap(10);
        ComboBox<String> comboBox = new ComboBox<>();        comboBox.getItems().addAll("Schere", "Stein", "Papier");         gridPane.add(label1, 0, 0);        gridPane.add(comboBox, 1, 0);        gridPane.add(label2, 0, 1);        gridPane.add(computerWahlLabel, 1, 1);        gridPane.add(label3, 0, 2);        gridPane.add(ergebnisLabel, 1, 2);        gridPane.add(label4, 0, 3);        gridPane.add(spielstandLabel, 1, 3);
Zeile im RasterSpalte 0Spalte 1 (Name im Code)
0Deine Wahl:comboBox
1Wahl des Computers:computerWahlLabel
2Gewinner:ergebnisLabel
3SpielstandspielstandLabel

Außen liegt eine VBox. new VBox(15) gibt den Abstand zwischen ihren Kindern gleich im Konstruktor an; das ist dasselbe wie setSpacing(15). Dazu kommen 15 Pixel Rand (Padding). Die VBox enthält ein GridPane und darunter den Button „Noch einmal“.

Ein GridPane ordnet seine Kinder in einem Raster aus Spalten und Zeilen an. setHgap(10) legt 10 Pixel zwischen die Spalten, setVgap(10) 10 Pixel zwischen die Zeilen. gridPane.add(knoten, spalte, zeile) setzt einen Knoten in eine Zelle; gezählt wird ab 0.

comboBox.getItems() liefert die Liste der Einträge, die die ComboBox zur Auswahl anbietet. addAll hängt die drei Wahlen an, wie bei getChildren().addAll in einer HBox.

Aus Blatt 10, Aufgabe 1 („Fenster „Geld Aufladen“ und sein Scene-Graph“): Eine VBox ordnet Knoten untereinander an. setPadding setzt den Rand zwischen Container und Inhalt, setSpacing den Abstand zwischen den Knoten; getChildren().addAll fügt Kinder in dieser Reihenfolge ein.

Links stehen die festen Beschriftungen, rechts die Teile, die sich ändern: die ComboBox (eine Auswahlliste zum Aufklappen) und drei Labels. Diese drei Labels und die ComboBox haben eigene Namen, weil unser Code sie später ändert.

Aus Vorlesung 12, Folie 21 („Verschiedene Arten von Containern (1)“): GridPane ordnet Knoten in einem Raster aus Spalten und Zeilen an; die Zelle wird als (Spalte, Zeile) angegeben.
Aus Vorlesung 12, Folie 29 („Einige Controls und nützliche Methoden (2)“): Eine ComboBox ist eine Auswahl aus einem Dropdown-Menü, einer Liste zum Aufklappen.

Der Spielstand als Attribute

    private int siegeComputer = 0;    private int siegeSpieler = 0;    private Random r = new Random(); // Zufallsgenerator

Der Spielstand muss von Runde zu Runde erhalten bleiben. Jede Runde ist ein eigener Aufruf des Lambdas, eine Schleife wie in Blatt 2 gibt es nicht. Eine lokale Variable in start hilft nicht: Ein Lambda darf eine lokale Variable nicht ändern. Wir haben es ausprobiert; der Compiler meldet dann, sie müsse „final oder effektiv final“ sein, also unveränderlich.

Darum werden die Zähler Attribute des Objekts. Sie leben so lange wie das Fenster, und jede Methode der Klasse darf sie ändern. Auch der Zufallsgenerator r wird ein Attribut: einmal angelegt, in jeder Runde benutzt.

Aus Blatt 5, Aufgabe 1 („Eine eigene Klasse Tier mit Konstruktor und toString“): Attribute stehen in der Klasse außerhalb der Methoden. Jedes Objekt hat seine eigenen Werte, und alle Methoden des Objekts können sie lesen und ändern.
Noch 6 Schritte bis zum Ergebnis
Den ganzen Lösungsweg sehen Studierende und Lehrende der HS KL. Registriere dich mit deiner Adresse @stud.hs-kl.de oder @hs-kl.de, dann geht es hier direkt weiter.

SchnickSchnackSchnuck.java

neu: 14–16, 57–74, 77–117

Abbildung 1SchnickSchnackSchnuck.java

neu: 14–16, 57–74, 77–117

import java.util.Random;import javafx.application.Application;import javafx.geometry.Insets;import javafx.scene.Scene;import javafx.scene.control.Button;import javafx.scene.control.ComboBox;import javafx.scene.control.Label;import javafx.scene.layout.GridPane;import javafx.scene.layout.VBox;import javafx.stage.Stage; public class SchnickSchnackSchnuck extends Application {     private int siegeComputer = 0;    private int siegeSpieler = 0;    private Random r = new Random(); // Zufallsgenerator     @Override    public void start(Stage primaryStage) {         VBox root = new VBox(15);        root.setPadding(new Insets(15));         GridPane gridPane = new GridPane();        gridPane.setPadding(new Insets(15));        gridPane.setHgap(10);        gridPane.setVgap(10);         Label label1 = new Label("Deine Wahl:");        Label label2 = new Label("Wahl des Computers:");        Label computerWahlLabel = new Label("***");        Label label3 = new Label("Gewinner: ");        Label ergebnisLabel = new Label("");        Label label4 = new Label("Spielstand ");        Label spielstandLabel = new Label("Computer: 0, Du: 0");        Button nochmalButton = new Button("Noch einmal");         ComboBox<String> comboBox = new ComboBox<>();        comboBox.getItems().addAll("Schere", "Stein", "Papier");         gridPane.add(label1, 0, 0);        gridPane.add(comboBox, 1, 0);        gridPane.add(label2, 0, 1);        gridPane.add(computerWahlLabel, 1, 1);        gridPane.add(label3, 0, 2);        gridPane.add(ergebnisLabel, 1, 2);        gridPane.add(label4, 0, 3);        gridPane.add(spielstandLabel, 1, 3);         root.getChildren().addAll(gridPane, nochmalButton);         Scene scene = new Scene(root, 500, 250);        primaryStage.setScene(scene);        primaryStage.setTitle("Schnick Schnack Schnuck");        primaryStage.show();         comboBox.setOnAction(e -> {            String benutzerWahl = comboBox.getValue();            if (benutzerWahl != null) {                String computerWahl = erzeugeComputerWahl();                String ergebnis = ermittleErgebnis(benutzerWahl, computerWahl);                computerWahlLabel.setText(computerWahl);                ergebnisLabel.setText(ergebnis);                spielstandLabel.setText("Computer: " + siegeComputer + ", Du: " + siegeSpieler);                comboBox.setDisable(true);            }        });         nochmalButton.setOnAction(e -> {            comboBox.setDisable(false);            comboBox.setValue(null);            computerWahlLabel.setText("***");            ergebnisLabel.setText("");        });    }     private String erzeugeComputerWahl() {        int i = r.nextInt(1, 4); // Erzeugt zufällige Zahl zwischen 1 und 3         String computerWahl = "Schere";        if (i == 1) {            computerWahl = "Papier";        } else if (i == 2) {            computerWahl = "Stein";        }        return computerWahl;    }     private String ermittleErgebnis(String benutzerWahl, String computerWahl) {        if (computerWahl.equals(benutzerWahl)) {            return "Unentschieden - beide haben " + computerWahl + " gewählt";        } else if (computerWahl.equals("Schere")) {            if (benutzerWahl.equals("Papier")) {                siegeComputer++;                return "Computer gewinnt - Schere schneidet Papier";            } else { // Benutzer muss Stein gewählt haben                siegeSpieler++;                return "Benutzer gewinnt - Stein schleift Schere";            }        } else if (computerWahl.equals("Stein")) {            if (benutzerWahl.equals("Papier")) {                siegeSpieler++;                return "Benutzer gewinnt - Papier wickelt Stein ein";            } else { // Benutzer muss Schere gewählt haben                siegeComputer++;                return "Computer gewinnt - Stein schleift Schere";            }        } else { // Computer muss Papier gewählt haben            if (benutzerWahl.equals("Stein")) {                siegeComputer++;                return "Computer gewinnt - Papier wickelt Stein ein";            } else { // Benutzer muss Schere gewählt haben                siegeSpieler++;                return "Benutzer gewinnt - Schere schneidet Papier";            }        }    }     public static void main(String[] args) {        launch(args);    }}
LegendeDas ganze Programm.