# Frage des richtigen Werkzeugs für ein Schachspiel?



## zerki (15. Mrz 2008)

hi,

ich frage mich grade, was der eleganteste weg ist, ein schachspiel zu realisieren, oder viel eher woran ich erkennen kann, was grade auf der GUI passiert ist.

das schachfeld wollte ich auf einem JPanel zeichnen, das krieg ich noch hin, nun hab ich aber das Problem, wie kriege ich später maus-bewegungen mit spielfiguren auf der gui, richtig erkannt. muss ich dann pixel zählen und so herausrechnen, über welchem feld die spielfigur fallen gelassen worden ist?

woran kann man das fest machen, irgendwie fehlt mir da das wissen zum richtigen werkzeug, wie man das am geschicktesten macht.

mein derzeitiger gedanke war eben die spielfelder auf dem schachbrett über die pixelkoordinate zu berechnen und daraus dann zu schließen, über welchem feld der cursor fallen gelassen wurde.

oder wie kann man das sonst sinnvoll machen?


----------



## 0x7F800000 (16. Mrz 2008)

du krigst die maus koords vom MouseMotionListener, du weisst wie hoch wie breit das feld ist, was willst du denn noch? die äußerst spektakuläre und super geheimnisvolle "dreisatzformel" oder was?  :wink: 

hab da zum spaß ein kleines demo zusammengebastelt, bin selbst überrascht dass der mist gleich beim ersten mal läuft 

```
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.image.*;
import java.lang.Thread;

public class ChessGUI extends JPanel implements MouseListener, MouseMotionListener{

private static interface Figure{
	public void paint(Graphics g, Rectangle rect);
}

private static final Figure[] figures={
		new Figure(){
			public void paint(Graphics g, Rectangle rect){
				g.setColor(Color.RED);
				g.fillRect(rect.x+rect.width/3,
							rect.y+rect.height/3,
							rect.width/3, 
							rect.height/3);
			}
		},
		new Figure(){
			public void paint(Graphics g, Rectangle rect){
				g.setColor(Color.BLUE);
				g.fillOval(rect.x+rect.width/3,
							rect.y+rect.height/3,
							rect.width/3, 
							rect.height/3);
			}
		}
};

//member vars
private Figure[][] fields;
private int width,height;
private int mouseX, mouseY;
private boolean isDragging;
private Figure draggedFigure;
private int originalPositionX,originalPositionY;
private BufferedImage backBuffer;

public ChessGUI(int _width, int _height){
	
	super();
	width=_width; height=_height;
	setSize(width,height);
	
	//create empty field
	fields=new Figure[8][];
	for(int x=0; x<fields.length; x++){
		fields[x]=new Figure[8];
		for(int y=0; y<fields[x].length; y++){
			fields[x][y]=null;
		}
	}
	
	//add some figures
	fields[0][0]=fields[4][5]=fields[2][1]=figures[0];
	fields[1][0]=fields[7][5]=fields[2][6]=figures[1];
	
	//add listeners
	addMouseListener(this);
	addMouseMotionListener(this);
	
	//nothing dragging
	mouseX=mouseY=originalPositionX=originalPositionY=0;
	isDragging=false;
	draggedFigure=null;
	
	//backBuffer
	backBuffer=
	new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
}

private int toFieldCoords(int xOrY, int widthOrHeight){ 
   return xOrY*8/widthOrHeight; 
}


public void mousePressed(MouseEvent e) {
	
	originalPositionX=toFieldCoords(mouseX,getWidth());
	originalPositionY=toFieldCoords(mouseY,getHeight());
	
	if(fields[originalPositionX][originalPositionY]!=null){
		isDragging=true;
		draggedFigure=fields[originalPositionX][originalPositionY];
		fields[originalPositionX][originalPositionY]=null;
	}
}

public void mouseReleased(MouseEvent e) {
	if(isDragging){
		isDragging=false;
		int fieldX=toFieldCoords(mouseX,getWidth());
		int fieldY=toFieldCoords(mouseY,getHeight());
		if(fields[fieldX][fieldY]==null){
			fields[fieldX][fieldY]=draggedFigure;
		}else{
			fields[originalPositionX][originalPositionY]=draggedFigure;
		}
		repaint();
	}
}

public void mouseDragged(MouseEvent e) {
	mouseX=e.getX(); mouseY=e.getY();
	repaint();
}

public void mouseMoved(MouseEvent e) {
	mouseX=e.getX(); mouseY=e.getY();
}

//stuff we dont need

public void mouseClicked(MouseEvent arg0) {}
public void mouseEntered(MouseEvent arg0) {}
public void mouseExited(MouseEvent arg0) {}

//paint
public void paint(Graphics componentGraphics){
	
	int cellWidth=width/8;
	int cellHeight=height/8;
	Graphics g=backBuffer.getGraphics();
	
	for(int x=0; x<8; x++){
	for(int y=0; y<8; y++){
		//background
		g.setColor(((x+y)%2==0)?(Color.DARK_GRAY):(new Color(200,150,100)));
		g.fillRect(x*cellWidth,
					y*cellHeight, 
					cellWidth, 
					cellHeight);
		//drawing all the figures in the fields
		if(fields[x][y]!=null){
			fields[x][y].paint(g,new Rectangle(x*cellWidth,
					y*cellHeight, 
					cellWidth, 
					cellHeight));
		}
	}
	}
	
	//drawing the dragged figure
	if(isDragging){
		draggedFigure.paint(g, new Rectangle(mouseX-cellWidth/2,
									mouseY-cellHeight/2, 
									cellWidth, 
									cellHeight));
	}
	
	//drawing the backBuffer
	componentGraphics.drawImage(backBuffer,0,0,getWidth(),getHeight(),this);
}

//main
public static void main(String[] args){
	JFrame f=new JFrame("Schach-GUI Prototyp");
	f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	f.setSize(510,530);
	f.setResizable(false);
	
	ChessGUI chessGui=new ChessGUI(500,500);
	f.getContentPane().add(chessGui);
	f.setVisible(true);
}
}
```

einfach kompilieren, ausführen. Insgesamt ist das alles wohl ein wenig unübersichtlich geworden, wenn es nach wie vor unklarheiten gibt, und die API nicht weiterhilft: weiterfragen...  :toll:
Schach ist eine gute sache  :bae:

[edit] hoppla, da war noch irgendein unsinniger überbleibsel von irgendeinem thread drinne, sry das war müll... habs jetzt rausgenommen, funktionieren tuts nach wie vor...


----------



## Quaxli (16. Mrz 2008)

Warum umständlich wenn's auch einfach geht?

Für ein Schachbrett nimmt man ein 8 x 8 Array von Rectangle bzw. einer Klasse, die von Rectanlge erbt (super-Aufruf im Konstrukor nicht vergessen). Damit hat man schon mal  eine Basisklasse, die Ihre Position und Höhe und Breite selbst speichert.  Außerdem erbt man dann gleich die Methode contains (int x, int y). Wenn man also von einem Mausklick den Punkt bekommt, loopt man einmal über das Array und prüft gegen diese Methode.

Zusätzlich bastelt man noch eine eigene Methode in diese Klasse, die etwa so aussieht:


```
public void drawField(Graphics g){

       if(black){   //black wäre in diesem Fall ein boolean, den man im Konstruktor setzt
         g.setColor(Color.black);
         g.fillRect(x,y,width,height);  //alles von Rectangle geerbte Klassen.
      }else{
         g.setColor(Color.white);
         g.fillRect(x,y,width,height);  //alles von Rectangle geerbte Klassen.
      }


    }
```

In der paintComponent-Methode bastelt man sich dann nur noch eine Schleife, die über alle Felder nudelt und ruft die oben skizzierte drawField-Methode auf um das komplette Schachbrett gezeichnet zu bekommen.


----------



## 0x7F800000 (16. Mrz 2008)

Quaxli hat gesagt.:
			
		

> Außerdem erbt man dann gleich die Methode contains (int x, int y). Wenn man also von einem Mausklick den Punkt bekommt, loopt man einmal über das Array und prüft gegen diese Methode.



das ist jetzt mal echt lol  :lol: 
man hat es hier mit dem allerprimitivsten rechteckigen gitter zu tun, warum sollte man da irgendwelche schleifen über ein zweidimensionales array einbauen, wenn man das kästchen explizit angeben kann? überleg doch mal:
bei der schleife musst du im worst case:

-64 mal den zähler inkrementieren
-64 mal die ganzen Rectangle-objekte aus dem array hin und herschieben
-64*4 mal irgendwelche if() abfragen mit größer/kleiner zeichen auswerten

da würde ich fast meinen, dass meine variante bereits auf einem kleinen 8x8 Feld selbst trotz einer division schneller ist:

```
private int toFieldCoords(int xOrY, int widthOrHeight){
	return xOrY*8/widthOrHeight;
}
```
(gut, diese methode muss auch 2mal ausgeführt werden, wegen x und y)
vor allem ist das immer in konstanter zeit ausführbar, nicht mit O(n) im worstcase


----------



## Marco13 (16. Mrz 2008)

Quaxli hat gesagt.:
			
		

> Warum umständlich wenn's auch einfach geht?


Das bezieht sich wohl auf deinen darauffolgenden Beitrag!? :wink: In einem regelmäßigen Gitter ist es wirklich einfacher, DIREKT aus den Mauskoorinaten das Feld auszurechnen...

```
int feldX = event.getX() / feldbreite;
int feldY = event.getY() / feldHöhe;
```


----------



## Janus (16. Mrz 2008)

bei nur 64 feldern könnt man auch einfach jedes feld als einen container mit entsprechenden listener implementieren und die dinger in ein grid layout kloppen. spart koordinatenberechnungen vollständig aus und sollte von der performance her noch recht anständig bleiben.

mal nen beispiel zusammengetrümmert: http://nopaste.info/9ea56a5035.html


----------



## 0x7F800000 (16. Mrz 2008)

omfg, anscheinend ist hier der wettkampf um die ressource-gefräßigste lösung des trivialen problems ausgebrochen :autsch: 

passt mal alle auf :!:  bald kommen hier leute an, die ein dreidimensionales modell des schachbrettes aus mikroskopisch kleinen voxeln zusammenbasteln, die dann alle in einem monströsen octree abgespeichern, das dazu unbeding krumme zylinderkoordinaten haben muss, sodass das bild dann mit einem extra dafür geschriebenen pixelschader geradegebogen werden kann, und die mausklicks werden dann zentral über einen server in california mithilfe von neuronalen netzwerken und hunderten datenbanken verteilt auf tausende computer irgendwo im world wide web verarbeitet....  :lol: 

ich schmeiß mich weg^^


----------



## Jango (16. Mrz 2008)

Andrey hat gesagt.:
			
		

> ...ich schmeiß mich weg^^


Gute Idee...


----------



## 0x7F800000 (16. Mrz 2008)

```
__________
|    |    |                          <------Fenster
|    |    |
|____|____|
|    |    |  _________
|    |    |           \
|____|____|             \                    
                         |
                         |
                         |
                         |
                         |
                         |
                         V


                         V
                        _|_                  <----Andrey
                         O






______________________________________
```
*sichAusDemFensterSchmeißUndSichDenSchädelZermatsch*


----------



## Janus (16. Mrz 2008)

Andrey hat gesagt.:
			
		

> omfg, anscheinend ist hier der wettkampf um die ressource-gefräßigste lösung des trivialen problems ausgebrochen :autsch:



die frage war, welches das beste werkzeug sei. sich den krempel selbst zu berechnen ist kein werkzeug. für das problem hier ist es gar nicht nötig, sich auf pixelebene zu begeben. warum also nicht wegrationalisieren?


----------



## 0x7F800000 (16. Mrz 2008)

@Janus:
in deinem beispiel werden die Feldkoordinaten ausgegeben, alles ist super in dieser hinsicht, aber wohin willst du das eigentliche dragging reinpacken, dass die figur mit der maus verschoben werden kann? 

1)Imho wäre es ein wenig ungünstig, dieses dragging in den listener für das einzelne kästchen reinzupacken (mir fällt momentan irgendwie nicht ein, wohin ich die figur dann zeichnen müsste: mit dem Graphics-Objekt des einzelnen kästchens würde es ja nicht gehen, weil man da nicht außerhalb des kästchens zeichnen kann=> eine figur befindet sich ja fast immer über 4 kästchen)

2)wieder in globale Spielfeldfeld-koordinaten umrechnen? das wäre dasselbe wie meine umrechnung in kästchen-koordinaten, nicht schwieriger nicht einfacher, also hätte man da nichts gewonnen...

3) einen extra mouselistener ans gesamte spielfeld hängen? Dann hättest du den Listener sowieso schon mal da, dann wären ja alle diese kleinen kästchen-listener überflüssig... 

würdest du vielleicht näher erläutern wie man das dragging in deinem beispiel umsetzen soll?

Bzw. wenn man will, dass die figur nur diskrete positionen annimmt (immer zentriert im kästchen) dann wären diese ganzen pixelberechnungen in der tat recht überflüssig... ich wollte es eben auf pixel genau verschieben können...  :roll:


----------



## Janus (16. Mrz 2008)

für d&d würd ich wahrscheinlich noch nen mousemotionlistener an die felder hängen. drag start events setzen das start feld, mouse release events das zielfeld. das sind 5 zeilen code oder so.


----------



## 0x7F800000 (16. Mrz 2008)

sry, ich hab mich wohl wieder nicht kurz fassen können, vielleicht ist in dem ganzen gelaber meine eigentliche frage untergegangen^^ 

was ich mich bei deinem code fragte: worauf willst du die gedraggte figur zeichnen? auf einzelnen feldern geht es ja nicht, das graphics-objekt eines einzelnen feldes kann ja nicht auf den umliegenden feldern die ganze figur zeichnen.


----------



## Marco13 (16. Mrz 2008)

Ja. Aber bis es funktioniert, sind es 50 Zeilen Code, eklige Hacks, und was rauskommt, wäre voraussichtlich ziemlicher Murks. "Keep it short & simple". Und das ist: Ein panel, wo man das Brett reinmalt, und mit position/feldgröße das betroffene Feld ausrechnet. Ist mit 2 Zeilen erledigt  :bae:


----------



## Janus (17. Mrz 2008)

ich hab keine ahnung, wie ihr auf die idee kommt, dass da irgendwelche hacks nötig wären. die verwendung von layout elementen statt graphics objekten ist grundsätzlich flexibler und einfacher erweiterbar. solang es nur darum geht, ein schachbrettmuster und ein paar figuren zu malen, ist das ganze auf pixelbasis vielleicht noch vertretbar. aber sobald komplexere methoden hinzugefügt werden müssen, wird man die draw events sehr wahrscheinlich gern in eigene klassen kapseln wollen. und dann fangen die ekligen hacks beim pixelbasierten ansatz an.


----------



## 0x7F800000 (17. Mrz 2008)

> aber sobald komplexere methoden hinzugefügt werden müssen, wird man die draw events sehr wahrscheinlich gern in eigene klassen kapseln wollen. und dann fangen die ekligen hacks beim pixelbasierten ansatz an


okay, damit bin ich voll einverstanden  :toll: darauf kann man sich einigen^^ ich bin halt davon ausgegangen, dass der OP nicht vorhatte, schach irgendwie zu erweitern (tut ja schon seit paar hundert jahren niemand mehr) insbesondere weil es dem OP anscheinend eh schon längst egal ist (der lässt sich hier nich allzu oft blicken). Bei allen anderen Sachen würde ich mir ebenfalls die option offen lassen, das spiel später irgendwie zu erweitern.


----------



## zerki (20. Mrz 2008)

ui, also ich poste mal meinen ansatz, ich möchte den umgang mit java ja lernen, da jetzt eine fast-fertig lösung zu kopieren (laufzeitverhalten sei mal dahin gestellt), ist nicht mein ziel

mein code sieht derzeit so aus:

probleme die ich hab:

* die zuordnung von Geschenissen auf der GUI zu logischen spielfeldern
   -> Wenn ich das richtig verstanden hab kann ich über den MausListener die CoOrds holen wo eine figur fallen gelassen wurde und dann anhand der spielfeldgrösse berechne wo ich mich befinde ?!?

* die layouts streiken bei mir, was muss ich machen, damit mein feld am rechten bildschirmrand ausgerichtet wird?
* wenn ich auf mein "this"-JPanel farbänderungen am background setze, werden diese nicht durchgeführt. wieso?


```
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Schachbrett extends JPanel
{
	private JFrame frame;
	final private int feldSize = 70;
	
	public Schachbrett()
	{
		frame = new JFrame("Schachbrett");
		frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
		frame.setSize(1024,768);
		frame.setPreferredSize(frame.getSize());
		frame.setLocationRelativeTo(null);
		//frame.setResizable(false);
		
		this.setSize(300, 200);
		this.setBackground(Color.yellow);

	
		frame.setLayout(new BorderLayout());
		frame.getContentPane().add(this);
		frame.pack();
		frame.setVisible(true);
		
	}
	
	protected void paintComponent(Graphics g)
	{	

		// Spielfeld zeichnen
		for(int i=0; i < 8; i++)
			for(int j=0; j < 8; j++)
			{	
				g.drawRect((0+ (feldSize*i)),
							0 + (feldSize*j),
							feldSize, feldSize);
				
				if (i % 2 == 0 ^ j % 2 == 0)
					g.setColor(Color.gray);
				else
					g.setColor(Color.white);
				
				g.fillRect(0 + (feldSize*i),
						   0 + (feldSize*j), feldSize, feldSize);
			}
		
		//Gitternetz nachträglich zeichnen
		g.setColor(Color.black);
		
		for(int i=0; i < 8; i++)
			for(int j=0; j < 8; j++)
			{			
				g.drawRect((0 + (feldSize*i)),
							0 + (feldSize*j),
							feldSize, feldSize);
			}
	}
	
	public static void main(String []args)
	{
		new Schachbrett();
	}
}
[/cod€]
```


----------



## Marco13 (20. Mrz 2008)

1. Zuordnung: Ja. Wenn ein MouseEvent auf dem Panel stattfindet, kann man mit
int feldX = event.getX() / feldSize;
int feldY = event.getY() / feldSize;
ausrechnen, auf welchem Feld man ist.


2. Layouts: Beim Layout wird (wenn überhaupt) dann die PreferredSize berücksichtigt. Und die sollte so sein, dass das ganze Feld gezeichnet werden kann. Um das Panel "im Osten" des Frames hinzuzufügen, muss man ihm das auch sagen :wink:


```
this.setPreferredSize(new Dimension(feldSize*8+1, feldSize*8+1));
...
        frame.getContentPane().add(this, BorderLayout.EAST);
```


3. Background: Im Moment wird ja das komplette Panel mit schwarzen/weißen Feldern übermalt. Wo sollte man da den Hintergrund sehen?


----------



## zerki (20. Mrz 2008)

Marco13 hat gesagt.:
			
		

> 1. Zuordnung: Ja. Wenn ein MouseEvent auf dem Panel stattfindet, kann man mit
> int feldX = event.getX() / feldSize;
> int feldY = event.getY() / feldSize;
> ausrechnen, auf welchem Feld man ist.
> ...



himmel-arsch und.......auf sowas muss man erstmal kommen. wieso wird den die größe die mit setSize() gesetzt wird ignoriert.

und warum +1 ?

ansonsten danke.


----------



## Marco13 (20. Mrz 2008)

Naja, das Setzen der Größe übernimmt eben der LayoutManager (außer bei null-Layout). Und der LayoutManager "versucht", den Components die Größe zu geben, die bei "getPreferredSize" zurückgegeben wird. Sowas wie
frame.setSize(300,300);
panleImFrame.setSize(600,600);
macht eben keinen Sinn. Wenn man dem Panel eine preferredSize von 600x600 setzt, dann ist das wie im richtigen Leben: Das Panel bekommt eben nicht das, was es gerne hätte, weil eine übergeordnete Instanz mehr zu sagen hat :wink:

BTW: Man sollte einem Frame nicht unbedingt eine PreferredSize geben - wenn man "pack" aufruft, wird automatisch ausgerechnet, wie groß der Frame sein muss, damit alle enthaltenen Components in ihrer PreferredSize dargestellt werden können.

_und warum +1 ? _

Jetzt wo du's sagst: Vmlt. wäre es sinnvoller, nicht das "+1" einzubauen, sondern beim Zeichnen des Gitters 
g.drawRect((0 + (feldSize*i)), 0 + (feldSize*j), feldSize-1, feldSize-1); 
hinten jeweils "-1" dazuzuschreiben.... 

Warum ich das "+1" hingeschrieben hatte: Wenn die fieldSize 70 ist, dann würde man bei 8x8 Felder sonst ja sagen
panel.setPreferredSize(new Dimension(560, 560)). 
Das Panel würde also alle Koordinaten von (0,0) bis (559,559) enthalten.

Wenn man dann
g.drawRect((0 + (feldSize*i)), 0 + (feldSize*j), feldSize, feldSize); 
aufruft, dann hat (für i und j ==7) das letzte Rechteck die Abmessungen
(490, 490)-(560,560).
D.h. die untere und rechte Linie dieses Rechtecks läge außerhalb des Bereiches, der vom Panel dargestellt werden kann. 

Aber wie gesagt: Statt des "+1" beim PreferredSize lieber  "-1" beim drawRecht für's Gitter!


----------



## 0x7F800000 (20. Mrz 2008)

@Marco13:
ne, das mit +1 -1 ist irgendein denkfehler, das muss nirgendwo rein, siehe zB meinen code...

oder wenn wirklich solche probleme auftauchen: dann einfach 64buttons reinpacken, wenn man es mit der pixelgenauigkeit nicht hinkriegt^^  :bae: Das mit 64 Komponenten ist anscheinend doch eine recht gute lösung, besser als wenn man an pixeln rumfummelt, und es nicht hinkrigt. Ich selbst habs pixelgenau gleich hinbekommen, dachte deswegen nicht dass es ein problem werden könnte...  :roll:


----------



## Marco13 (20. Mrz 2008)

Andrey hat gesagt.:
			
		

> @Marco13:
> ne, das mit +1 -1 ist irgendein denkfehler, das muss nirgendwo rein, siehe zB meinen code...



Jupp, dein Code - ohne umrahmte Felder. Wenn man in deiner paint-Methode mal

```
for(int y=0; y<8; y++){
      //background
      g.setColor(((x+y)%2==0)?(Color.DARK_GRAY):(new Color(200,150,100)));
      g.fillRect(x*cellWidth,
               y*cellHeight,
               cellWidth,
               cellHeight);

//--->--- Diesen Teil
      g.setColor(Color.GREEN);
      g.drawRect(x*cellWidth,
               y*cellHeight,
               cellWidth,
               cellHeight);
//---<--- Diesen Teil
```
einfügt (und die Größe des Panels auf einen Wert einstellt, der glatt durch 8 teilbar ist), kommt das raus:





Und dort fehlt rechts unten die grüne Umrandung.

Was willst'n eigentlich?  :x Hab's doch vorgerechnet  :meld:  :bae:  :wink:


----------



## 0x7F800000 (20. Mrz 2008)

achso, jo, okay... sry, hab irgendwie gar nich mitbekommen dass es um irgendeinen grünen rahmen geht^^


----------



## zerki (25. Mrz 2008)

hallo, ich wieder  :autsch: 

ich bin mitterlweile soweit, das ich mein GUI aufgebaut bekomme und meine figuren in initialposition anordnen kann. Jetzt bin ich aber am grübeln wie ich die Verknüpfung zwischen GUI-Elementen und Logik hergestellt bekomme.

ich habe ein Array[4][8] das meine Spielfiguren aufnimmt. jetzt müsste ich die position der figuren auf der gui ja irgendwie auf einem anderem [8][8] array darstellen.

nur weis ich da überhaupt nicht, was ich da für ein array nehmen soll. 

wäre es sinnvoll eine eigenen klasse für die spielfelder zu machen, so dass ich dann 8x8 spielfelder erzeuge und diese dann das image aufnehmen, sprich die figur, die auf dem feld stehen?

beim durchdenken ist das alles so extrem kompliziert, liegt das an der materie oder denk ich einfach zu kompliziert.


----------



## 0x7F800000 (25. Mrz 2008)

du denkst zu kompliziert...
warum brauchst du irgendwelche extra-arrays für die figuren an sich? in schach haben die figuren doch gar keine veränderliche eigenschaften, die haben einfach nur ihren typ, einen healthpoint, 0 rüstung und 1 attakke und sonst nichts... (das mit hp, armor etc war natürlich ironisch gemeint=> das brauchst du nicht zu speichern, es ist immer so)

Ich würde vorschlagen, dass du "figur" einfach als eine eigenschaft des feldes auffasst, und alle typen in ein Enum pakst. Ähm... nun gut, eine eigenschaft haben die doch: farbe s/w. Ein boolean mit dazunehmen halt...
Dann machst du noch 2-3 statische funktionen, die überprüfen ob der eine oder der andere zug gültig ist, und ob einer gewonnen hat etc, und das war es schon...


----------



## Wildcard (25. Mrz 2008)

Andrey hat gesagt.:
			
		

> Ähm... nun gut, eine eigenschaft haben die doch: farbe s/w. Ein boolean mit dazunehmen halt...


Und mindestens noch eine Wertigkeit für die Gütefunktion. Dazu kommen dann noch spezielle Felder für bestimmte Figuren, beispielsweise sollte ein Bauer wissen, ob er schon bewegt wurde.


----------



## 0x7F800000 (26. Mrz 2008)

tja, wer schach-regeln kennt ist klar im vorteil, gute beobachtung Wildcard :toll:
Dann lohnt es sich doch eine kleine klasse für die figuren anzulegen... aber dann bitte keine krummen arrays wie 8x4 arrays, das macht irgendwie wenig sinn... einfach nur Figure[32] und fertig.
Jede Figur müsste sich dann merken:
-Typ (ein wert aus dem enum)
-Farbe
-Koordinaten (x,y)
-Status (wie etwa das, was der Wildcard genannt hat)
-tot oder nicht tot? oder ganz entfernen und auf "null" prüfen...


----------



## zerki (26. Mrz 2008)

momentan sieht mein Code so aus, habe also noch keinen logischen Bezug zu den Geschenissen auf der GUI. Ich habe zwar verstanden was du damit meinst die figur als eigenschaft des feldes aufzufassen, aber nicht wie ich das jetzt umsetzen kann....soll ich dann dem schachbrett ein 8x8 array aus spielfiguren geben und alle spielfiguren wo das image=null ist, sind dann leere felder?


```
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Schachbrett extends JPanel implements MouseMotionListener, MouseListener
{
	private JFrame frame;
	private JPanel visualArea;
	final private int feldSize = 70;
	final private int textSpace = 50;
	
	private Spielfigur[][] spielFigur;
	
	public Schachbrett()
	{
		initSpielfiguren();
		
		frame = new JFrame("Schachbrett");
		frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
		frame.setSize(1024,768);
		frame.setPreferredSize(frame.getSize());
		frame.setLocationRelativeTo(null);
		frame.setResizable(false);
		
		this.setSize((feldSize*8+1)+ textSpace, (feldSize*8+1) + textSpace);
		this.setPreferredSize(new Dimension((feldSize*8+1)+ textSpace, (feldSize*8+1)+ textSpace));
		this.setMaximumSize(this.getSize());
		this.setBackground(new Color(255,23,132));
		this.addMouseMotionListener(this);
		
		visualArea = new JPanel();
		visualArea.setSize(new Dimension(frame.getSize()));
		visualArea.setPreferredSize(new Dimension(frame.getSize()));
		visualArea.setLayout(new BorderLayout());
		visualArea.setBackground(Color.green);
		visualArea.add(this, BorderLayout.EAST);
	
		frame.getContentPane().add(visualArea);
		frame.pack();
		frame.setVisible(true);
	}
	
	public Dimension getFigurPos(int x, int y)
	{
		return new Dimension(this.spielFigur[x][y].getImage().getWidth(this),
				             this.spielFigur[x][y].getImage().getHeight(this)); 
	}
	
	private void initSpielfiguren()
	{
		spielFigur = new Spielfigur[4][8];
		
		// Figuren Farbe Weiss
		spielFigur[0][0] = new Spielfigur('T', false, 0, 0, feldSize, textSpace, 40);
		spielFigur[0][1] = new Spielfigur('S', false, 1, 0, feldSize, textSpace, 40);
		spielFigur[0][2] = new Spielfigur('L', false, 2, 0, feldSize, textSpace, 40);
		spielFigur[0][3] = new Spielfigur('D', false, 3, 0, feldSize, textSpace, 40);
		spielFigur[0][4] = new Spielfigur('K', false, 4, 0, feldSize, textSpace, 40);
		spielFigur[0][5] = new Spielfigur('L', false, 5, 0, feldSize, textSpace, 40);
		spielFigur[0][6] = new Spielfigur('S', false, 6, 0, feldSize, textSpace, 40);
		spielFigur[0][7] = new Spielfigur('T', false, 7, 0, feldSize, textSpace, 40);
		//Bauern
		for(int i=0; i < 8; i++)
			spielFigur[1][i] = new Spielfigur('B', false, i, 1, feldSize, textSpace, 40);
		
		//Figuren Farbe Schwarz
		spielFigur[2][0] = new Spielfigur('T', true, 0, 7, feldSize, textSpace, 40);
		spielFigur[2][1] = new Spielfigur('S', true, 1, 7, feldSize, textSpace, 40);
		spielFigur[2][2] = new Spielfigur('L', true, 2, 7, feldSize, textSpace, 40);
		spielFigur[2][3] = new Spielfigur('D', true, 3, 7, feldSize, textSpace, 40);
		spielFigur[2][4] = new Spielfigur('K', true, 4, 7, feldSize, textSpace, 40);
		spielFigur[2][5] = new Spielfigur('L', true, 5, 7, feldSize, textSpace, 40);
		spielFigur[2][6] = new Spielfigur('S', true, 6, 7, feldSize, textSpace, 40);
		spielFigur[2][7] = new Spielfigur('T', true, 7, 7, feldSize, textSpace, 40);
		//Bauern
		for(int i=0; i < 8; i++)
			spielFigur[3][i] = new Spielfigur('B', true, i, 6, feldSize, textSpace, 40);
	}

	
	protected void paintComponent(Graphics g)
	{
	
		super.paintComponent(g);
		
	// Spielfeld zeichnen
		for(int i=0; i < 8; i++)
			for(int j=0; j < 8; j++)
			{
				g.drawRect((textSpace+ (feldSize*i)),
						0 + (feldSize*j),
				feldSize, feldSize);
				
				if (i % 2 == 0 ^ j % 2 == 0)
				g.setColor(Color.gray);
				else
				g.setColor(Color.orange);
				
				g.fillRect(textSpace + (feldSize*i),
						0 + (feldSize*j), feldSize, feldSize);
			}
		
		//Gitternetz nachträglich zeichnen
		g.setColor(Color.black);
		
		for(int i=0; i < 8; i++)
			for(int j=0; j < 8; j++)
			{
				g.drawRect((textSpace + (feldSize*i)),
						0 + (feldSize*j),
				feldSize, feldSize);
			}
		
		// Horizontale Spielfeldbeschriftung
		char []letter ={'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'};
		// Vertikale Spielfeldbeschriftung
		char []digits ={'8', '7', '6', '5', '4', '3', '2', '1'};
		
		for(int i=0; i < 8; i++)
		{
			g.drawChars(letter,i, 1, textSpace + (feldSize/2) + (feldSize *i), feldSize *8 + 20);
			g.drawChars(digits, i, 1, 20, feldSize/2 + feldSize*i);
		}
		
		//Spielfiguren zeichnen
		for(int i= 0; i < 8; i++)
			for(int j=0; j <4; j++)
			g.drawImage(spielFigur[j][i].getImage(),
						spielFigur[j][i].getPositionX(),
						spielFigur[j][i].getPositionY(),
						this);
}
	
		
	public void mouseDragged(MouseEvent e)
	{
			//Image img;
			//Dimension dim;
			//int x,y;
			//x = (e.getX()- textSpace)/feldSize;
			//y = e.getY()/feldSize;
			//System.out.println("X: "+ x);
			//System.out.println("Y: "+ y);*/



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

	@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
		
	}
	
	
	public static void main(String []args)
	{
		new Schachbrett();
	}



}
```

Meine Figurenklasse

```
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.ImageObserver;


public class Spielfigur 
{
	private Image img;
	private int positionX, positionY;
	private int sizeX, sizeY;
	
	public Spielfigur()
	{
		img = null;
		positionX = 0;
		positionY = 0;
	}
	
	public int getPositionX()
	{
		return positionX;
	}
	
	public int getPositionY()
	{
		return positionY;
	}
	
	public void setPositionX(int _x)
	{
		positionX = _x;
	}
	
	public void setPositionY(int _y)
	{
		positionY = _y;
	}
	
	Spielfigur(char figurTyp, boolean color, int _x, int _y, int _feldSize, int _textSpace, int _picSize)
	{

		switch(figurTyp)
		{
			
		//König
		case 'K':
			if(color) //true = schwarze Spielfigur
				img = Toolkit.getDefaultToolkit().getImage("koenig_black.gif");
			else      //false = weisse Spielfigur
				img = Toolkit.getDefaultToolkit().getImage("koenig_white.gif");
			break;
		//Dame
		case 'D':
			if(color) //true = schwarze Spielfigur
				img = Toolkit.getDefaultToolkit().getImage("dame_black.gif");
			else      //false = weisse Spielfigur
				img = Toolkit.getDefaultToolkit().getImage("dame_white.gif");
			break;
		//Turm	
		case 'T':
			if(color) //true = schwarze Spielfigur
				img = Toolkit.getDefaultToolkit().getImage("turm_black.gif");
			else      //false = weisse Spielfigur
				img = Toolkit.getDefaultToolkit().getImage("turm_white.gif");
			break;
		//Läufer	
		case 'L':
			if(color) //true = schwarze Spielfigur
				img = Toolkit.getDefaultToolkit().getImage("laeufer_black.gif");
			else      //false = weisse Spielfigur
				img = Toolkit.getDefaultToolkit().getImage("laeufer_white.gif");
			break;
		//Springer	
		case 'S':
			if(color) //true = schwarze Spielfigur
				img = Toolkit.getDefaultToolkit().getImage("springer_black.gif");
			else      //false = weisse Spielfigur
				img = Toolkit.getDefaultToolkit().getImage("springer_white.gif");
			break;
		//Bauer
		case 'B':
			if(color) //true = schwarze Spielfigur
				img = Toolkit.getDefaultToolkit().getImage("bauer_black.gif");
			else      //false = weisse Spielfigur
				img = Toolkit.getDefaultToolkit().getImage("bauer_white.gif");
			break;
		}
		
		
		if (img != null)
		{
			positionX = _textSpace + _x *_feldSize + (_feldSize - _picSize)/2;
		    positionY = _y * _feldSize + (_feldSize - _picSize)/2;
		}
	}
		
	public Image getImage()
	{
		return img;
	}

}
```


----------



## 0x7F800000 (26. Mrz 2008)

neeee....
das geht so ned...

zum einen hat Wildcard schon gesagt, dass es mit "figurtyp als zustand des feldes" nicht gehen kann, das war mein denkfehler, weil ich mich einfach schlecht mit schach auskenne...

aber was soll das denn sein:

```
public class Spielfigur 
{ 
   private Image img; 
   private int positionX, positionY; 
   private int sizeX, sizeY;
```
das ist doch der übelste mix aus grafik und logik, den man sich vorstellen kann...

Überleg doch mal: wieviele positionen musst du bei 32 figuren abspeichern? 
=> genau 32, ein koordinatenpaar PRO FIGUR

Und wieviele bilder musst du abspeichern? 32 wäre eine krasse verschwendung, es gibt ja insgesamt nur sechs TYPEN, na gut, wegen den zwei farben brauchst du insgesamt 12 bilder, aber du brauchst definitiv nicht für jede figur ein bild. Wie der logische aufbau der Figur in etwa aussehen soll, habe ich schon im letzten beitrag skizziert.

Der "logische" teil des Programmes muss vollkommen frei von der GUI sein. Dieser teil muss komplett frei von jeglichen Swing oder AWT-Objekten sein: keine bilder, keine components etc... Es muss genausogut auf einem computer laufen, an den niemals ein bildschirm angeschlossen werden kann, und der stattdessen ein holzbrett mit irgendwelchen sensoren hat. An der verwaltung des Spielzustandes darf sich nichts ändern.


----------



## zerki (26. Mrz 2008)

hm, nagut,hab dann die figur klasse mal kastriert, die zugriffsfunktionen hab ich mal weg gelassen. die enum's "figurTyp" und "figurColor" musste ich in meiner hauptklasse defniere wo ich die klasse von ausrufe.


```
public class Spielfigur 
{
	private int positionX, positionY;
	private figurTyp typ;
	private figurColor color;
	private boolean alive;
	
	Spielfigur(figurTyp _typ, figurColor _color, int _posX, int _posY) 
	{
		typ	= _typ;
		color = _color;
		positionX = _posX;
		positionY = _posY;
		alive = true;
	}

}
```

mein primärziel ist es erstmal die figuren auf dem spielfeld grafisch darzustellen und diese bewegen zu können und diese bewegungen "erfassen" zu können.(regeln und wer sich wohin bewegen darf( etc.) kommt später, ich kann selbst nämlich auch kein schach ;-) ).

die images zum zeichnen auf der gui hol ich mir dann in meiner schachbrett-klasse wo auch die restlichen zeichen aktionen ausgeführt werden, seh ich das richtig?


----------



## 0x7F800000 (26. Mrz 2008)

jo, hört sich schon besser an  :toll:


----------



## zerki (26. Mrz 2008)

es klappt soweit, ich kann jetzt figuren über die gui bewegen:

kann nochmal jemand wegen des klassen design drauf schauen, ich will mir ja vom stil her nichts angewöhnen was ganz häßlich ist   


```
import java.awt.BorderLayout;
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.event.MouseMotionListener;

import javax.swing.JFrame;
import javax.swing.JPanel;



enum figurTyp 	{king, queen, castle, bishop, knight, pawn};
enum figurColor	{black, white};


public class Schachbrett extends JPanel implements MouseMotionListener, MouseListener
{
	private JFrame frame;
	private JPanel visualArea;
	final private int feldSize = 70;
		
	private Spielfigur[]spielFigur;
	
	/**
	 * Position der Figur im Array, die Grade bewegt wird.
	 */
	private int arrayPosMoveFigur;
	
	public Schachbrett()
	{
		initSpielfiguren();
		
		frame = new JFrame("Shitty Chess 2008");
		frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
		frame.setSize(1024,768);
		frame.setPreferredSize(frame.getSize());
		frame.setLocationRelativeTo(null);
		frame.setResizable(false);
		
		this.setSize((feldSize*8+1), (feldSize*8+1));
		this.setPreferredSize(new Dimension(feldSize*8+1, feldSize*8+1));
		this.setMaximumSize(this.getSize());
		this.setBackground(new Color(255,23,132));
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
		
		visualArea = new JPanel();
		visualArea.setSize(new Dimension(frame.getSize()));
		visualArea.setPreferredSize(new Dimension(frame.getSize()));
		visualArea.setLayout(new BorderLayout());
		visualArea.setBackground(Color.green);
		visualArea.add(this, BorderLayout.EAST);
	
		frame.getContentPane().add(visualArea);
		frame.pack();
		frame.setVisible(true);
	}
	
	public void initSpielfiguren()
	{
		spielFigur = new Spielfigur[32];
		
		spielFigur[0] = new Spielfigur(figurTyp.castle, figurColor.black, 0, 0);
		spielFigur[1] = new Spielfigur(figurTyp.knight, figurColor.black, 1, 0);
		spielFigur[2] = new Spielfigur(figurTyp.bishop, figurColor.black, 2, 0);
		spielFigur[3] = new Spielfigur(figurTyp.queen,  figurColor.black, 3, 0);
		spielFigur[4] = new Spielfigur(figurTyp.king,   figurColor.black, 4, 0);
		spielFigur[5] = new Spielfigur(figurTyp.bishop, figurColor.black, 5, 0);
		spielFigur[6] = new Spielfigur(figurTyp.knight, figurColor.black, 6, 0);
		spielFigur[7] = new Spielfigur(figurTyp.castle, figurColor.black, 7, 0);
		
		for(int i=8; i < 16; i++)
			spielFigur[i] = new Spielfigur(figurTyp.pawn, figurColor.black, i-8, 1);
		
		spielFigur[16] = new Spielfigur(figurTyp.castle, figurColor.white, 0, 7);
		spielFigur[17] = new Spielfigur(figurTyp.knight, figurColor.white, 1, 7);
		spielFigur[18] = new Spielfigur(figurTyp.bishop, figurColor.white, 2, 7);
		spielFigur[19] = new Spielfigur(figurTyp.queen,  figurColor.white, 3, 7);
		spielFigur[20] = new Spielfigur(figurTyp.king,   figurColor.white, 4, 7);
		spielFigur[21] = new Spielfigur(figurTyp.bishop, figurColor.white, 5, 7);
		spielFigur[22] = new Spielfigur(figurTyp.knight, figurColor.white, 6, 7);
		spielFigur[23] = new Spielfigur(figurTyp.castle, figurColor.white, 7, 7);

		for(int i=24; i < 32; i++)
			spielFigur[i] = new Spielfigur(figurTyp.pawn, figurColor.white, i-24, 6);
		
	}
	
	public int checkPositionForFigur(int _x, int _y)
	{
		for(int i=0; i < 32; i++)
			if (spielFigur[i].getPositionX() == _x &&
				spielFigur[i].getPositionY() == _y)
				return i;
		
		return -1;
	}
	
	public Image getImage(Spielfigur figur)
	{
		Image img = null;
		
		switch(figur.getFigurTyp())
		{
		case castle:
			if (figur.getFigurColor() == figurColor.black)
				img = Toolkit.getDefaultToolkit().getImage("castle_black.gif");
			else
				img = Toolkit.getDefaultToolkit().getImage("castle_white.gif");
			break;
			
		case knight:
			if (figur.getFigurColor() == figurColor.black)
				img = Toolkit.getDefaultToolkit().getImage("knight_black.gif");
			else
				img = Toolkit.getDefaultToolkit().getImage("knight_white.gif");
			break;
			
		case bishop:
			if (figur.getFigurColor() == figurColor.black)
				img = Toolkit.getDefaultToolkit().getImage("bishop_black.gif");
			else
				img = Toolkit.getDefaultToolkit().getImage("bishop_white.gif");
			break;
			
		case queen:
			if (figur.getFigurColor() == figurColor.black)
				img = Toolkit.getDefaultToolkit().getImage("queen_black.gif");
			else
				img = Toolkit.getDefaultToolkit().getImage("queen_white.gif");
			break;
			
		case king:
			if (figur.getFigurColor() == figurColor.black)
				img = Toolkit.getDefaultToolkit().getImage("king_black.gif");
			else
				img = Toolkit.getDefaultToolkit().getImage("king_white.gif");
			break;
			
		case pawn:
			if (figur.getFigurColor() == figurColor.black)
				img = Toolkit.getDefaultToolkit().getImage("pawn_black.gif");
			else
				img = Toolkit.getDefaultToolkit().getImage("pawn_white.gif");
			break;
		}
		
		return img;
	}
	
	protected void paintComponent(Graphics g)
	{
	
		super.paintComponent(g);
		
	// Spielfeld zeichnen
		for(int i=0; i < 8; i++)
			for(int j=0; j < 8; j++)
			{
				g.drawRect(((feldSize*i)),
						0 + (feldSize*j),
				feldSize, feldSize);
				
				if (i % 2 == 0 ^ j % 2 == 0)
				g.setColor(Color.gray);
				else
				g.setColor(Color.orange);
				
				g.fillRect((feldSize*i),
						0 + (feldSize*j), feldSize, feldSize);
			}
		
		//Gitternetz nachträglich zeichnen
		g.setColor(Color.black);
		
		for(int i=0; i < 8; i++)
			for(int j=0; j < 8; j++)
			{
				g.drawRect(((feldSize*i)),
						0 + (feldSize*j),
				feldSize, feldSize);
			}
		
	/*	// Horizontale Spielfeldbeschriftung
		char []letter ={'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'};
		// Vertikale Spielfeldbeschriftung
		char []digits ={'8', '7', '6', '5', '4', '3', '2', '1'};
		
		for(int i=0; i < 8; i++)
		{
			g.drawChars(letter,i, 1, (feldSize/2) + (feldSize *i), feldSize *8 + 20);
			g.drawChars(digits, i, 1, 20, feldSize/2 + feldSize*i);
		}*/
		
		for(int i=0; i < 32; i++)
			g.drawImage(this.getImage(spielFigur[i]),
					spielFigur[i].getPositionX()* feldSize + (feldSize - this.getImage(spielFigur[i]).getWidth(this))/2,
					spielFigur[i].getPositionY()* feldSize+ (feldSize - this.getImage(spielFigur[i]).getWidth(this))/2,
					this);
}
	

	@Override
	public void mouseDragged(MouseEvent e) {

		if (arrayPosMoveFigur != 0)
		{
			spielFigur[arrayPosMoveFigur].setPositionX(e.getX()/feldSize);
			spielFigur[arrayPosMoveFigur].setPositionY(e.getY()/feldSize);
			repaint();
		}	
	}

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


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

	@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) {
		int x=0, y=0;
		
		x = e.getX()/ feldSize;
		y = e.getY()/ feldSize;
		
		arrayPosMoveFigur = this.checkPositionForFigur(x, y);
	}

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


	public static void main(String []args)
	{
		new Schachbrett();
	}



}
```


```
public class Spielfigur 
{
	private int positionX, positionY;
	private figurTyp typ;
	private figurColor color;
	private boolean alive;
	
	Spielfigur(figurTyp _typ, figurColor _color, int _posX, int _posY) 
	{
		typ	= _typ;
		color = _color;
		positionX = _posX;
		positionY = _posY;
		alive = true;
	}
	
	public figurTyp getFigurTyp()
	{
		return typ;
	}
	
	public figurColor getFigurColor()
	{
		return color;
	}
	
	public int getPositionX()
	{
		return positionX;
	}
	
	public void setPositionX(int _x)
	{
		positionX = _x;
	}
	
	public void setPositionY(int _y)
	{
		positionY = _y;
	}
	
	public int getPositionY()
	{
		return positionY;
	}
}
```


----------



## sc0p (18. Jan 2010)

Top Diskussion 
Was ist denn mit dem Projekt geworden?
& warum hab ich keine Figuren bei deinem Beispiel ? 

hehe 
gruss,sc0p


----------

