Schach(Springer Logik)

Hias12345

Hias12345

Mitglied
Ich bin gerade dabei die Überprüfung ob der Springer auf das eingegebene Feld springen kann. Da kommen ich jedoch nicht mehr weiter. Ich habe eine if Verzweigung und diese Verzweigung soll ausgeführt werden, wenn auf das eingegebene Feld die Figur gezogen werden kann. Nun die Frage kann mir jemand helfen bzw sagen was ind die Klammer kommt (if(...))?
 
H

httpdigest

Top Contributor
Naja, doch ganz offensichtlich so:
Java:
if (aufDasFeldKannGezogenWerden(springer, feld)) {
  ...
}
Jetzt mal im Ernst: Du hast uns doch überhaupt rein garnichts vorgegeben, z.B. wie du überhaupt das Feld modellierst...
 
kneitzel

kneitzel

Top Contributor
Also da bitte etwas mehr auf die Modellierung achten. Ob eine Figur auf ein bestimmtes Feld ziehen kann oder nicht obliegt ja der Figur würde ich sagen.

Daher wäre doch eher ein
Java:
if (springer.canMoveTo(zielfeld)) { ... }
angebracht.

Dann hat die Figur eine Position, ein Zielposition wird angegeben.

Eine Position hat natürlich die notwendigen Informationen bezüglich Belegung. Das ist wichtig, um das zu entscheiden.

Dann hätte man in jeder Figur die jeweilige Logik, die diverse Dinge enthalten kann wie:
- Unterschiedliches Verhalten je nach Belegung des Feldes (Beim Bauer das Schlagen!)
- die Prüfung von allen Feldern auf dem Weg (Turm, Dame, Läufer ...) und ggf. der Figur daraus. (Rochade - Weg muss frei sein, König und Turm dürfen noch nicht bewegt worden sein ...)

Da kann man also recht schnell ein recht schönes Objektmodell zusammen bauen ...
 
Hias12345

Hias12345

Mitglied
Naja, doch ganz offensichtlich so:
Java:
if (aufDasFeldKannGezogenWerden(springer, feld)) {
  ...
}
Jetzt mal im Ernst: Du hast uns doch überhaupt rein garnichts vorgegeben, z.B. wie du überhaupt das Feld modellierst...

public boolean zug(int xKoord,int yKoord) {
if(....){
return super.zug(xKoord, yKoord);
}
return false;

Also die beiden Koordinaten xKoord und yKoord sind die beiden Werte auf die der Springer ziehen soll. Mit dem Befehl super.getx/yKoord bekomme ich die aktuellen Position der Figur. Nun soll mit diesen vier Werten die Prüfung aufgestellt werden. Die Prüfung soll korrekt sein wenn der Zug ausführbar ist.

Hoffe es ist jetzt ausreichend gut angegeben mein Problem
 
kneitzel

kneitzel

Top Contributor
Was hast du dir denn dazu überlegt? Hast Du Dir das mal aufgemalt? Evtl. erleichtert das die Überlegungen.
 
M

M.L.

Top Contributor
Es gilt zu prüfen ob das Zielfeld mit einem eigenen Stein belegt ist und ob das als 8x8 angenommene Schachbrett nicht überschritten wird. Und bei den Zahlen für die Koordinaten werden entweder 1 oder 2 addiert (oder subtrahiert) und selbiges bei den Buchstaben (in Zahlen umgewandelt). Dabei die L-Form des Springerzugs beachten.
 
W

White_Fox

Top Contributor
Ich würde das ja eher so aufziehen:

Java:
Chesspiece chesspiece = new Horse(Black, Positioin.B8);

if(chesspiece.getPossiblePositions().equals(someOtherPositoin)){
    //...
}

Nachtrag:
Ja, im Threadtitel steht was von Springer. Und nein, in meinem Code steht nix von Springer. Ja, das ist Absicht.
 
H

httpdigest

Top Contributor
mit
Java:
chesspiece.getPossiblePositions().equals(someOtherPositoin)
verlagerst du das "Problem" ja einfach nur nach getPossiblePositions(). Und ich weiss nicht, ob eine Liste von Positionen "gleich" einer Position sein sollte.
 
Hias12345

Hias12345

Mitglied
Ich würde das ja eher so aufziehen:

Java:
Chesspiece chesspiece = new Horse(Black, Positioin.B8);

if(chesspiece.getPossiblePositions().equals(someOtherPositoin)){
    //...
}

Nachtrag:
Ja, im Threadtitel steht was von Springer. Und nein, in meinem Code steht nix von Springer. Ja, das ist Absicht.
Ja dies Möglichkeit hab ichauch schon gesehn aber unser Lehrer will das in der If verzwigung mit Logik gearbeitet wird zB && und ||
 
W

White_Fox

Top Contributor
Das ist gut das euer Lehrer das will. Ich stelle es mir sehr schwer vor, in einer If-Abfrage ohne Logik auszukommen.
 
W

White_Fox

Top Contributor
mit
Java:
chesspiece.getPossiblePositions().equals(someOtherPositoin)
verlagerst du das "Problem" ja einfach nur nach getPossiblePositions(). Und ich weiss nicht, ob eine Liste von Positionen "gleich" einer Position sein sollte.
Da haste recht...es sollte auch chesspiece.getPossiblePositions().contains(someOtherPositoin) heißen.

Klar ist das eine Problemverlagerung, aber was willst du ihm sonst raten wenn du nicht weißt, wie er was implementiert hat. Ich wollte ihn auf einen objektorientierten Ansatz schubsen...das, was er bisher beschreibt, sieht schlimm nach prozeduraler Quälerei aus.
 
Hias12345

Hias12345

Mitglied
Da haste recht...es sollte auch chesspiece.getPossiblePositions().contains(someOtherPositoin) heißen.

Klar ist das eine Problemverlagerung, aber was willst du ihm sonst raten wenn du nicht weißt, wie er was implementiert hat. Ich wollte ihn auf einen objektorientierten Ansatz schubsen...das, was er bisher beschreibt, sieht schlimm nach prozeduraler Quälerei aus.
Ich habe eine Möglichkeit die funktioniert aber der Code zur Prüfung ist sehr lang.
und das mit der obejektorientierten Lösung haben wir noch nicht gelernt haen erst dieses jahr mit Java begonnen...

public boolean zug(int xKoord,int yKoord) {
if(xKoord==super.getxKoord()-2 && yKoord==super.getyKoord()+1 || xKoord==super.getxKoord()-1 && yKoord==super.getyKoord()+2 ||
xKoord==super.getxKoord()+1 && yKoord==super.getyKoord()+2 || xKoord==super.getxKoord()+2 && yKoord==super.getyKoord()+1 ||
xKoord==super.getxKoord()+2 && yKoord==super.getyKoord()-1 || xKoord==super.getxKoord()+1 && yKoord==super.getyKoord()-2 ||
xKoord==super.getxKoord()-1 && yKoord==super.getyKoord()-2 || xKoord==super.getxKoord()-2 && yKoord==super.getyKoord()-1
){

return super.zug(xKoord, yKoord);

}
 
Hias12345

Hias12345

Mitglied
Ich habe eine Möglichkeit die funktioniert aber der Code zur Prüfung ist sehr lang.
und das mit der obejektorientierten Lösung haben wir noch nicht gelernt haen erst dieses jahr mit Java begonnen...

public boolean zug(int xKoord,int yKoord) {
if(xKoord==super.getxKoord()-2 && yKoord==super.getyKoord()+1 || xKoord==super.getxKoord()-1 && yKoord==super.getyKoord()+2 ||
xKoord==super.getxKoord()+1 && yKoord==super.getyKoord()+2 || xKoord==super.getxKoord()+2 && yKoord==super.getyKoord()+1 ||
xKoord==super.getxKoord()+2 && yKoord==super.getyKoord()-1 || xKoord==super.getxKoord()+1 && yKoord==super.getyKoord()-2 ||
xKoord==super.getxKoord()-1 && yKoord==super.getyKoord()-2 || xKoord==super.getxKoord()-2 && yKoord==super.getyKoord()-1
){

return super.zug(xKoord, yKoord);

}
Hier hab ich einfach der Reihe nach die möglichen Felder abgearbeitet..
 
mihe7

mihe7

Top Contributor
Das ist durchaus eine Möglichkeit. Eine andere wäre, sich zu überlegen, dass
  1. sich das Zielfeld in einer anderen Zeile UND einer anderen Spalte als der Springer befinden muss UND
  2. das Zielfeld drei Felder weit von der Figur entfernt ist (2 in eine Richtung + 1 in die andere Richtung).
Dann wird der Spaß übersichtlicher.
 
Hias12345

Hias12345

Mitglied
Das ist durchaus eine Möglichkeit. Eine andere wäre, sich zu überlegen, dass
  1. sich das Zielfeld in einer anderen Zeile UND einer anderen Spalte als der Springer befinden muss UND
  2. das Zielfeld drei Felder weit von der Figur entfernt ist (2 in eine Richtung + 1 in die andere Richtung).
Dann wird der Spaß übersichtlicher.
Danke
 
W

White_Fox

Top Contributor
Ich konnte es einfach nicht lassen...

Java:
//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){
        //...
    }
}
 
mrBrown

mrBrown

Super-Moderator
Mitarbeiter
Java:
    public void moveToNorth(){
        row.increment();
    }
   
    public void moveToSouth(){
        row.decrement();
    }
   
    public void moveToEast(){
        column.increment();
    }
   
    public void moveToWest(){
        column.decrement();
    }
Die moveTo-Methoden sehen falsch aus, row und column sind ja unveränderlich und den Rückgabewert von increment/decrement ignorierst du aktuell :)
 
W

White_Fox

Top Contributor
Die moveTo-Methoden sehen falsch aus, row und column sind ja unveränderlich und den Rückgabewert von increment/decrement ignorierst du aktuell :)
Stimmt, und die Erstellung der Läuferpositionen ist auch noch fehlerhaft. Wenn die Schleife aus dem Spielfeld läuft kommt sie zwar wieder auf der anderen Seite rein, aber nicht dort wo man sie haben will.

Ich habs mal angepasst:

Java:
//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 = row.increment();
    }
    
    public void moveToSouth(){
        row = row.decrement();
    }
    
    public void moveToEast(){
        column = column.increment();
    }
    
    public void moveToWest(){
        column = column.decrement();
    }
    
    public Position clone(){
        return new Position(row, column);
    }
    
    public boolean isBorderPosition(){
        return row == Row.1 ||
                row == Row.8 ||
                column == Column.A ||
                column == Column.H;
}

//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 Bishop 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 Bishop extends ChessPiece{
    
    public Bishop(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.
        while(p.isBorderPosition){                        //Die Schleife läuft solange, bis 'p' die Spielfeldgrenze erreicht.
            p.moveToNorth();                            //Wir ziehen einmal nach Norden...
            p.moveToWest();                                //...und einmal nach Westen, sodaß wir auf einem diagonal benachbarten Feld stehen...
            possiblePositions.add(p.clone());            //...dann kopieren wir diese Position als mögliche Position in das HashSet.
        }                                                //Damit ist die Nord-West-Diagonale abgefahren.
        
        p = myPosition().clone();                        //p wieder auf die eigene Positin zurück...
        while(p.isBorderPosition){                        //...und die Nord-Ost-Diagonale abfahren.
            p.moveToNorth();
            p.moveToEast();
            possiblePositions.add(p.clone());
        }

        p = myPosition().clone();                        //p wieder auf die eigene Positin zurück...
        while(p.isBorderPosition){                        //...und die Süd-West-Diagonale abfahren.
            p.moveToSouth();
            p.moveToWest();
            possiblePositions.add(p.clone());
        }
        
        p = myPosition().clone();                        //p wieder auf die eigene Positin zurück...
        while(p.isBorderPosition){                        //...und die Süd-Ost-Diagonale abfahren.
            p.moveToSouth();
            p.moveToEast();
            possiblePositions.add(p.clone());
        }
        
        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 bishopsStartposition = 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. bishopsStartposition und anotherPosition sind
                                                                    //Instanzen der Klasse Position.
                                                                    
    Bishop myBishop = new Bishop(bishopsStartposition);                //Und da ist er, unser erster Läufer.
    Bishop yourBishop = new Bishop(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(myBishop.getPossiblePositions.contains(anyPosition){
        //...
    }
}
 
H

httpdigest

Top Contributor
Ganz ehrlich? Ich will wirklich nicht meckern, aber sowas kommt dabei raus, wenn Leute versuchen, etwas OO-style zu lösen. :)
Warum um alles in der Welt sollte man Positionen als Enum-Literale abbilden? Das macht die Rechnerei damit nur unfassbar schwer.
Die Bezeichnung B3 oder H2 ist einzig und alleine für den User bei I/O auf der Kommandzeile oder auf einer UI interessant. Niemand würde eine solche Repräsentation intern als Koordinaten wählen... du musst ja ständig hinundherrechnen Enum->int->Enum bzw. Enum-Instanzmethoden bereitstellen.
Zumal glaube ich auch nicht, dass die eigentliche Aufgabenstellung _nur_ darauf beschränkt war, zu sagen, ob eine Schachfigur zu einem Feld laufen kann, wenn sie die einzige Figur auf dem Schachbrett ist. Da geht es ganz bestimmt auch noch darum, zu prüfen, ob auf seinem Weg nicht noch andere Figuren (der eigenen Farbe oder des Gegners stehen).

Aber, wenn es wirklich nur darum geht, herauszufinden, ob die Arithmetik von aktueller Position und Zielposition stimmt, warum dann nicht einfach:
Java:
abstract class Chesspiece {
  protected final int x, y;
  protected Chesspiece(int x, int y) {
    this.x = x;
    this.y = y;
  }
  public boolean canMoveTo(int x, int y) {
    return x >= 0 && y >= 0 && x < 8 && y < 8;
  }
}
class Bishop extends Chesspiece {
  public Bishop(int x, int y) {
    super(x, y);
  }
  @Override
  public boolean canMoveTo(int x, int y) {
    return super.canMoveTo(x, y) && Math.abs(y - this.y) == Math.abs(x - this.x);
  }
}
Ich muss doch nicht ernsthaft erstmal alle Positionen als Objekte konstruieren und dann prüfen, ob meine Zielposition in der Liste drin ist.
Mit ein ganz klein bisschen Nachdenken, kann man jedes Problem elegant lösen.
 
Zuletzt bearbeitet:
W

White_Fox

Top Contributor
Warum um alles in der Welt sollte man Positionen als Enum-Literale abbilden?
Mir gefällt so etwas wie Position(C, 1) im Code recht gut, allein schon weil man allein aufgrund der Werte sieht um was es geht (ok, ich will nicht übertreiben, man sollte schon noch wissen daß der Code zu einem Schachspiel gehört). Klar kannst du mit Integern herummachen, aber was machst du damit besser? Ob x oder y jetzt Zeile oder Spalte sind, sehe ich daraus auch nicht. Überläufe mußt du ebenso abfangen.
Und wenn du jedem Enum ein Integer zuordnest mußt du auf Positionsberechnung ja nicht verzichten.

Die Bezeichnung B3 oder H2 ist einzig und alleine für den User bei I/O auf der Kommandzeile oder auf einer UI interessant.
Ich würde eher sagen, das kommt darauf an was man später haben will. Die einfache Konvertierung von programmcodeinterner Darstellung nach üblicher Konvention würde ich mir jedenfalls nicht ohne Not verbauen wollen - auch wenn ich dafür zwei relativ übersichtliche Enumklassen schreiben muß, das ist ein akzeptabler Preis. Finde ich jedenfalls.

Ich will allerdings nicht behaupten, daß mein Ansatz der Einzige oder Beste wäre, und es ging mir ja auch nicht darum, ein Schachspiel zu implementieren. Dann würde ich so etwas auch nicht in 30min runterrotzen, sondern mir etwas mehr Zeit nehmen. Dann würde ich die Klasse Position lieber von einer Factory instanzieren lassen, wobei jedes Positionsobjekt nur einmal existieren darf. Damit z.B. eine Klasse Chessboard diese alle überwachen kann. Wahrscheinlich würde ich auch noch ein oder zwei andere Dinge anders machen. Oder vielleicht würde ich einfach alles komplett anders machen...wer weiß.

Aber wenn der TS etwas daraus mitgenommen hat, dann hat mein Codefetzen da oben alles erreicht was er je erreichen sollte.
 
H

httpdigest

Top Contributor
Du hast ja Recht. :)
Ich schätze, wenn man alle möglichen Stile/Paradigmen gesehen hat und sowieso viel von dem persönlichen Geschmack abhängt, dann bin ich wohl bei der Metrik "Besser = weniger Code" (gemäss dem Motto "der beste Code ist der, den man nicht schreibt") stehengeblieben, was sicherlich auch nicht richtig ist (z.B. "weniger Code" bedeutet häufiger ja auch: schlechter lesbar).
 
kneitzel

kneitzel

Top Contributor
Also ich kann der Idee mit dem Enums auch nicht wirklich folgen. Wenn Du diese Enumerations dann wirklich nutzen würdest im Code....

Aber wo tauchen die im Code auf? Du könntest die Initialisierung damit machen. Und dann evtl. die Erkennung des Randfeldes, welches ein Bauer erreichen kann zur Umwandlung ... Aber sonst? Wo tauchen diese enum Elemente wirklich auf? Du hast diese in Variablen und wenn Du damit etwas machen willst, dann wird es immer eine Umwandlung in den hinterlegten int um dann nach der Berechnung es wieder zurück zu wandeln.... Daher würde ich aus Gründen von KISS eben genau darauf verzichten ... (Aber evtl. hast Du ja noch weitere Usecases im Blick die ich bei einem Schach Programm eben nicht sehe.)

Und die Idee mit 1, 2, 3, ... als identifier? Die einzelnen Elemente müssen identifier sein und da gibt es klare Regeln in JLS 3.8 ...
 
W

White_Fox

Top Contributor
Also ich kann der Idee mit dem Enums auch nicht wirklich folgen. Wenn Du diese Enumerations dann wirklich nutzen würdest im Code....
Ey Leute, hätte ich mal vorher geahnt daß das soviel Resonanz hervorruft hätte ich mir mehr Mühe gegeben.

Aber dennoch:
Die Ausgangsfrage war ja, wie man feststellen kann ob ein Läufer auf einer bestimmten Position steht - da hab ich angefangen. Dafür muß ja aber erstmal damit anfangen, 'Position' näher zu definieren.
Ich benutze Enums sehr gerne, um eine endliche Anzahl von Varianten einer Art von Etwas zu beschreiben. Ich schätze die Codelesbarkeit, die das mit sich bringt, und ich bin ein großer Freund davon, Enums auch andere Eigenschaften (wie in diesem Fall z.B. eine Ordnungszahl von 1-8) mitzugeben. In meinem jCLS-Projekt (das heute übrigens zum ersten Mal einen vollständigen "Arbeitszyklus", also Daten definieren - kompilieren - exportieren, erfolgreich gemeistert hat, allmählich kommt es ins pre-alpha-Stadium komm :) ) benutze ich Enums z.B. um Dateitypen zu unterscheiden. Ein Enum FileType.LIBRARY weist auf eine Datei hin in der eine Bibliothek gespeichert wird, und das Enum liefert auch die zugehörige Dateiendung (in diesem Fall .jCLSlib).
Von daher lag es, zumindest aus meiner Sicht, einfach nahe jeder Spalte/Zeile eine Enumeration zuzuordnen.

Wenn Du diese Enumerations dann wirklich nutzen würdest im Code....
Na, aber das tu ich doch. Sieh doch wie 'Position' erzeugt wird. Und ohne ein Positionsobjekt stellst du keine Figur hin. Und das felderweise verrücken wird letztlich ja auch vom Enum besorgt, auch wenn das durch die Positionsklasse verdeckt wird. Inkonsequent war ich bei der Methode isBorderPosition() in der Positionklasse, das hätte auch nochmal an die Enums weiterdelegiert werden müssen.
Und der ChessPiecekonstruktor muß auch nicht unbedingt ein Positoinobjekt bekommen...die zwei Enums könnte man ihm auch zum Fraß vorwerfen.


Wieso schreibe ich hier eigentlich so viel...ausgerechnet ich, der vom Programmieren keine Ahnung hat. Daher mein Vorschlag: Eröffne jemand bitte ein Repository auf gitlab oder sonst wo, und dann möchte ich sehen wie Profis das Problem lösen. Ich lerne ja auch gerne dazu. :)
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
T Springer Problem - Schach Java Basics - Anfänger-Themen 4
G Schach -Frage 2- Maussteuerung Java Basics - Anfänger-Themen 7
G Schach in Java - Allgemeine Frage zur Architektur Java Basics - Anfänger-Themen 7
S Schach Frontend programmieren Java Basics - Anfänger-Themen 2
I Backtracking Schach Java Basics - Anfänger-Themen 5
E Schach in Java-Applet <No main classes found> Java Basics - Anfänger-Themen 5
C Schach(matt) setzen Java Basics - Anfänger-Themen 13
O Schach programmieren mit java Java Basics - Anfänger-Themen 4
I Springer auf Schachbrett Java Basics - Anfänger-Themen 18
F JAVA Springer-Tour Java Basics - Anfänger-Themen 6
J Schachzüge vom Springer berechnen Java Basics - Anfänger-Themen 7
K Springer-Problem Java Basics - Anfänger-Themen 14
M Kann mir jemand hier die Logik vermitteln? Java Basics - Anfänger-Themen 3
M Kann mir jemand die Logik erklären? Java Basics - Anfänger-Themen 1
C Array-Werte werden gemischt, ohne Logik Java Basics - Anfänger-Themen 2
R Best Practice Logik in der Datenbank oder in Java? Java Basics - Anfänger-Themen 3
B Logik Upgrade / Downgrade Java Basics - Anfänger-Themen 13
I Hilfe bei der Logik Java Basics - Anfänger-Themen 9
A Minesweeper Logik Java Basics - Anfänger-Themen 10
D Logik von GUI trennen Java Basics - Anfänger-Themen 3
Meeresgott OOP Gui, Logik und Datenbank richtig aufbauen Java Basics - Anfänger-Themen 43
V Memory Logik Problem/Denkblockade, bitte helft Java Basics - Anfänger-Themen 1
Z Jump and Run - Grafik,Logik und GUI trennen Java Basics - Anfänger-Themen 4
P fibonacci - do while Statement Logik Fehler Java Basics - Anfänger-Themen 5
Z GUI und Logik - Trennung Java Basics - Anfänger-Themen 2
H Logik Frage Java Basics - Anfänger-Themen 3
X Methoden Logik-Problem mit Schleifen. Java Basics - Anfänger-Themen 7
kaoZ Logik und Gui trennen Java Basics - Anfänger-Themen 3
S Logik knobeln... Java Basics - Anfänger-Themen 4
G Klassen Von Logik auf TextField in der GUI zugreifen Java Basics - Anfänger-Themen 14
V Verstehe die Logik nicht ... Java Basics - Anfänger-Themen 30
S OOP Trennung der GUI von der Logik Java Basics - Anfänger-Themen 11
F While Schleife - Logik ? Java Basics - Anfänger-Themen 5
B Logik von verschachtelten For Schleifen Java Basics - Anfänger-Themen 6
Luk10 Logik/Mathe Problem Java Basics - Anfänger-Themen 6
M Logik in Java Java Basics - Anfänger-Themen 4
K java.util.ConcurrentModificationException problem in der Logik? Quaxli-Tutorial Java Basics - Anfänger-Themen 9
S Frage zu Verständnis und Logik Java Basics - Anfänger-Themen 5
K Logik in if-Bedingung Java Basics - Anfänger-Themen 2
L Wie Trennung von Logik und Ausgabe? Java Basics - Anfänger-Themen 6
T Hilfe - Ein Logik Problem Java Basics - Anfänger-Themen 17
sliwalker Wie löse ich eine "DfB-Pokalauslosung"?Logik fehlt Java Basics - Anfänger-Themen 5
T Problem mit der Logik von Switch und do-while Java Basics - Anfänger-Themen 3
G die Logik für eine Buchung! Java Basics - Anfänger-Themen 3

Ähnliche Java Themen

Anzeige

Neue Themen


Oben