Java:
package de.fernschulen;
import javafx.application.Application;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
import javafx.scene.Scene;
public class MemoryFX extends Application {
@Override
public void start(Stage meineStage) throws Exception {
//den obersten Knoten erzeugen
//hier verwenden wir ein FlowPane
//erzeugt wird die Oberfläche über eine eigene Methode in der Klasse MemoryFeld
FlowPane rootNode = new MemoryFeld().initGUI(new FlowPane());
//die Szene erzeugen
//an den Konstruktor werden der oberste Knoten und die Größe übergeben
Scene meineScene = new Scene(rootNode, 500, 600);
//den Titel über stage setzen
meineStage.setTitle("Memory");
//die Szene setzen
meineStage.setScene(meineScene);
//Größenänderungen verhindern
meineStage.setResizable(false);
//und anzeigen
meineStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
package de.fernschulen;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.image.ImageView;
import javafx.event.ActionEvent;
//die Klasse für eine Karte des Memory-Spiels
//Sie erbt von Button
public class MemoryKarte extends Button {
//die Instanzvariablen
//eine eindeutige ID zur Identifizierung des Bildes
private int bildID;
//für die Vorder- und Rückseite
private ImageView bildVorne, bildHinten;
//wo liegt die Karte im Spielfeld
private int bildPos;
//ist die Karte umgedreht?
private boolean umgedreht;
//ist die Karte noch im Spiel?
private boolean nochImSpiel;
//das Spielfeld für die Karte
private MemoryFeld spielfeld;
//die innere Klasse für den Eventhandler der Karte
class KartenHandler implements EventHandler<ActionEvent>{
@Override
public void handle(ActionEvent arg0) {
//ist die Karte überhaupt noch im Spiel?
//und sind Züge erlaubt
if ((nochImSpiel == false) || (spielfeld.zugErlaubt() == false))
return;
//wenn die Rückseite zu sehen ist, die Vorderseite anzeigen
if (umgedreht == false) {
vorderseiteZeigen();
//die Methode karteOeffnen() im Spielfeld aufrufen
//übergeben wird dabei die Karte
//also die this-Referenz der äußeren Klasse
spielfeld.karteOeffnen(MemoryKarte.this);
}
}
}
//der Konstruktor
//er setzt die Bilder
public MemoryKarte(String vorne, int bildID, MemoryFeld spielfeld) {
//die Vorderseite, der Dateiname des Bildes wird an den Konstruktor übergeben
bildVorne = new ImageView(vorne);
//die Rückseite, sie wird fest gesetzt
bildHinten = new ImageView("grafiken/back.jpg");
setGraphic(bildHinten);
//die Bild-ID
this.bildID = bildID;
//die Karte ist erst einmal umgedreht und noch im Feld
umgedreht = false;
nochImSpiel = true;
//mit dem Spielfeld verbinden
this.spielfeld = spielfeld;
//die Action setzen
setOnAction(new KartenHandler());
}
//da MemoryKarte von der Klasse Button erbt und somit
//Schaltflächen erzeugen kann, erstelle ich
//einen weiteren Konstruktor, der es ermöglicht einen Button
//in der Klasse MemoryFeld
//mit dem Typ der Klasse MemoryKarte zu erzeugen
//der dann Methoden der Klasse MemoryKarte aufrufen kann
public MemoryKarte (String text) {
setText(text); // setzt den Text auf der Schaltfläche, wird im Konstruktor als Argument übergeben
}
//die Methode zeigt die Vorderseite der Karte an
public void vorderseiteZeigen() {
setGraphic(bildVorne);
umgedreht = true;
}
//die Methode zeigt die Rückseite der Karte an
public void rueckseiteZeigen(boolean rausnehmen) {
//soll die Karten komplett aus dem Spiel genommen werden?
if (rausnehmen == true) {
//das Bild aufgedeckt zeigen und die Karte aus dem Spiel nehmen
setGraphic(new ImageView("grafiken/aufgedeckt.jpg"));
nochImSpiel = false;
}
else {
//sonst nur die Rückseite zeigen
setGraphic(bildHinten);
umgedreht = false;
}
}
//die Methode liefert die Bild-ID einer Karte
public int getBildID() {
return bildID;
}
//die Methode liefert die Position einer Karte
public int getBildPos() {
return bildPos;
}
//die Methode setzt die Position einer Karte
public void setBildPos(int bildPos) {
this.bildPos = bildPos;
}
//die Methode liefert den Wert der Variablen umgedreht
public boolean isUmgedreht() {
return umgedreht;
}
//die Methode liefert den Wert der Variablen nochImSpiel
public boolean isNochImSpiel() {
return nochImSpiel;
}
}
package de.fernschulen;
//für die Klassen Arrays und Collections
import java.util.Arrays;
import java.util.Collections;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.util.Duration;
public class MemoryFeld {
//eine innere Klasse für den Eventhandler des Timer
class TimerHandler implements EventHandler<ActionEvent> {
@Override
//die Methode ruft die Methode karteSchliessen() auf
public void handle(ActionEvent arg0) {
karteSchliessen();
}
}
//zu EA 13.3
//eine innere Klasse für den Schummel-Button
class Schummler implements EventHandler<ActionEvent>{
@Override
//die Methode ruft die Methode allesAufdecken() auf
public void handle(ActionEvent e) {
//schummeln.setOnAction(new Schummler());
//if(e.getSource() instanceof Schummler)
allesAufdecken();
}
}
//das Array für die Karten
private MemoryKarte[] karten;
//das Array für die Namen der Grafiken
private String[] bilder = {"grafiken/apfel.jpg", "grafiken/birne.jpg", "grafiken/blume.jpg", "grafiken/blume2.jpg",
"grafiken/ente.jpg", "grafiken/fisch.jpg", "grafiken/fuchs.jpg", "grafiken/igel.jpg",
"grafiken/kaenguruh.jpg", "grafiken/katze.jpg", "grafiken/kuh.jpg", "grafiken/maus1.jpg",
"grafiken/maus2.jpg", "grafiken/maus3.jpg", "grafiken/melone.jpg", "grafiken/pilz.jpg",
"grafiken/ronny.jpg", "grafiken/schmetterling.jpg","grafiken/sonne.jpg",
"grafiken/wolke.jpg", "grafiken/maus4.jpg"};
//für die Punkte
private int menschPunkte, computerPunkte;
//zwei Labels für die Punkte
private Label menschPunkteLabel, computerPunkteLabel, aktuellerSpielerLabel; //aktuellerSpielerLabel für EA13.2
//wie viele Karten sind aktuell umgedreht?
private int umgedrehteKarten;
//für das aktuell umdrehte Paar
private MemoryKarte[] paar;
//für den aktuellen Spieler
private int spieler;
//das "Gedächtnis" für den Computer
//er speichert hier wo das Gegenstück liegt
private int[][] gemerkteKarten;
//für die Spielstärke
private int spielstaerke;
//für den Timer
private Timeline timer;
//für die Ausgabe des aktuellen Spielers
//zu EA 13.2
private String esSpielt;
//für die Schummelfunktion
//zu EA 13.3
private MemoryKarte schummeln;
//eine Variable des Typs MemoryKarte um
//Methode aus der Klasse MemoryKarte öffnen zu können
//private MemoryKarte kartenKlasse;
//der Konstruktor
public MemoryFeld() {
//das Array für die Karten erstellen, insgesamt 42 Stück
karten = new MemoryKarte[42];
//für das Paar
paar = new MemoryKarte[2];
//für das Gedächtnis
//es speichert für jede Karte paarweise die Position im Spielfeld
gemerkteKarten = new int[2][21];
//keiner hat zu Beginn einen Punkt
menschPunkte = 0;
computerPunkte = 0;
//es ist keine Karte umgedreht
umgedrehteKarten = 0;
//der Mensch fängt an
spieler = 0;
//die Spielstärke ist 10
spielstaerke = 10;
//es gibt keine gemerkten Karten
for (int aussen = 0; aussen < 2; aussen++)
for (int innen = 0; innen < 21; innen++)
gemerkteKarten[aussen][innen] = -1;
}
//die Methode erstellt die Oberfläche und zeichnet die Karten über eine eigene Methode
//übergeben wird ein FlowPane
public FlowPane initGUI(FlowPane feld) {
//für die Ausgaben
kartenZeichnen(feld);
menschPunkteLabel = new Label();
computerPunkteLabel = new Label();
//Aufgabe 13.2
//Label erzeugen, das den aktuellen Spieler anzeigt
//zunächst wird das Label mit "Der Mensch" beschriftet und später in der
//Methode spielerWechsel() verändert
aktuellerSpielerLabel = new Label();
aktuellerSpielerLabel.setText("Der Mensch");
menschPunkteLabel.setText(Integer.toString(menschPunkte));
computerPunkteLabel.setText(Integer.toString(computerPunkte));
//den Button für die Schummelfunktion erzeugen
//aktiviert wird er in der Methode spielerWechsel()
schummeln = new MemoryKarte("Schummeln");
//schummeln.setActionCommand("geschummelt");
//Button mit dem EventHandler verbinden
schummeln.setOnAction(new Schummler());
//in zwei Spalten anzeigen
GridPane tempGrid = new GridPane();
//und einfügen, dabei werden die Koordinaten angegeben
tempGrid.add(new Label("Mensch: "), 0 , 0 );
tempGrid.add(menschPunkteLabel, 1, 0);
tempGrid.add(new Label("Computer: "), 0, 1);
tempGrid.add(computerPunkteLabel, 1 ,1);
//Label einfügen, das den aktuellen Spieler anzeigt
tempGrid.add(new Label("Aktueller Spieler: "), 0, 2);
tempGrid.add(aktuellerSpielerLabel, 1,2);
//den Schummel-Button einfügen
tempGrid.add(schummeln,0, 3);
//Button mit dem EventHandelr verbinden
//schummeln.setOnAction(new Schummler());
feld.getChildren().add(tempGrid);
return feld;
}
//das eigentliche Spielfeld erstellen
private void kartenZeichnen(FlowPane feld) {
int count = 0;
for (int i = 0; i <= 41; i++) {
//eine neue Karte erzeugen
karten[i] = new MemoryKarte(bilder[count], count, this);
//bei jeder zweiten Karte kommt auch ein neues Bild
if ((i + 1) % 2 == 0)
count++;
}
//die Karten werden gemischt
Collections.shuffle(Arrays.asList(karten));
//und ins Spielfeld gesetzt
for (int i = 0; i <= 41; i++) {
feld.getChildren().add(karten[i]);
//die Position der Karte setzen
karten[i].setBildPos(i);
}
}
//die Methode übernimmt die wesentliche Steuerung des Spiels
//Sie wird beim Anklicken einer Karte ausgeführt
public void karteOeffnen(MemoryKarte karte) {
//zum Zwischenspeichern der ID und der Position
int kartenID, kartenPos;
//die Karten zwischenspeichern
paar[umgedrehteKarten]=karte;
//die ID und die Position beschaffen
kartenID = karte.getBildID();
kartenPos = karte.getBildPos();
//die Karte in das Gedächtnis des Computers eintragen
//aber nur dann, wenn es noch keinen Eintrag an der entsprechenden Stelle gibt
if ((gemerkteKarten[0][kartenID] == -1))
gemerkteKarten[0][kartenID] = kartenPos;
else
//wenn es schon einen Eintrag gibt
//und der nicht mit der aktuellen Position übereinstimmt, dann haben wir die
//zweite Karte gefunden
//die wird dann in die zweite Dimension eingetragen
if (gemerkteKarten[0][kartenID] != kartenPos)
gemerkteKarten[1][kartenID] = kartenPos;
//umgedrehte Karten erhöhen
umgedrehteKarten++;
//sind zwei Karten umgedreht worden?
if (umgedrehteKarten == 2) {
//dann prüfen wir, ob es ein Paar ist
paarPruefen(kartenID);
//den Timer erzeugen
timer = new Timeline(new KeyFrame(Duration.millis(2000), new TimerHandler()));
//und starten
timer.play();
}
//haben wir zusammen 21 Paare, dann ist das Spiel vorbei
if (computerPunkte + menschPunkte == 21) {
//Methode aufrufen, die den Gewinner-Dialog erzeugt
gewinnerDialog();
//dann die Anwendung beenden
Platform.exit();
}
}
//Einsendeaufgabe 13.1
//die Methode erstellt einen Dialog, der den Gewinner bekannt gibt
//sie wird am Ende der Methode karteOeffnen() aufgerufen, bevor die Anwendung geschlossen wird
private void gewinnerDialog() {
//Zur Anzeige des Gewinnners
String gewinner;
if(computerPunkte > menschPunkte)
gewinner = "Computer!";
else
gewinner = "Mensch!";
//den Dialog erzeugen
Alert meinDialog = new Alert(AlertType.INFORMATION,"Gewonnen hat der "+gewinner);
//den Text setzten
meinDialog.setHeaderText("Herzlichen Glückwunsch!");
//den Titel setzten
meinDialog.setTitle("Gewinner");
//den Dialog anzeigen
meinDialog.showAndWait();
}
//die Methode dreht die Karten wieder auf die Rückseite
//bzw. nimmt sie aus dem Spiel
private void karteSchliessen() {
boolean raus = false;
//ist es ein Paar?
if (paar[0].getBildID() == paar[1].getBildID())
raus = true;
//wenn es ein Paar war, nehmen wir die Karten aus dem Spiel
//sonst drehen wir sie nur wieder um
paar[0].rueckseiteZeigen(raus);
paar[1].rueckseiteZeigen(raus);
//es ist keine Karte mehr geöffnet
umgedrehteKarten = 0;
//hat der Spieler kein Paar gefunden?
if (raus == false)
//dann wird der Spieler gewechselt
spielerWechseln();
else
//hat der Computer ein Paar gefunden?
//dann ist er noch einmal an der Reihe
if (spieler == 1)
computerZug();
}
//die Methode prüft, ob ein Paar gefunden wurde
private void paarPruefen(int kartenID) {
if (paar[0].getBildID() == paar[1].getBildID()) {
//die Punkte setzen
paarGefunden();
//die Karten aus dem Gedächtnis löschen
gemerkteKarten[0][kartenID]=-2;
gemerkteKarten[1][kartenID]=-2;
}
}
//die Methode setzt die Punkte, wenn ein Paar gefunden wurde
private void paarGefunden() {
//spielt gerade der Mensch?
if (spieler == 0) {
menschPunkte++;
menschPunkteLabel.setText(Integer.toString(menschPunkte));
}
else {
computerPunkte++;
computerPunkteLabel.setText(Integer.toString(computerPunkte));
}
}
//die Methode wechselt den Spieler
//und zeigt den aktuellen Spieler im Label an (Einsendeaufgabe 13.2)
private void spielerWechseln() {
//wenn der Mensch an der Reihe war,
//kommt jetzt der Computer
if (spieler == 0) {
spieler = 1;
esSpielt = "Der Computer";
aktuellerSpielerLabel.setText(esSpielt);
//der Schummel-Button wird deaktiviert
schummeln.setDisable(true);
computerZug();
}
else {
spieler = 0;
esSpielt= "Der Mensch";
aktuellerSpielerLabel.setText(esSpielt);
//der Schummel-Button wird aktiviert
schummeln.setDisable(false);
}
}
//zu EA 13.3
//die Methode für die Schummelfunktion
//mit Timer
private void allesAufdecken() {
/*
for (int aussen = 0; aussen < 2; aussen++)
for (int innen = 0; innen < 21; innen++)
if (gemerkteKarten[aussen][innen] >= -1)
*/
schummeln.vorderseiteZeigen();
}
//die Methode setzt die Computerzüge um
private void computerZug() {
int kartenZaehler = 0;
int zufall = 0;
boolean treffer = false;
//zur Steuerung über die Spielstärke
if ((int)(Math.random() * spielstaerke) == 0) {
//erst einmal nach einem Paar suchen
//dazu durchsuchen wir das Array gemerkteKarten, bis wir in beiden Dimensionen
//einen Wert finden
while ((kartenZaehler < 21) && (treffer == false)) {
//gibt es in beiden Dimensionen einen Wert größer oder gleich 0?
if ((gemerkteKarten[0][kartenZaehler] >=0) && (gemerkteKarten[1][kartenZaehler] >=0)) {
//dann haben wir ein Paar
treffer = true;
//die Vorderseite der Karte zeigen
karten[gemerkteKarten[0][kartenZaehler]].vorderseiteZeigen();
//und dann die Karte öffnen
karteOeffnen(karten[gemerkteKarten[0][kartenZaehler]]);
//die zweite Karte auch
karten[gemerkteKarten[1][kartenZaehler]].vorderseiteZeigen();
karteOeffnen(karten[gemerkteKarten[1][kartenZaehler]]);
}
kartenZaehler++;
}
}
//wenn wir kein Paar gefunden haben, drehen wir zufällig zwei Karten um
if (treffer == false) {
//solange eine Zufallszahl suchen, bis eine Karte gefunden wird, die noch im Spiel ist
do {
zufall = (int)(Math.random() * karten.length);
} while (karten[zufall].isNochImSpiel() == false);
//die erste Karte umdrehen
//die Vorderseite der Karte zeigen
karten[zufall].vorderseiteZeigen();
//und dann die Karte öffnen
karteOeffnen(karten[zufall]);
//für die zweite Karte müssen wir außerdem prüfen, ob sie nicht gerade angezeigt wird
do {
zufall = (int)(Math.random() * karten.length);
} while ((karten[zufall].isNochImSpiel() == false) || (karten[zufall].isUmgedreht() == true));
//und die zweite Karte umdrehen
karten[zufall].vorderseiteZeigen();
karteOeffnen(karten[zufall]);
}
}
//die Methode liefert, ob Züge des Menschen erlaubt sind
//die Rückgabe ist false, wenn gerade der Computer zieht
//oder wenn schon zwei Karten umgedreht sind
//sonst ist die Rückgabe true
public boolean zugErlaubt() {
boolean erlaubt = true;
//zieht der Computer?
if (spieler == 1)
erlaubt = false;
//sind schon zwei Karten umdreht?
if (umgedrehteKarten == 2)
erlaubt = false;
return erlaubt;
}
}
Lassen Sie am Ende des Memory-Spiels ausgeben, wer gewonnen hat. Damit der Spieler diese Ausgabe lesen kann, sorgen Sie bitte außerdem dafür, dass das Spiel nicht sofort nach dem Ende geschlossen wird.
Welche Technik Sie dazu verwenden, ist Ihnen freigestellt. Sie können zum Beispiel die Ausgabe in einem Label durchführen und das Spiel über einen Timer beenden.
2. Aufgabe:
Erstellen Sie für das Memory-Spiel eine Anzeige des aktuellen Spielers. Lassen Sie dazu in einem Label unterhalb des Spielfelds anzeigen, ob gerade der Mensch zieht oder der Computer.
3. Aufgabe:
Bauen Sie eine „Schummel“-Funktion in das Memory-Spiel ein. Ergänzen Sie dazu eine Schaltfläche Alles aufdecken. Beim Anklicken der Schaltfläche sollen alle noch nicht aufgedeckten Karten für eine bestimmte Zeit angezeigt und danach automatisch wieder umgedreht werden.
Sorgen Sie dafür, dass die „Schummel“-Funktion nur dann aufgerufen werden kann, wenn gerade der Mensch am Zug ist und wenn keine andere Karte angezeigt wird. Dazu können Sie zum Beispiel die Schaltfläche zum Starten der „Schummel“-Funktion je nach Spielzustand aktivieren beziehungsweise deaktivieren.
FRAGE:
Aufgabe 1 + 2 habe ich gelöst und die funktionieren auch. Ob es perfekt ist, sei mal hingestellt
Zu Aufgabe 3:
Den Button zur Schummelfunktion habe ich als Instanz der Klasse MemoryKarten erstellt , da die ja von der Klasse Button erbt und Schaltflächen erstellen kann. Die Idee war dann mit dieser Instanz eine Methode der Klasse MemoryKarte in der Klasse MemoryFeld aufzurufen. Man sieht vielleicht noch an den Kommentaren, dass ich einiges versucht habe aber die Verbindung zwischen den Klassen und dem Button nicht hinbekomme und keinen Plan habe , wie ich alle Karten anzeigen lassen soll. Bin für Gedankenhilfen dankbar