//Dies sind Enumerationen. Eine Enumeration für Zeilen...
public enum Row{
1 (1),
2 (2),
3 (3),
4 (4),
5 (5),
6 (6),
7 (7),
8 (8);
private final int value;
private Row(int value){
this.value = value;
}
public Row increment(){
int i = value + 1;
if(i > 8){ i = 1;}
return getRowFromValue(i);
}
public Row decrement(){
int i = value - 1;
if(i < 1){ i = 8;}
return getRowFromValue(i);
}
private getRowFromValue(int i){
switch(i){
case 1: return Row.1;
case 2: return Row.2;
case 3: return Row.3;
case 4: return Row.4;
case 5: return Row.5;
case 6: return Row.6;
case 7: return Row.7;
case 8: return Row.8;
}
}
}
//...und eine für Spalten.
public enum Column{
A (1),
B (2),
C (3),
D (4),
E (5),
F (6),
G (7),
H (8);
private final int value;
private Column(int value){
this.value = value;
}
public Column increment(){
int i = value + 1;
if(i > 8){ i = 1;}
return getColumnFromValue(i);
}
public Column decrement(){
int i = value - 1;
if(i < 1){ i = 8;}
return getColumnFromValue(i);
}
private getColumnFromValue(int i){
switch(i){
case 1: return Column.A;
case 2: return Column.B;
case 3: return Column.C;
case 4: return Column.D;
case 5: return Column.E;
case 6: return Column.F;
case 7: return Column.G;
case 8: return Column.H;
}
}
}
//Das ist eine Klasse. Wie eine Klasse benutzt wird...kommt noch. Bis dahin betrachte eine
//Klasse als Bauplan.
public class Position{
private Row row; //Jede Position liegt auf einer Zeile...
private Column column; //...und auf einer Spalte.
public Position(Row row, Column column){ //Dies ist ein Konstruktor.
this.row = row; //Damit wird ein Positionsobjekt erzeugt (kommt auch noch).
this.column = column; //Dem Positionsobjekt muß mit den Übergabeparametern mitgeteilt werden, welche Position es ist.
}
@Override
public int hashCode() {
return Objects.hash(row, column);
}
@Override
public boolean equals(Object obj) { //Diese Methode besorgt einen Vergleich mit anderen Objekten und
if(obj instanceof Position){ //liefert true, wenn das andere Objekt auch ein Positionsobjekt ist UND wenn es diesselben Koordinaten hat.
Position p = (Positon) obj; //Ansonsten false.
return this.row == p.row && this.column == p.column;
}
return false;
}
public void moveToNorth(){
row.increment();
}
public void moveToSouth(){
row.decrement();
}
public void moveToEast(){
column.increment();
}
public void moveToWest(){
column.decrement();
}
public Position clone(){
return new Position(row, column);
}
}
//Dies noch eine Klasse. Besonderheit: diese Klasse ist abstrakt, d.h. es kann kein Objekt
//damit gebaut werden. Warum das so ist - kommt noch. Fürs erste sei gesagt, daß diese
//Klasse für alles zuständig ist was eine Schachfigur ausmacht.
public abstract class ChessPiece{
private Position myPosition;
public ChessPiece(Position startPosition){ //Jede Schachfigur hat eine Position. Die braucht sie schon am Anfang.
myPosition = startPosition;
}
/**
* Liefert die gegenwärtige Position der Schachfigur zurück.
*/
public Position getPosition(){ //Jede Klasse von Typ ChessPiece stellt diese Methode zur Verfügung...
return myPosition;
}
/**
* Stellt die Schachfigur auf eine neue Position.
*/
public void setNewPosition(Position newPosition){ //...genauso wie diese Methode. 'Public' heißt, daß die Methode von überall her öffentlich zugänglich ist.
myPosition = newPosition;
}
protected Position myPosition(){ //Protected heißt, daß die Methode nur von abgeleiteten Klassen (kommt gleich) aufgerufen werden kann.
return myPosition;
}
/**
* Diese Methode liefert ein HashSet mit allen möglichen Positionen,
* auf die das ChessPieceobjekt bewegt werden kann.
*/
public abstract HashSet<Position> getPossiblePositions(); //Dies ist eine abstrakte Methode.
//Was mit dieser leeren Methode gemacht wird - kommt geich.
}
//Dies ist die Klasse für Läufer. Läufer ist von der Art Schachfigur. Was hier gemacht wird, ist als Vererbung bekannt.
//Die Klasse Runner ist eine Art von ChessPiece. Ein Läufer ist eine Schachfigur (aber nicht jede Schachfigur ein Läufer).
//Die Klasse ist nicht mehr abstrakt, da Objekte von ihr gebildet werden sollen. Jetzt ist es vielleicht auch logischer:
//Du kannst nicht einfach eine x-beliebige Schachfigur erzeugen. Woher soll der Compiler wissen, welche du haben willst?
//Eine Figur 'Läufer' ist aber konkret genug, damit der Compiler weiß was du willst.
//Abstrakte Klassen dienen dazu, abstrakte Dinge zu definieren. Konkrete (also nichtabstrakte) Klassen konkretisieren diese.
//Das passiert jetzt mit der Methode getPossiblePositions().
public class Runner extends ChessPiece{
public Runner(Position startPosition){
super(startPosition); //Fordere eine Position ein, auf die die Figur gesetzt werden kann. Mit super() wird der Parameter an die Superklasse durchgereicht.
}
@Override //Die Override-Annotation zeigt an, daß die Methode 'getPossiblePositions' bereits existiert, jedoch überschrieben wird.
public abstract HashSet<Position> getPossiblePositions(){ //Diese Methode wird deshalb in der Superklasse 'ChessPiece' bereits deklariert, weil jede Schachfigur diese Methode haben soll.
HashSet<Position> possiblePositions = new HashSet<>(); //Wir wollen, das jede Schachfigur alle möglichen Positionen, auf die sie von ihrer aktuellen Position aus gesetzt werden kann,
//berechnen kann. Aber was soll 'irgendeine Schachfigur' genau berechnen? Läufer werden nunmal anders gezogen als Bauern, das ist halt so.
//Deshalb wird diese Methode erst hier in der konkreten Klasse implementiert.
Position p = super.myPosition().clone(); //Kopie der aktuellen Position erstellen.
do{ //Die Schleife läuft mindestens einmal.
p.moveToNorth(); //Wir ziehen einmal nach Norden...
p.moveToWest(); //...und einmal nach Westen, sodaß wir auf einem diagonal benachbarten Feld stehen...
possiblePositions.add(p); //...dann kopieren wir diese Position als mögliche Position in das HashSet...
}while(p.equals(super.myPosition()); //...und machen das so lange, bis wir wieder dort stehen wo wir angefangen haben.
//Damit ist eine Diagonale abgefahren.
do{ //Jetzt dasselbe nochmal mit der anderen Diagonalen.
p.moveToSouth();
p.moveToEast();
possiblePositions.add(p);
}whilep.equals(super.myPosition());
return possiblePositions; //Alle möglichen Positionen, auf die der Läufer gesetzt werden kann, sind im HashSet und werden zurückgegeben.
}
}
//Jetzt benutzen wir das Ganze mal:
public static void main(String[] args){
Position runnersStartposition = new Position(Row.1, Column.C); //Die Startposition des Läufers. 'new Position' ruft den Konstruktor der Klasse auf und erzeugt ein Objekt.
Position anotherPosition = new Position(Row.1, Column.F); //Objekte kann man mehrfach erzeugen, man sagt auch instanzieren. runnersStartposition und anotherPosition sind
//Instanzen der Klasse Position.
Runner myRunner = new Runner(runnersStartposition); //Und da ist er, unser erster Läufer.
Runner yourRunner = new Runner(anotherPosition); //Und da ist noch ein zweiter Läufer. Bedenke, daß du für ein richtiges Spiel insgesamt vier Läufer brauchst, die kannst du alle
//genauso instanzieren wie die ersten beiden, mußt aber nur Code für einen einzigen Läufer schreiben. (Auch) deshalb ist Java so geil. :)
//Und hier wird die Ausgangsfrage deines Threads endlich beantwortet:
Position anyPosition;
//...
if(myRunner.getPossiblePositions.contains(anyPosition){
//...
}
}