Memory Kartenspiel - Schummelfunktion

Guten Tag liebe Java-Gemeinde,

aktuell schlage ich mich mit einem Memoryspiel rum und bräuchte mal ein par symantische Ratschläge.

In der Aufgabe wird gefordert dass ich ein Memoryfeld durch eine Schummelfunktion offenlege.

Was ich bereits hinbekommen habe, ist dass alle Karten sichtbar und danach von selbst umgedreht werden...

Ich habe die Schummelfunktion über eine eigene Methode realisiert und einen Timer genutzt um das automatische umdrehen zu realisieren.

hier ein mal der Code für die Methode und den Timer

Java:
    class TimerSchummelnAus implements EventHandler<ActionEvent> {                             
        @Override
        //
        //die Methode
        public void handle(ActionEvent arg0) {
            // Dieser Code wird ausgeführt, wenn der Button geklickt wird
            for (int i = 0; i <= 41; i++) {
                if (karten[i].isNochImSpiel() == true) {
                karten[i].rueckseiteZeigen(false);
                karten[i + 1].rueckseiteZeigen(false);
                i++;
                }
            }
            System.out.println("Die Karten wurden rückgesetzt");
        }
    }


und hier für die Methode

Java:
//***************************************Aufgabe3***************************************
    //die Methode setzt die Schummelfunktion um.
    //
    //
    private void schummelfunktion() {
        //sicherstellen dass nur beim Menschenzug gedrückt werden darf
        if (spieler == 0) {
            //alle Karten auf dem Spielfeld aufdecken
            for (int i = 0; i <= 41; i++) {
                    if (karten[i].isNochImSpiel() == true && karten[i].isUmgedreht() == false) {
                        karten[i].vorderseiteZeigen();
                        System.out.println("Karte " + i + " ist noch im Spiel");
                        karten[i + 1].vorderseiteZeigen();
                        System.out.println("Karte " + (i + 1) + " ist noch im Spiel");
                        i++;
                    }
            }
            //den Timer erzeugen um die Karten nach 3 Sekunden umzudrehen.
            timer = new Timeline(new KeyFrame(Duration.millis(3000), new TimerSchummelnAus()));
            //und starten
            timer.play();
        }
    }
//***************************************Aufgabe3***************************************

irgendwie werde ich das Gefühl nicht los, dass die in Klammern gesetzten "i + 1" Geschichte mir aktuell die Probleme bereitet.

Beim 1. aufgedeckten Paar läuft alles noch tadellos und spätestens ab dem 2. aufgedeckten Paar erscheinen Probleme in Form von "ein Paar bleibt ständig zugedeckt; wird auf ein mal aufgedeckt; dann doch wieder nicht". Irgendwas kommt durcheinander....

Was ist eure Meinung?

Liebe Grüße...
 

majhul

Neues Mitglied
Hallo,

im Großen funktioniert es so, aber es wird später zu Problemen führen wenn die Array Grenze erreicht ist, da du diese nicht abgrenzt.
Außerdem wieso erhöhst du innerhalb der Schleife nochmal extra?

LG Majhul
 
danke dir für die Antwort majhul,

genau dass ist der Knackpunkt... aktuell wird im Feld nur jede zweite Karte aufgedeckt wenn ich diesen Extrabefehl nicht Anweise... möchtest du vielleicht mal den gesamten Quelltext in Augenschein nehmen?
 

majhul

Neues Mitglied
danke dir für die Antwort majhul,

genau dass ist der Knackpunkt... aktuell wird im Feld nur jede zweite Karte aufgedeckt wenn ich diesen Extrabefehl nicht Anweise... möchtest du vielleicht mal den gesamten Quelltext in Augenschein nehmen?
Worauf ich hinaus will ist in der Schleife direkt um 2 zu erhöhen. Ausserdem halt die letzte Zahl zu überprüfen damit es zu keiner ungeraden Zahl kommt, auch wenn es unwahrscheinlich ist mit der Logik jede 2. aufzudecken.
 

KonradN

Super-Moderator
Mitarbeiter
Also da einfach einmal meine Anmerkungen:

a) Wie schon angedeutet wurde: Du solltest Array-Grenzen nicht fest codieren! Dazu dient length vom Array. Du kannst also die Grösse vom Array karten über karten.length auslesen. Und wenn du in der Schleife auf index + 1 zugreifst, sollte dies in der Schleife berücksichtigt werden.
Und wie auch schon angedeutet wurde: Den Index einer Zählschleife sollte man nur im Schleifenkopf anpassen!
Das wäre dann also bei Dir eine Schleife wie:
for (int i+0: i < karten.length -1; i += 2) {
  • Der Index geht von 0 .. karten.length-1 und da wir auf i+1 zugreifen muss i immer < karten.length-1 sein!
  • Wir gehen in 2er Schritten vor, daher i =+ 2 (oder i = i + 2 falls Dir das besser gefällt)

b) Prüfen von boolean Werten: Code sollte lesbar sein. Und wie sprichst Du? Du fragst doch etwas in der Art: Bist Du volljährig? Du fragst nicht: Ist deine Volljährigkeit wahr?
Im Code ist es daher üblich, einfach nur zu schreiben if (karten[i].isNochImSpiel()) { - also ohne ein == true. Und statt == false negiert man es mit einem !: Der Ausdruck karten[i].isUmgedreht() == false wird also einfach zu !karten[i].isUmgedreht()

c) Du solltest einmal den ganzen Code zeigen. Prinzipiell sieht es korrekt aus, so Du die Paare immer auf Indices x und x+1 mit x gerade hast und Du den Status (noch im Spiel und umgedreht) korrekt setzt. Evtl. ist hier ein Fehler.
Und was Probleme bringen könnte: Wenn bereits eine Karte aufgedeckt wurde. Dann wird dieses Paar beim Schummeln nicht mit erfasst aber beim zurückdrehen wird die Karte mit erfasst. Aber ob das ein Problem ist, kann man nur sagen, wenn man das genaue Vorgehen sieht. Daher wäre es tatsächlich hilfreich, mehr vom Code zu sehen (am Besten wirklich alles).

d) Den Hinweis, die inneren Klassen durch Lambda Ausdrücke oder Methodenreferenzen zu ersetzen hatte ich im anderen Thread schon erläutert.
 
Erstmal danke ich euch für die Antworten...

im folgenden poste ich die Codes...

1. Main-Klasse
Java:
package de.fernschulen;


import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;

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, 480, 550);
//***************************************Aufgabe1***************************************
        Scene meineScene = new Scene(rootNode, 480, 600);
//***************************************Aufgabe1***************************************
        
        //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) {
        //der Start
        launch(args);
    }
}
 
2. Memoryfeld

Java:
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.Button;
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();
        }
    }
    
//***************************************Aufgabe1***************************************
    class TimerProgrammAus implements EventHandler<ActionEvent> {                             
        @Override
        //die Methode beendet das Programm
        public void handle(ActionEvent arg0) {
            Platform.exit();
        }
    }
//***************************************Aufgabe1***************************************
    
//***************************************Aufgabe3***************************************
    class TimerSchummelnAus implements EventHandler<ActionEvent> {                             
        @Override
        //
        //die Methode
        public void handle(ActionEvent arg0) {
            //
            for (int i = 0; i <= 41; i++) {
                if (karten[i].isNochImSpiel() == true) {
                karten[i].rueckseiteZeigen(false);
                //karten[i + 1].rueckseiteZeigen(false);
                i++;
                }
            }
            System.out.println("Die Karten wurden rückgesetzt");
        }
    }
//***************************************Aufgabe3***************************************
        
    //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 einen für den Sieger(Aufgabe 1) und eins für den aktuellen Spieler(Aufgabe 2)
    private Label menschPunkteLabel, computerPunkteLabel, sieger, aktuellerSpieler;
    
//***************************************Aufgabe3***************************************
    //einen Button für die Schummelfunktion
    private Button schummeln;
//***************************************Aufgabe3***************************************

    //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;   
    
    //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 = 0;
        
        //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();
        menschPunkteLabel.setText(Integer.toString(menschPunkte));
        computerPunkteLabel.setText(Integer.toString(computerPunkte));
//***************************************Aufgabe3***************************************
        schummeln = new Button();
        schummeln.setText("schummeln");
//***************************************Aufgabe3***************************************
//***************************************Aufgabe2***************************************
        aktuellerSpieler = new Label();
        aktuellerSpieler.setText("Der Mensch");
//***************************************Aufgabe2***************************************
//***************************************Aufgabe1***************************************
        sieger = new Label();
        sieger.setText("");
//***************************************Aufgabe1***************************************

        //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);
//***************************************Aufgabe2***************************************
        tempGrid.add(new Label("Es Zieht: "), 0, 2);
        tempGrid.add(aktuellerSpieler, 1, 2);
//***************************************Aufgabe2***************************************
//***************************************Aufgabe1***************************************
        tempGrid.add(new Label("Sieger: "), 0, 3);
        tempGrid.add(sieger, 1 ,3);
//***************************************Aufgabe1***************************************
//***************************************Aufgabe3***************************************
        tempGrid.add(schummeln, 1, 4);
//***************************************Aufgabe3***************************************
        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) {
//***************************************Aufgabe3***************************************
    // Aktion hinzufügen
    schummeln.setOnAction(event -> {
        schummelfunktion();
        //System.out.println("Button wurde geklickt!");
    });
//***************************************Aufgabe3***************************************
        
        //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) {
            abschlussDialog();
        }
    }
    
    //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
    private void spielerWechseln() {
        //wenn der Mensch an der Reihe war,
        //kommt jetzt der Computer
        if (spieler == 0) {
            spieler = 1;
            computerZug();
        }
        else
            spieler = 0;

//***************************************Aufgabe2***************************************
        //Prüfen ob der Menschliche Spieler dran ist und im Label ausgeben.
        if (spieler == 0) {
            aktuellerSpieler.setText("Der Mensch");
//***************************************Aufgabe3***************************************
//            schummelfunktion();
//***************************************Aufgabe3***************************************
        }
        else
          //Prüfen ob der Computer dran ist und im Label ausgeben.
          if (spieler == 1)
              aktuellerSpieler.setText("Der Computer");
//***************************************Aufgabe2***************************************
    }
    
    //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;
    }
    
//***************************************Aufgabe1***************************************
    //die Methode zeigt den Sieger des Memoryspiels an und beendet das Programm.
    private void abschlussDialog() {
        //Variable vereinbaren für die Anzeige des Siegers
        String sieger, headerDialog;

        //prüfen ob der Mensch mehr Punkte hat.
        //Falls ja hat er gewonnen und wenn nicht hat der Computer gewonnen.
        if (menschPunkte > computerPunkte) {
            this.sieger.setText("Der Mensch hat gewonnen");
            sieger = "Mensch";
            headerDialog = "Herzlichen Glückwunsch!";
        }
        else {
            this.sieger.setText("Der Computer hat gewonnen");
            sieger = "Computer";
            headerDialog = "Arbeite noch etwas an deinem Gedächtnis...";
        }
        //den Dialog erzeugen
        Alert meinDialog = new Alert(AlertType.INFORMATION,"Der " + sieger + " hat gesiegt!");
        //den Text setzen
        meinDialog.setHeaderText(headerDialog);
        //den Titel setzen
        meinDialog.setTitle("Gewinner");
        //den Dialog anzeigen
        meinDialog.showAndWait();

        //den Timer erzeugen um das Ende für 5 Sekunden hinaus zuzögern.
        timer = new Timeline(new KeyFrame(Duration.millis(5000), new TimerProgrammAus()));
        //und starten
        timer.play();
    }
//***************************************Aufgabe1***************************************
    
//***************************************Aufgabe3***************************************
    //die Methode setzt die Schummelfunktion um.
    //
    //
    private void schummelfunktion() {
        //sicherstellen dass nur beim Menschenzug gedrückt werden darf
        if (spieler == 0) {
            //alle Karten auf dem Spielfeld aufdecken
            for (int i = 0; i <= 41; i++) {
                if (karten[i].isNochImSpiel() == true) {
                    karten[i].vorderseiteZeigen();
                    System.out.println("Karte " + i + " ist noch im Spiel");
                    //karten[i + 1].vorderseiteZeigen();
                    //System.out.println("Karte " + (i + 1) + " ist noch im Spiel");                        i++;
                }
            }
            //den Timer erzeugen um die Karten nach 3 Sekunden umzudrehen.
            timer = new Timeline(new KeyFrame(Duration.millis(3000), new TimerSchummelnAus()));
            //und starten
            timer.play();
        }
    }
//***************************************Aufgabe3***************************************
}
 
3. Memorykarte

Java:
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());
    }
    
    //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 Karte 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;
    }
    
}
 

Oneixee5

Top Contributor
Beim Memory geht es um Paare, also würde ich eine Paar-ID mitgeben, vermutlich ist das mit deiner bildId gemeint. Die Karten-Position (bildPos) würde ich nicht in der Karte ablegen. Es kann eine Liste von Karten/Array verwendet werden, der Index in der Kartenliste entspricht schon der Kartenposition. Es besteht die Möglichkeit, dass bildPos und index auseinander laufen - so eine doppelte Datenhaltung sollte man vermeiden.
Java:
// 1. Eine leere Liste für Kartenobjekte erstellen
List<Karte> kartenDeck = new ArrayList<>();
// 2. Die Liste mit 21 Paaren befüllen
...
// 3. Das Deck mischen
Collections.shuffle(kartenDeck);
Die Anordnung der Karten würde ich einfach dem Layoutmanager überlassen, oder einen passenden schreiben. Quasi ein Spielfeld, welches die Karten selbst anordnet. Die Verwaltung der Karten erfolgt dann einfach immer über die Liste (Index).

Verwaltung: Jede Karte kann ihren eigenen Zustand speichern, z. B. ob sie gerade aufgedeckt (isFlipped) oder bereits als Teil eines Paares gefunden wurde (isMatched).

Identifikation: Über eine paarId (Integer) können Paare verglichen werden, ohne sich auf Bildnamen oder andere anfällige Strings verlassen zu müssen. Ein Vergleich von card1.getPaarId() == card2.getPaarId() ist eindeutig und sicher.

Flexibilität: Objekte können leicht um weitere Eigenschaften erweitert werden, z. B. den Pfad zum Bild (imagePath), einen Soundeffekt beim Finden des Paares oder einen eindeutigen Identifier.

Lesbarkeit: Der Code wird selbsterklärend. Eine Zeile wie if (angeklickteKarte.istGefunden()) ist viel verständlicher als eine komplexe Abfrage auf mehrdimensionale Arrays.

Ein Spielfeld für die Karten könnte vereinfacht so aufgebaut sein:
Java:
public class Spielfeld extends TilePane {

    // besser Konstanten aus Karte-Klasse
    private static final int KARTEN_BREITE = 80;
    private static final int KARTEN_HOEHE  = 80;

    /**
     * Konstruktor: nimmt eine Liste von Karten entgegen und zeigt sie an.
     */
    public Spielfeld(List<Karte> karten) {
        // Layout-Einstellungen
        setHgap(10);
        setVgap(10);
        setPrefTileWidth(KARTEN_BREITE);
        setPrefTileHeight(KARTEN_HOEHE);
        setStyle("-fx-padding: 20; -fx-background-color: #2E8B57;");

        // Anzahl Spalten automatisch berechnen (z. B. max 7 Spalten)
        int spalten = 7;
        setPrefColumns(spalten);

        // Karten hinzufügen, nur Test -> als Methode schreiben
        for (int i = 0; i < karten.size(); i++) {
            Karte karte = karten.get(i);
            // nur Beispiel, auch Button ist möglich
            ImageView imageView = new ImageView(new Image(karte.getBildUrl()));
            imageView.setFitWidth(KARTEN_BREITE);
            imageView.setFitHeight(KARTEN_HOEHE);
            getChildren().add(imageView);
        }
    }
}
 

Ähnliche Java Themen


Oben