# Memory-Spiel alle verdeckte karten aufdecken.



## kaper28 (11. Dez 2008)

Hallo Leute, 

ich habe ein neues Projekt angefangen, ein Memory-Spiel ( nicht alleine natürlich , in der Schule ). Bis jetzt ist alles ok, nur ich möchte eine Schmumel-Funktion einbauen .

Ich baue eine Button ein der "Alles Aufdecken" heißt und wenn ich darauf drücke sollen alle Kasrten für eine bestimte Zeit sich öfnen ?

Was kann ich machen ?



```
//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 2 Karten umgedreht worden?
		if (umgedrehteKarten == 2) {
			//dann prüfen wir, ob es ein Paar ist
			paarPruefen(kartenID);
			//den Timer starten
			timer.start();
		}
		//haben wir zusammen 21 Paare, dann ist das Spiel vorbei
		if (computerPunkte + menschPunkte == 1) {
			JOptionPane.showMessageDialog(this, "Das Spiel ist vorbei.");
		
			//  4 neue 	MessageDialog eingefügt...
			JOptionPane.showMessageDialog(this, "Der Mensch hat "
					+ (menschPunkte) + " punkte gemacht");
			JOptionPane.showMessageDialog(this, "Der Computer hat "
					+ (computerPunkte) + " punkte gemacht ");
			if (menschPunkte > computerPunkte)
				JOptionPane.showMessageDialog(this, " Der Mensch Hat Gewonnen");
			else
				JOptionPane.showMessageDialog(this,
						" Der Computer  Hat Gewonnen");

			System.exit(0);

		}
	}
```

so das ist Methode wo mann die Karten öfnet.


----------



## kaper28 (11. Dez 2008)

ich baue ein Button ein 

Erstelle eine Methode Schmummel soll sie heißen 

und verbinde sie mit dem Button ...

nur wie kann die Methode erstellen ?


----------



## Marco13 (11. Dez 2008)

Wenn du einfach für allen Karten die "karteOeffnen"-Methode aufrufst, kommt wehrscheinlich deine Spiellogik komplett durcheinander. Vielleicht reicht es, dort, wo die Karten gezeichnet werden, ein "schummel"-Flag auf "true" zu setzen?


----------



## kaper28 (11. Dez 2008)

Marco13 hat gesagt.:
			
		

> Wenn du einfach für allen Karten die "karteOeffnen"-Methode aufrufst, kommt wehrscheinlich deine Spiellogik komplett durcheinander. Vielleicht reicht es, dort, wo die Karten gezeichnet werden, ein "schummel"-Flag auf "true" zu setzen?



ja das ist eine gute idee, marco du meinst in der klasse wo die karten gezeichnet werden ? Also alles anzeigen auf true oder habe ich flasch verstanden ?


----------



## Ark (11. Dez 2008)

Irgendwo beim Zeichnen musst du dir ja die Frage stellen, ob die Karte nun verdeckt (die Rückseite) oder offen (die Vorderseite) gezeichnet werden soll. Diese Stelle musst du einfach anpassen, etwas der Form:


```
// Vorher:
if(dieseKarte.istOffen()) { //offen malen}
else { // geschlossen malen}

// Nachher:
if(dieseKarte.istOffen() || schummeln) { //offen malen}
else { // geschlossen malen}
```
Die boolesche Variable schummeln ist dann entsprechend eben true oder false, und danach wird dann eine Karte auf jeden Fall dann offen gezeichnet, wenn diese Variable gesetzt ist.

Ark


----------



## kaper28 (13. Dez 2008)

ich verstehe, nur ich muß so machen . Ich habe jetzt eine leere Methode kartenAufdecken(), einen Button der "Alles Aufdecken "heißt und mit dem listener verbundenist .


```
public void kartenAufdecken(){
		
	
		
		
		}
```

es muß doch eine möglichkeit geben , alle katen aufeinmal zu öffnen. Wie der Ark geschriben hat , ist die karte gescholssen dann öfnen, das muß ich in diese Methode codieren  denke ich .


----------



## kaper28 (13. Dez 2008)

```
if  (die karten sind umgedreht )

öffne sie 
else

mach nichts
```
so mußte es sein , was meint ihr ?


----------



## Ark (13. Dez 2008)

Ganz wichtig: Es gibt einen Unterschied zwischen

der Eigenschaft einer Karte, offen oder geschlossen zu sein,

und

der Frage, ob man eine Karte offen oder geschlossen zeichnen soll.

Das sind zwei völlig verschiedene Dinge. 

Ark


----------



## kaper28 (13. Dez 2008)

hmmmmm, wie meinst du das Ark ?


----------



## Ark (13. Dez 2008)

Ich meine es üblicherweise genau so, wie ich es geschrieben habe. 

Zeig doch einfach mal den Code, der das "Spielbrett" zeichnet.

BTW: Ich habe mir mal deinen Code für karteOeffnen(MemoryKarte) angesehen. Was bitte passiert denn, wenn jemand zweimal auf dieselbe Karte klickt?

Ark


----------



## kaper28 (13. Dez 2008)

```
//die Methode erstellt die Oberfläche und zeichnet die Karten
	private void initGUI() {
		//das Layout setzen
		setLayout(new FlowLayout(FlowLayout.LEFT));
		
		//ein Panel für das eigentliche Spielfeld
		JPanel feld = new JPanel();
		//das Panel bekommt ein Gridlayout mit 7 Zeilen
		feld.setLayout(new GridLayout(7,0));
		//die Karten erstellen und zeichnen
		kartenZeichnen(feld);

		add(feld);
		
		//für die Ausgaben
		JPanel ausgabe = new JPanel();
		anzeigeLabel= new JLabel();
		menschPunkteLabel = new JLabel();
		computerPunkteLabel = new JLabel();
		menschPunkteLabel.setText(Integer.toString(menschPunkte));
		computerPunkteLabel.setText(Integer.toString(computerPunkte));
		JButton schummelButton = new JButton("Alles Aufdecken");
		schummelButton.setActionCommand("aufdecken");
		// für den ActionListener
		// für den ActionListener
		MeinListener listener = new MeinListener();
		schummelButton.addActionListener(listener);
		
		//in zwei Spalten
		ausgabe.setLayout(new GridLayout(0,2));
		ausgabe.add(new JLabel("Mensch: "));
		ausgabe.add(menschPunkteLabel);
		ausgabe.add(new JLabel("Computer: "));
		ausgabe.add(computerPunkteLabel);
		ausgabe.add(anzeigeLabel);
		ausgabe.add(schummelButton);
		add(ausgabe);
	}
	
	//das eigentliche Spielfeld erstellen
	private void kartenZeichnen(JPanel 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 und dann ins Spielfeld gesetzt
		Collections.shuffle(Arrays.asList(karten));
		for (int i = 0; i <= 41; i++) {
			feld.add(karten[i]);
			//die Position der Karte setzen
			karten[i].setBildPos(i);
		
		
		}
	}
```

Das ist die Methode die du meinst


----------



## kaper28 (13. Dez 2008)

oder ich brauche eine Methode der mit die alle vorderseiten der karten anzeigt.


----------



## kaper28 (13. Dez 2008)

ich bin bischen weiter gekommen 


```
karten[1].vorderseiteZeigen();
```

wenn ich auf den Button alles Aufdecken drücke ,zeigt  es mir die vorderseite die karte mit der nummer 1 .Das funktionert .


----------



## Ark (14. Dez 2008)

Au weia, das sieht gar nicht gut ... zumindest würde ich es so auf keinen Fall programmieren. 

1. Trenne GUI von Logik!
2. Denke objektorientiert und nicht prozedural!
3. Vermeide Redundanzen, vereinfache Code!

Ein bisschen anders:

```
private void kartenZeichnen(JPanel feld) {
		// count wird nicht mehr gebraucht (Punkt 3)
		for (int i = 0; i < 42; i++) { // so schreibt man die Grenzen in for-Schleifen üblicherweise
			karten[i] = new MemoryKarte(bilder, i / 2, this); // diese Zeile hat hier gar nichts verloren (Punkt 1)
			// außerdem ist das Aussehen der Karten GUI-Code und folglich sollte eine Karte
			// kein Erscheinungsbild von sich selbst haben (Punkte 1 und 3)
		}
		// Der Rest ist Logik und hat in GUI-Code nichts zu suchen
		Collections.shuffle(Arrays.asList(karten));
		for (int i = 0; i < 42; i++) {
			feld.add(karten[i]);
			karten[i].setBildPos(i); // eine Karte weiß selbst am besten, wo sie hingehört, und das Malen
			// muss reiner GUI-Code sein (Punkte 2 und 3)
		}
	}
```
Der Code ist dennoch komplett falsch strukturiert. Aber das mit der Objektorientierung kommt mit der Zeit auch in deine Birne.  Ich selbst habe lange gebraucht, bis ich von meinem krampfhaften Festhalten an der Kontrolle über das Geschehen (prozedurale Programmierung) losgekommen bin. Inzwischen kann ich durch und durch objektorientiert denken, und das heißt, Objekte "machen zu lassen" anstatt "alles selbst machen". Ich erinnere mich gut an einen Werbespot von IBM. Darin heißt es:


> Er überwacht sich selbst. Managet sich selbst. Optimiert sich selbst. Schützt sich selbst. Repariert sich so gut wie selbst.


Und genau so musst du auch zu denken lernen. 

Ark


----------



## kaper28 (14. Dez 2008)

Lieber Ark, du hást vollkommen recht. Ich bin noch in der anfangsstufe , aber ich habe es mir fest vorgemonnen es zu lernen und das werde ich auch. Danke für deine tips ..


----------



## Ark (14. Dez 2008)

Was macht eine Memory-Karte aus? Sie hat beispielsweise etwas, das sie von anderen Karten unterscheidet bzw. mit ihrem Zwilling gemeinsam hat. Um das zu beschreiben, reicht eine natürliche Zahl aus: 0, 1, 2, 3 ... (In der Graphentheorie nennt man natürliche Zahlen auch Farbe, reelle Zahlen nennt man Gewichte.) Des weiteren ist eine Karte offen oder eben nicht. Dafür reicht ein boolescher Wert vollkommen. Die Farbe einer Karte kann man nach dem Erstellen nicht mehr ändern, aber man kann eine Karte umdrehen. Mit einer Methode könnte die Karte nun bei Bedarf ihrer Umwelt mitteilen, welche Farbe sie hat. Dabei wird sie z.B. -1 zurückgeben, wenn sie nicht offen ist, und nur dann ihre "wahre" Farbe, wenn sie offen ist. Das sind alles Dinge, die du auch von "echten" Karten kennst.

Bau doch mal eine Klasse nach dieser Beschreibung. 

Das Spielbrett und nur dieses(!) wiederum merkt sich, wo sich welche Karte befindet. Folglich gehört das Mischen bzw. Auslegen der Karten auch dorthin.

Die eigentliche Logik sollte man immer so einfach wie möglich beschreiben. Über die konkrete Darstellung auf dem Bildschirm etc. sollte man sich hier noch gar keine Gedanken machen.

Ark


----------



## kaper28 (14. Dez 2008)

Lieber Ark, 

Das stimmt volkommen , mann muß am anfang gut lernen später wird es schwierieger. Ich habe es geschaft mit einem Knopfdruck alles zu öfnen, nur ich will es auch schließen mit einem konopfdruck das klappt jetzt nicht .


```
public void kartenAufdecken(){
		
	
			int i =0;
		for(i=0; i+1 <=42;++i ){
			
			karten[i].vorderseiteZeigen();

			
			
		}
```

mit dieser Methode habe ich geschaft alles aufzudecken . Nur wie kann ich die karten wier schließen. ?


```
public void kartenZudecken(){
	

		int i =0;
	for(i=0; i+1 <=42;++i ){
		karten[i].rueckseiteZeigen(rootPaneCheckingEnabled);
		
	}
```

das ist die methode für die kArten zu schlißen aber klappt nicht...


----------



## kaper28 (14. Dez 2008)

```
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Collections;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;


public class MemoryFeld extends JFrame{

	private String anzeige = "Es Zieht der Mensch";
		private String anzeige1 = "Es Zieht der Computer";

		private ImageIcon bildVorne,bildHinten;
		
		class MeinListener implements ActionListener {
			@Override
//			die Methode ruft die Methode karteSchliessen() auf
			public void actionPerformed(ActionEvent e) {
			
			if(e.getActionCommand().equals("aufdecken"));
			
			kartenAufdecken();
			
			
		
			if(e.getActionCommand().equals("zudecken"));
			
			//kartenZudecken();
			
			}
		}

		
///eine innere Klasse für den Timer
	class TimerListener implements ActionListener {

		@Override
//		die Methode ruft die Methode karteSchliessen() auf
		public void actionPerformed(ActionEvent e) {
			karteSchliessen();
			
		}
	}

	//automatisch über Eclipse ergänzt
	private static final long serialVersionUID = -649630686152121284L;
	
	//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 JLabel menschPunkteLabel, computerPunkteLabel,anzeigeLabel;
	
	//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;
	
	//für den Timer
	private Timer timer;
	
	//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;
	
	//der Konstruktor
	//er erzeugt das Spielfeld mit den Karten und die Oberfläche
	public MemoryFeld(String titel) {
		super(titel);
		//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;
		
		//es gibt keine gemerkten Karten
		for (int aussen = 0; aussen < 2; aussen++)
			for (int innen = 0; innen < 21; innen++)
				gemerkteKarten[aussen][innen] = -1;

		//die Oberfläche erstellen
		initGUI();
		
		//die Spielstärke ist 10, also eher schwach
		spielstaerke = 10;
		//für den Timer
		//eine neue Instanz erstellen, der Timer soll alle 2 Sekunden ausgelöst werden
		timer = new Timer(2000, new TimerListener());
		//in unserem Spiel soll er aber nur einmal ausgeführt werden
		timer.setRepeats(false);
		
		//Größe setzen, keine Größenänderungen zulassen, Standard-Verhalten festlegen und anzeigen
		setSize(405,600);
		setResizable(false);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);
	}
	
	//die Methode erstellt die Oberfläche und zeichnet die Karten
	private void initGUI() {
		//das Layout setzen
		setLayout(new FlowLayout(FlowLayout.LEFT));
		
		//ein Panel für das eigentliche Spielfeld
		JPanel feld = new JPanel();
		//das Panel bekommt ein Gridlayout mit 7 Zeilen
		feld.setLayout(new GridLayout(7,0));
		//die Karten erstellen und zeichnen
		kartenZeichnen(feld);

		add(feld);
		
		//für die Ausgaben
		JPanel ausgabe = new JPanel();
		anzeigeLabel= new JLabel();
		menschPunkteLabel = new JLabel();
		computerPunkteLabel = new JLabel();
		menschPunkteLabel.setText(Integer.toString(menschPunkte));
		computerPunkteLabel.setText(Integer.toString(computerPunkte));
		
		JButton schummelButton = new JButton("Alles Aufdecken");
		schummelButton.setActionCommand("aufdecken");
		// für den ActionListener
		// für den ActionListener
		MeinListener listener = new MeinListener();
		schummelButton.addActionListener(listener);
		
		JButton schummelButton1 = new JButton("Alles zudecken");
		schummelButton1.setActionCommand("zudecken");
		// für den ActionListener
		// für den ActionListener
		MeinListener listener1 = new MeinListener();
		schummelButton1.addActionListener(listener1);
		
		
		
		//in zwei Spalten
		ausgabe.setLayout(new GridLayout(0,2));
		ausgabe.add(new JLabel("Mensch: "));
		ausgabe.add(menschPunkteLabel);
		ausgabe.add(new JLabel("Computer: "));
		ausgabe.add(computerPunkteLabel);
		ausgabe.add(anzeigeLabel);
		ausgabe.add(schummelButton);
		ausgabe.add(schummelButton1);
		add(ausgabe);
	}
	
	//das eigentliche Spielfeld erstellen
	private void kartenZeichnen(JPanel 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 und dann ins Spielfeld gesetzt
		Collections.shuffle(Arrays.asList(karten));
		for (int i = 0; i <= 41; i++) {
			feld.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;
		anzeigeLabel.setText((anzeige));
		//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 2 Karten umgedreht worden?
		if (umgedrehteKarten == 2) {
			//dann prüfen wir, ob es ein Paar ist
			paarPruefen(kartenID);
			//den Timer starten
			timer.start();
		}
		//haben wir zusammen 21 Paare, dann ist das Spiel vorbei
		if (computerPunkte + menschPunkte == 1) {
			JOptionPane.showMessageDialog(this,"Das Spiel ist vorbei.");
		//  4 neue 	MessageDialog eingefügt...
			JOptionPane.showMessageDialog(this, "Der Mensch hat"
					+ ( menschPunkte ) + " punkte gemacht");
			JOptionPane.showMessageDialog(this, "Der Computer hat"
					+ ( computerPunkte ) + " punkte gemacht ");
			if (menschPunkte > computerPunkte)
				JOptionPane.showMessageDialog(this, " Der Mensch Hat Gewonnen");
			else
				JOptionPane.showMessageDialog(this,
						" Der Computer  Hat Gewonnen");

			
			
			System.exit(0);
		}
	}
	
	//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;
	
		anzeigeLabel.setText(anzeige1);
	}
	
	//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;
	}
	
	
	
	public void kartenAufdecken(){
		
	
			int i =0;
		for(i=0; i+1 <=42;++i ){
			
			karten[i].vorderseiteZeigen();

			
			
		}
	}
	/*public void kartenZudecken(){
	

		int i =0;
	for(i=0; i+1 <=42;++i ){
		karten[i].rueckseiteZeigen(rootPaneCheckingEnabled);
		
	}*/
	
		
	
		}
```

hier der komplete code nochmal


----------



## Ark (14. Dez 2008)

Das ist nicht der komplette Code. Es fehlt noch mindestens der Quelltext der Klasse MemoryKarte (her damit!). Aber mal davon abgesehen sollte man 99% des bisherigen Codes wegwerfen. ^^

Ark


----------



## kaper28 (14. Dez 2008)

```
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.Timer;

import de.fernschulen.memoryspiel.MemoryFeld.TimerListener;

//die Klasse für eine Karte des Memory-Spiels
//Sie erbt von JButton
public class MemoryKarte extends JButton {
	
	//automatisch mit Eclipse erzeugt
	private static final long serialVersionUID = -7586403525312208557L;

	//die Instanzvariablen
	//eine eindeutige ID zur Identifizierung des Bildes
	private int bildID;
	//für die Vorder- und Rückseite
	private ImageIcon 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 ActionListener
	class KartenListener implements ActionListener {

		@Override
		public void actionPerformed(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 Größe, die Bilder und die Position
	public MemoryKarte(String vorne, int bildID, MemoryFeld spielfeld) {
		//die Größe auf 64 * 64 setzen
		setPreferredSize(new Dimension(64,64));
		//die Vorderseite, der Dateiname des Bildes wird an den Konstruktor übergeben
		bildVorne = new ImageIcon(vorne);
		//die Rückseite, sie wird fest gesetzt
		bildHinten = new ImageIcon("grafiken/back.jpg");
		setIcon(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;
		//den ActionListener verbinden
		addActionListener(new KartenListener());
	}
	
	//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
			setIcon(new ImageIcon("grafiken/aufgedeckt.jpg"));
			nochImSpiel = false;
		}
		else {
			//sonst nur die Rückseite zeigen
			setIcon(bildHinten);
			umgedreht = false;
		}
	}
	
	//die Methode zeigt die Vorderseite der Karte an
	public void vorderseiteZeigen() {
		setIcon(bildVorne);
		umgedreht = true;
	}

	//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;
	}

	

	
	
	}
```

Stimmt sorry hier ist es


----------



## Ark (15. Dez 2008)

kaper28 hat gesagt.:
			
		

> ```
> //die Instanzvariablen
> //eine eindeutige ID zur Identifizierung des Bildes
> private int bildID;
> ...


Redundanzen sind meist Hinweise auf Designfehler. Wenn du eine ID des Bildes hast, warum speicherst du dann zusätzlich noch die Bilder selbst? Das ergibt gar keinen Sinn und hat mal wieder mit Punkt 1 zu tun: Trenne GUI von Logik! Und warum hat jede Karte noch einmal eine eigene Rückseite? Damit könnte ja jede Karte von der Rückseite her anders aussehen, und das widerspricht der Idee, dass man durch die Rückseite eben nicht erkennt, welche Karte genau es ist. Widersprüche sind auch Hinweise auf Designfehler!



			
				kaper28 hat gesagt.:
			
		

> ```
> if ((nochImSpiel == false) || (spielfeld.zugErlaubt() == false))
> return;
> ```


Garantiert jeder nicht-konstante boolesche Audruck lässt sich komplett ohne boolesche Konstanten schreiben:

```
if (!nochImSpiel || !spielfeld.zugErlaubt())
				return;
```
Oder mit De Morgan:

```
if (!(nochImSpiel && spielfeld.zugErlaubt()))
				return;
```



			
				kaper28 hat gesagt.:
			
		

> ```
> //die Methode zeigt die Vorderseite der Karte an
> public void vorderseiteZeigen() {
> setIcon(bildVorne);
> ...


Ich kann mich nur wiederholen: Trenne GUI von Logik! Der Methodenname täuscht vor, dass die Karte nur ihre Vorderseite zeigen würde, aber in Wirklichkeit wird sie auch noch umgedreht! So wird das mit dem Schummelmodus nie was. 


			
				kaper28 hat gesagt.:
			
		

> ```
> //die Methode liefert die Position einer Karte
> public int getBildPos() {
> return bildPos;
> ...


Eine Karte muss nicht wissen, auf welcher Position sie liegt. Wenn du dir den Code der Klasse MemoryKarte anschaust, wirst du auch sehen, dass sich eine Karte nicht wirklich anders verhält, wenn sie eine andere Position bekommt, sondern dass es sich bei der Position nur um einen Speicherung derselben handelt. An einer anderen Stelle aber, nämlich hier:


			
				kaper28 hat gesagt.:
			
		

> ```
> //die Karten werden gemischt und dann ins Spielfeld gesetzt
> Collections.shuffle(Arrays.asList(karten));
> for (int i = 0; i <= 41; i++) {
> ...


sieht man, dass du dir die Position doppelt merkst (Redundanz!!). Zum einen merkt sich das Array die Position, zum anderen merkt sich die Karte selbst noch einmal, wo sie sich befindet. Damit ist es möglich, dass eine Karte intern woanders hinplatziert wird, als sich das Spielbrett denkt (das wäre ein Widerspruch! Außerdem ist, um das zu verhindert, der Code unnötig groß und damit kompliziert geworden).

Wenn ich jetzt alles durchgehen würde, würde ich vermutlich noch viel mehr Fehler finden. Die bisherige Anzahl an Fehlern sollte dir aber vor allem sagen, dass du besser noch mal von Grund auf neu mit dem Spiel anfangen solltest. 

Mach doch einfach mal eine Klasse für eine Karte so, wie ich sie dir weiter oben beschrieb. Das wäre immerhin ein Anfang. Und um das Aussehen solltest du dir da noch gar keine Gedanken machen. Die GUI kommt erst ganz zum Schluss!

Ark


----------



## Marco13 (15. Dez 2008)

Ob bei einem Schulprojekt die Zeit und Muße besteht, alles nochmal neu zu machen? :wink:


----------



## Ark (15. Dez 2008)

Das hängt davon ab, worauf Wert gelegt wird. Wenn es ums Programmieren geht, um sauberen Code und nachvollziehbare Logik, dann würde ich das, was bisher zu sehen war, nach meinem Ermessen mit einer 3 bewerten (eher schlechter). Dann würde es aber auch weit weniger eine Rolle spielen, ob das Spiel schön aussieht (GUI etc.).

Wenn dagegen es nur darum geht, dass die GUI hübsch aussieht, unter der Haube aber maximale Unappetitlichkeit herrscht, dann könnte das eventuell sogar noch mit einer 2 durchgehen. (Ich habe das Programm nie getestet.)

Den ersten Ansatz halte ich für sinnvoller als den zweiten.

Ark


----------



## kaper28 (16. Dez 2008)

Hallo Ark, natürlich hast du recht .Mann sagt ja wie es anfängt so geht es weiter. Aber Marco hat auch recht , die zeit ist sehr knapp . Ich habe mein Programm immer noch nicht fertig. 

Ich bekomme einfach die karten nicht umgedreht . Wenn ich auf die Alles Aufdecken Button drücke drehen sIch alle karten auf das ist ok , aber nach 5 sekunden müssen sich die karten die noch nicht AUF  sind wieder schließen wie vorher als ich sie aufgemacht habe. Das kriege ich nicht hin . Ich werde froh sein wenn ICH  alle karten auf einmal schließen kann , das kann ich auch nicht . Habe alles versucht aber Klappt leider  nicht.


----------



## Ark (16. Dez 2008)

Wie würdest du es denn mit "echten" Karten machen? Wenn du sie einfach alle umdrehst, hast du wohl nachher das Problem, dass du jetzt wissen müsstest, welche vorher umgedreht waren und welche nicht. Folglich muss sich vor dem Schummeln irgendjemand oder -etwas merken, welche Karten denn offen sind, um im Nachhinein die anderen wieder umzudrehen.

Das würde wohl freilich funktionieren, aber dass das etwas umständlich wird, liegt dann nur daran, dass du GUI nicht von Logik trennst. Würdest du es nämlich tun, dann könntest du einfach alle Karten als offen darstellen, auch obwohl sie noch geschlossen sind. 

Ark


----------



## Marco13 (17. Dez 2008)

Nicht schön, aber GROB in die Richtung gehend, die man mit einer sauberen Trennung von Model und View hinbekommen würde:

Im Moment verwendest du die Methode

```
//die Methode zeigt die Vorderseite der Karte an
   public void vorderseiteZeigen() {
      setIcon(bildVorne);
      umgedreht = true;
   }
```
um die Vorderseite zu zeigen - UND um die Karte umzudrehen.

Wenn du eine Methode machen würdest

```
public void vorderseiteZeigenAberNichtUmdrehen() {
      setIcon(bildVorne);
   }
```
dann könntest du die für den Schummel-Modus verwenden. Entsprechend bräuchtest du dann eine Methode wie

```
public void zeigeDieKarteWiederSoAnWieSieSeinMuss() {
      if (umgedreht)
      {
          setIcon(bildVorne);
      }
      else
      {
          setIcon(bildHinten);
      }
   }
```
um dem Schummel-Modus zu beenden.

Nochmal: Das ist von der Struktur her nicht schön, ziemlich verwirrend und unübersichtlich, aber vielleicht die einfachste und schnellste Lösung für die Abgabe. NACH der Abgabe kannst du das ganze ja nochmal richtig schreiben... wenn du willst :wink:


----------



## kaper28 (19. Dez 2008)

Hallo Marko , tut mir leid für die verspätete antwort.Mein pc spinnt wieder ...naja ist ja egal ich werde mal dein weg vercuhen ich glaube das wird klappen....


----------

