# Hilfe bei Memory-Spiel



## noob1990 (13. Mai 2012)

Hey

ich muss ein Memory-Spiel ersellen mit 8*8 Karten.
Ich sitze gerade fest beim Misch-Algorithmus, so sieht der momentan aus:

```
public static void shuffle(Card[] array)
	{
		for(int i= 0;i<10000;i++)
		{
			int z1=(int) (Math.random()*64);
			int z2=(int) (Math.random()*64);
			array[z1]=array[z2];
			array[z2]=array[z1];
		}
	}
```

ich erhalte jedoch immer eine NullPointerException, wenn ich versuch mir die karten anzeigen zu lassen.

Hat irgendjemand ne Idee warum?


----------



## Marco13 (13. Mai 2012)

Weil du eine Variable derefernzierst, die "null" ist.

Poste den Stacktrace, den entsprechenden Code, usw...


----------



## Noob1990 (13. Mai 2012)

```
public static void main(String[] args) 
	{	
		
		MyFrame frame = new MyFrame(600,600,"Fenster");
		Card memoryCards1[] = new Card[32];
		Card memoryCards2[] = memoryCards1.clone();
		int photoNumber= 0;
	
			for(int j=0; j<32; j++)
			{	
				int rand = (int)(Math.random()*6); 
				Color zufallsFarbe = Farbe();
				double relativeGroeße = relativeGroeße();
				
				//verhindert das bilder doppelt geladen werden
				if (photoNumber>=6)
				{
					rand=(int)(Math.random()*5);
				}
					
					
					switch (rand)
					{
						case 0:		memoryCards1[j] = new Square();
									memoryCards2[j] = new Square();
									break;
						
						case 1 :	memoryCards1[j] = new PacMan();			
									memoryCards2[j] = new PacMan();
									break;
						
						case 2:		memoryCards1[j] = new Triangle();
									memoryCards2[j] = new Triangle();
									break;
									
						case 3:		memoryCards1[j] = new Circle();
									memoryCards2[j] = new Circle();
									break;
									
						case 4: 	memoryCards1[j] = new MySpecialShape();
									memoryCards2[j] = new MySpecialShape();
									break;
						
						case 5:		memoryCards1[j]= new Photo();
									memoryCards1[j].setPhotoNumber(photoNumber);
									memoryCards2[j]= new Photo();
									memoryCards2[j].setPhotoNumber(photoNumber);
									break;
									
						default:    memoryCards1[j] = new Circle();
									memoryCards2[j] = new Circle();
									break;
					}
					
				
					
					
					memoryCards1[j].setColor(zufallsFarbe);
					memoryCards1[j].setRelativeSize(relativeGroeße);
					memoryCards2[j].setColor(zufallsFarbe);					
					memoryCards2[j].setRelativeSize(relativeGroeße);
					
							
					shuffle(memoryCards1);
					shuffle(memoryCards2);
					
					
					//geht zum naechsten foto des verzeichnises ueber
					if(rand==5)
					{
						photoNumber++;
					}	
				
				}
		
			for(int j=0; j<32; j++)
			{	
				frame.add(memoryCards2[j]);
			}
			for(int j=0; j<64;j++)	
			{
				
				frame.add(memoryCards1[j]);
			}
				
			System.out.println(Arrays.asList(memoryCards1)); 
			System.out.println(Arrays.asList(memoryCards2)); 
				 
			}
```


----------



## Tesla (13. Mai 2012)

Hallo,

Poste mal die Ausnahme-Fehlermeldung, vielleicht sieht man die entsrpechende Zeile.

Was willst du damit machen [c]frame.add(memoryCards2[j]);[/c] ?


----------



## nobb1990 (13. Mai 2012)

Exception in thread "main" java.lang.NullPointerException
	at java.awt.Container.addImpl(Unknown Source)
	at java.awt.Container.add(Unknown Source)
	at javax.swing.JFrame.addImpl(Unknown Source)
	at java.awt.Container.add(Unknown Source)
	at Main.main(Main.java:99) ->das ist die zeile mit frame.add(..)

damit sollen halt die karten des geklonten arrays angezeigt werden


----------



## Volvagia (13. Mai 2012)

Ich finde den Fehler zwar nicht, aber das würde mich sowieso viel mehr interessieren:

[java=80]
for(int j=0; j<64;j++)
[/code]

Treibts die for nicht ein wenig zu weit?
Und warum clonst du 1) ein leeres Array und 2) castest du den clone nicht? Die Methode gibt doch Object zurück, oder? :autsch:


----------



## noob1990 (13. Mai 2012)

ja ich hab den code nochmal überarbeitet


```
import java.awt.Color;
import java.util.Arrays;

import java.util.Random;


public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) 
	{	
		int myCardArrayLength=64;
		MyFrame frame = new MyFrame(600,600,"Fenster");
		Card[] myCards = new Card[myCardArrayLength+1];
		Card temp;
		
		int photoNumber= 0;
	
			for(int j=1; j<(myCardArrayLength/2)+1; j++)
			{	
				int rand = (int)(Math.random()*6); 
				Color zufallsFarbe = Farbe();
				double relativeGroeße = relativeGroeße();
				
				//verhindert das bilder doppelt geladen werden
				if (photoNumber>=6)
				{
					rand=(int)(Math.random()*5);
				}
					
				for(int i=0;i<2;i++)	
				{
					switch (rand)
				
					{
						case 0:		myCards[j*i] = new Square();
									break;
						
						case 1 :	myCards[j*i] = new PacMan();		
									break;
						
						case 2:		myCards[j*i] = new Triangle();
									break;
									
						case 3:		myCards[j*i] = new Circle();
									break;
									
						case 4: 	myCards[j*i] = new MySpecialShape();
									break;
						
						case 5:		myCards[j*i]= new Photo();
									myCards[j*i].setPhotoNumber(photoNumber);
									break;
									
						default:    myCards[j*i] = new Circle();
									break;
					}
					
					frame.add(myCards[j*i]);	
					myCards[j*i].setRelativeSize(relativeGroeße);
					myCards[j*i].setColor(zufallsFarbe);
					
			
				}
					//geht zum naechsten foto des verzeichnises ueber
					if(rand==5)
					{
					photoNumber++;
					}	
			}
			for(int l= 0;l<myCardArrayLength*2;l++)
			{		
		    	int z1;
				int z2;
				do
				{
					z1=Randomize(myCardArrayLength);
					z2=Randomize(myCardArrayLength);
					
				}while(z1!=z2);
					temp=myCards[z1];
					myCards[z1]=myCards[z2];
					myCards[z2]=temp;
			}
				for(int k=1; k<myCardArrayLength+1;k++)	
				{
					frame.add(myCards[k]);
				}
						
				
			}
```


----------



## noob1990 (13. Mai 2012)

es ist schon gemischt aber man erkennt ein muster, d.h. die karten 1-32 sind gemischt und die karten karten 33-64 sind gemischt jedoch sind sie gleich gemischt

soll heißen karten 0-31=karten 32-64


----------



## Volvagia (13. Mai 2012)

Also der Bug ist jetzt weg?
Warum benutzt du zum Mischen nicht einfach Collections.shuffle?


----------



## noob1990 (13. Mai 2012)

Volvagia hat gesagt.:


> Also der Bug ist jetzt weg?
> Warum benutzt du zum Mischen nicht einfach Collections.shuffle?



die Null-Pointer_Exception taucht immernoch auf, aber er zeigt die Karten an.
Sorry das kenne ich nicht; könntest du mir das mal als code hinschreiben.


----------



## Volvagia (13. Mai 2012)

Zeig am besten mal den ganzen Code, dann kann man auch per Debugger durchfahren.


```
String[] array = {
	"A", "B", "C"
};
Collections.shuffle(Arrays.asList(array));
```

Arrays.asList gibt eine ArrayList zurück. Aber vorsicht, ArrayList != ArrayList. Eine java.util.Array.ArrayList ist bloß eine Adapterklasse und eignet sich deshalb ausschließlich zum Auslesen des Arrays während eine java.util.ArrayList auch hinzufügen und Vergrößerung des internen Arrays erlaubt.


----------



## noob1990 (13. Mai 2012)

```
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.ImageObserver;
import java.io.File;

import javax.swing.BorderFactory;
import javax.swing.JPanel;


public abstract class Card extends JPanel implements ImageObserver, MouseListener
{
	public Card()
	{
		super();
		this.setBorder(BorderFactory.createLineBorder(Color.red));
		this.addMouseListener(this);
	} 
	
	int i, pacmanAngle1=45, pacmanAngle2=280 ;
	
	Color squareColor;
	double relativeSize;
	boolean disguised=false;
	Color black = new Color(0,0,0);
	Color white = new Color(255, 255, 255);
	
	File fhLogo = new File("bilder");
	Image myPhoto=Toolkit.getDefaultToolkit().getImage("bilder");
	public void setColor(Color color)
	{
		squareColor = color;
	}
	public void setPhotoNumber(int photoNumber)
	{
		i=photoNumber;
		
	}
	
	public void setRelativeSize(double size)
	{	if(size>=100)
		{
			relativeSize = 100;
		}
		relativeSize =  size;
	
	}
	public void disguise()
	{
		disguised =! disguised;
		repaint();
	}
	public void paint(Graphics g)
	{	
		super.paint(g);
		
		Dimension mySize = this.getSize();
		int length=Math.min(mySize.height,mySize.width);
		int size = (int)(length*relativeSize/100);
		
		
		
		if(disguised)
		{	
			
			g.drawImage(myPhoto, 0, 0, mySize.width, mySize.height,null);
			pacmanAngle1= pacmanAngle1+90;
		
		}
		else
		{	
			g.setColor(squareColor);
			specialPaint(g, size,mySize);
			
		}
	}
	
	public void  specialPaint(Graphics g, int size, Dimension mySize)
	{
		
	}

	@Override
	public void mouseClicked(MouseEvent me) 
	{
		if (me.getButton() == 1)
		{
			disguise();
			
		}
		
	}



	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}



	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}



	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}



	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
}
import java.awt.Dimension;
import java.awt.Graphics;


public class Circle extends Card
{
	
	public Circle()
	{
		super();
	
	}
	
	
	
	public void specialPaint(Graphics g, int size,  Dimension mySize)
	{
		
		g.fillOval(mySize.width/2-size/2, mySize.height/2-size/2, size, size);
	
	}



}
import java.awt.Color;
import java.util.Arrays;

import java.util.Random;


public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) 
	{	
		int myCardArrayLength=64;
		MyFrame frame = new MyFrame(600,600,"Fenster");
		Card[] myCards = new Card[myCardArrayLength+1];
		Card temp;
		
		int photoNumber= 0;
	
			for(int j=1; j<(myCardArrayLength/2)+1; j++)
			{	
				int rand = (int)(Math.random()*6); 
				Color zufallsFarbe = Farbe();
				double relativeGroeße = relativeGroeße();
				
				//verhindert das bilder doppelt geladen werden
				if (photoNumber>=6)
				{
					rand=(int)(Math.random()*5);
				}
					
				for(int i=0;i<2;i++)	
				{
					switch (rand)
				
					{
						case 0:		myCards[j*i] = new Square();
									break;
						
						case 1 :	myCards[j*i] = new PacMan();		
									break;
						
						case 2:		myCards[j*i] = new Triangle();
									break;
									
						case 3:		myCards[j*i] = new Circle();
									break;
									
						case 4: 	myCards[j*i] = new MySpecialShape();
									break;
						
						case 5:		myCards[j*i]= new Photo();
									myCards[j*i].setPhotoNumber(photoNumber);
									break;
									
						default:    myCards[j*i] = new Circle();
									break;
					}
					
					frame.add(myCards[j*i]);	
					myCards[j*i].setRelativeSize(relativeGroeße);
					myCards[j*i].setColor(zufallsFarbe);
					
			
				}
					//geht zum naechsten foto des verzeichnises ueber
					if(rand==5)
					{
					photoNumber++;
					}	
			}
			for(int l= 0;l<myCardArrayLength*2;l++)
			{		
		    	int z1;
				int z2;
				do
				{
					z1=Randomize(myCardArrayLength);
					z2=Randomize(myCardArrayLength);
					
				}while(z1!=z2);
					temp=myCards[z1];
					myCards[z1]=myCards[z2];
					myCards[z2]=temp;
			}
				for(int k=1; k<myCardArrayLength+1;k++)	
				{
					frame.add(myCards[k]);
				}
						
				
			}
		
			

				
		
			
		
	
	private static int Randomize(int range) 
	{
		double rawResult;
		rawResult = Math.random();
		return (int) (rawResult * range);
	}

	public static void shuffle1(Card[] array)
	{
		for(int i= 0;i<10000;i++)
		{
			int z1=(int) (Math.random()*64);
			int z2=(int) (Math.random()*64);
			array[z1]=array[z2];
			array[z2]=array[z1];
		}
	}
	
	public static void shuffle (Card[] array) 
	{ 
	   Random rng = new Random();   
	   int n = array.length;        
	   while (n > 0) 
	   { 
	      int k = rng.nextInt(n);  
	      n--;                      
	      Card temp = array[n];     
	      array[n] = array[k]; 
	      array[k] = temp; 
	   } 
	}


	public static Color Farbe()
	{
		Color zufallsFarbe = new Color((int)(255*Math.random()),(int)(255*Math.random()),(int)(255*Math.random()));
		return zufallsFarbe;
	}
	public static double relativeGroeße()
	{
		double relativeSize =30+Math.random()*60;
		return relativeSize;
	}
}
import java.awt.Dimension;
import java.awt.GridLayout;

import javax.swing.JFrame;


public class MyFrame extends JFrame
{			
	public MyFrame(int a, int b, String title )
	{	
		super();
	
		setSize(a,a);
		setTitle(title);
		
	
		setLocation(b,0);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setLayout(new GridLayout(8,8,a/64,a/64));
		setVisible(true);
		
	}

	
		
}
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;


public class MySpecialShape extends Card
{
	public MySpecialShape()
	{
		super();
	
	}
	
	
	
	public void specialPaint(Graphics g, int size, Dimension mySize)
	{
		int x [] = new int[4];
		int y [] = new int[4];
		
		x[0] = mySize.width/2 -size/2;
		x[1] = mySize.width/2 -size/3 ;
		x[2] = mySize.width/2 +size/3;
		x[3] = mySize.width/2 + size/2;
		
	
		y[0] = mySize.height/2 + size/2;
		y[1] = mySize.height/2-size/2;
		y[2] = mySize.height/2-size/2;
		y[3] = mySize.height/2 + size/2;
		g.fillPolygon(x,y,4);
	
	}


}


import java.awt.Dimension;
import java.awt.Graphics;


public class PacMan extends Card 
{
	public PacMan() 
	{
		super();
	}
	
	public void specialPaint(Graphics g, int size, Dimension mySize)
	{	
			
		g.fillArc(mySize.width/2-size/2, mySize.height/2-size/2, size, size, pacmanAngle1 ,pacmanAngle2);
	}
}
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.File;

public class Photo extends Card
{
	
	public Photo()
	{
		super();
	
	}
	
	
	public void specialPaint(Graphics g, int size, Dimension mySize)
	{
	
		
		File myPhotoDirectory = new File("bilder");
		File [] myPhotos = myPhotoDirectory.listFiles();
		Image picture = Toolkit.getDefaultToolkit().getImage(myPhotos[i].getPath());
		g.drawImage(picture, 0, 0, mySize.width, mySize.height,null);
		repaint();
	
	}
}

import java.awt.Dimension;
import java.awt.Graphics;


public class Square extends Card
{
	
	public Square()
	{
		super();
	
	}
	
	
	
	public void specialPaint(Graphics g, int size, Dimension mySize)
	{
			
		g.fillRect(mySize.width/2-size/2, mySize.height/2-size/2, size, size);
	
	}
}
import java.awt.Dimension;
import java.awt.Graphics;


public class Triangle extends Card
{
	
	public Triangle()
	{
		super();
	
	}
	
	
	
	public void specialPaint(Graphics g, int size, Dimension mySize)
	{
		
	
		
		int x [] = new int[3];
		int y [] = new int[3];
		
		x[0] = mySize.width/2 -size/2;
		x[1] = mySize.width/2 ;
		x[2] = mySize.width/2 + size/2;
		
		y[0] = mySize.height/2 + size/2;
		y[1] = mySize.height/2-size/2;
		y[2] = mySize.height/2 + size/2;
		
		g.fillPolygon(x,y,3);
	
	}
}
```


----------



## Volvagia (13. Mai 2012)

Jetzt ist es kein Wunder. Du befüllst ein Array zur Hälfte (for(int j=1; j<(myCardArrayLength/2)+1; j++)) und rennst es komplett durch. (for(int k=1; k<myCardArrayLength+1;k++)). Dabei ist mir auch wärend des Aufteils der Klassen aufgefallen, dass du in einer paint ein Bild asynchron lädst und nicht wartest, bis es fertig ist.


----------



## noob1990 (13. Mai 2012)

hast du einen lösungsvorschlag parat?


----------



## Volvagia (13. Mai 2012)

Ja: Mach es anderst. 
Eigendlich habe ich die Hälfte des Codes nicht verstanden. Warum z. B. erzeugst du nicht nur jeweils eine Card (oder andere Klasse, da der Name dann wahrscheinlich nicht mehr passen wird) und lässt dir davon einfach 2 JLabel generieren, die in zufälliger Reihenfolge hinzugefügt werden? Wäre doch viel simpler als das, was du jetzt hast. Und warum vererbst du so viel? Kann sein, dass ich mich da irre, aber grundsätzlich Favour Composition over Inheritance.


----------



## noob1990 (13. Mai 2012)

das war in der aufgabe so vorgegeben


----------



## Volvagia (13. Mai 2012)

Die geben dir eine Aufgabe mit GUI, ohne dass du weißt wie du eine NPE, die wahrscheinlich 2.-häufigste Exception bei Anfängern, erkennst und behebst? Ich werde immer froher, dass ich nicht mehr als die in Österreich nötigen 9 Jahre Schule hatte. (+ 1 Jahr in eine Schule wegen eines Mädchens) Das wirkt immer mehr, als würden die Lehrer nur so tun, als ob sie den Schülern was beibringen. Nicht die Schüler werden schlechter, die Lehrer werden es und ziehen die Schüler auf ihr Niveau herunter.

Wie lautet denn die genaue Aufgabenstellung?


----------



## noob1990 (13. Mai 2012)

Man soll halt diese Symbole(dreieck,pacman,quadrat...) sowie bilder erzeugen, die Anzahl der  verschiedenen Kartenarten ist zufällig.
Von jedem Objekt soll es einen "Klon" geben, d.h. es gibt 32 verschiedene Karten, von dem es jeweils eine Kopie gibt.
Die Karten sollen gemischt sein.


----------



## Volvagia (13. Mai 2012)

Ich hab mal versucht den Code zusammenzuräumen und ein wenig zu vereinfachen. Aber das geht nicht, so kannst du den unmöglich irgendwann abgeben.

1) Du vermischt deutsch und englisch. Nicht tragisch fürs Programm aber höllisch zu lesen.
2) Du vergibst Methodennamen wie "Farbe".
3) Du zeigst das JFrame an bevor es überhaupt befüllt ist.
4) Du verzichtest auf EDT-Invoke.
5) Du lädst Bilder in der paint.
6) Du benutzt Bilder, ohne sicherzustellen, dass sie vollständig geladen wurden.
7) Du schaffst mit dem Repaint (mehr oder weniger) eine Endlosschleife.
8) Du überschreibst paint statt paintComponent.
9) Du berechnest in Card reine Informationen für eine Subklasse.

Und ich denke, das ist nur eine Auswahl.


----------

