Schachfiguren Zug korrigieren

Degget

Mitglied
Hallo,
wir sollen ein kleines Spiel programmieren, bei dem mit Schachfiguren über ein Schachbrett gezogen werden muss. Die Angabe des Zugs erfolgt allerdings nicht normal mit "von E 6 auf A 2" sondern mit einer Richtungsangabe im Sinne von "/" (nach rechts oben oder links unten) und einer Reichweite (-int würde nach links unten, +int nach rechts oben ziehen). Eine Methode soll Züge, die außerhalb des Schachbretts führen würden korrigieren, indem sie die Figur auf das im Zug letztmöglich Feld setzt.
Nun mein Problem:
Die Methode für vertikale/horizontale Züge ist recht einfach umzusetzen. Allerdings finde ich keinen Weg, es für diagonale Züge zu implementieren. Habt ihr Anregungen?

Mal die Zug-Methode der Dame und der Anfang der Korrigierungsmethode:

Java:
private String[] möglicheRichtungen = {"/", "\\", "-", "|"};

Java:
	public void ziehe(String richtung, int weite, Spielfeld brett)
	{
		boolean inputOk = false;
		int auswahl = 10;
		for(int i = 0; i < möglicheRichtungen.length; i++)
			if(möglicheRichtungen[i].equals(richtung))
			{
				inputOk = true;
				auswahl = i;
			}
		if(inputOk)
		{
			switch(auswahl)
			{
				case 0: 
					setxPosition(getxPosition() +  weite);
					setyPosition(getyPosition() + weite);
					break;
				case 1:
					setxPosition(getxPosition() - weite);
					setyPosition(getyPosition() + weite);
					break;
				case 2:
					setxPosition(getxPosition() + weite);
					korrigiere(brett, true, false, false);
					break;
				case 3: 
					setyPosition(getyPosition() + weite);
					korrigiere(brett, false, true, false);
					break;
				default:
					System.out.println("Zug nicht moeglich!");
					break;
			}
		} 
		else
		{
			System.out.println("Zug nicht moeglich!");
		}

Java:
	public void korrigiere(Spielfeld brett, boolean horizontal, boolean vertikal,
												 boolean diagonal)
	{
		if(horizontal)
		{
			while(getxPosition() < 0)
				setxPosition(getxPosition() + 1);
			while(getxPosition() > brett.getZeilen())
				setxPosition(getxPosition() - 1);
		}
		if(vertikal)
		{
			while(getyPosition() < 0)
				setyPosition(getyPosition() + 1);
			while(getyPosition() > brett.getSpalten())
				setyPosition(getyPosition() - 1);
		}
		
	}

Ist mein Ansatz so überhaupt sinnvoll oder kann das nur gegen den Baum laufen?
 

AlexSpritze

Bekanntes Mitglied
Wenn ich das richtig verstanden habe, prüfst du, nachdem ein Zug vollendet worden ist, ob er gültig (= immernoch auf dem Schachbrett) ist.
Vielleicht könntest du eine Methode prüfen schreiben, die schaut ob ein Zug gültig ist und nur wenn das der Fall ist, wird er auch ausgeführt, vielleicht mit einer Methode setze.
 

Degget

Mitglied
Ich glaube ich wüsste, wie ich so eine setze-Methode umsetzen könnten. Das Problem ist halt, dass wir diese korrigieren-Methode einbringen sollen. Also ich weiß quasi, wie man prüft, ob ein Zug gültig ist. Ich weiß allerdings nicht, wie ich einen Zug automatisch korrigieren kann.

Als Beispiel:

Ich erzeuge das ein Schachbrett(3, 3) und setze Meine Dame auf (3, 2)

0 D 0
0 0 0
0 0 0

nun sage ich: \, -3

Meine Dame wäre dann bei

1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 0 0 0 1 1
1 1 0 0 0 1 1
1 1 0 0 0 1 1
1 1 1 1 1 1 D
1 1 1 1 1 1 1

(außerhalb des Felds also)

sollte allerdings bei

0 0 0
0 0 D
0 0 0

stehen. Also auf dem letzten Feld, das in diesem Zug möglich wäre.
Der Benutzer soll halt nicht "Zug nicht möglich" kriegen und nochmal neu eingeben, sondern "Zug wird automatisch korrigiert, Dame zieht auf XX" bekommen.
Da bei einem diagonalen Zug allerdings beinahe überall hingezogen werden kann, weiß ich nicht wirklich, wie man das umsetzen könnte.
 

Marco13

Top Contributor
Wie AlexSpritze schon sagte: Im Moment bewegst du die Figur auf das ungültige Feld, und dann so lange schrittweise zurück, bis das Feld gültig ist. Besser wäre es, vorher auszurechnen, welches das letzte gültige Feld ist, und gleich nur dort hinzuziehen.

Aber aufbauend auf deiner "koorigiere"-Methode: Man kann in einer Schleife oder if-Abfrage auch mehrere Kriterien überprüfen
Code:
        if(diagonal)
        {
            while(getyPosition() < 0 || getxPosition() < 0) // Solange das eine oder andere gilt...
            ...
Beachte, dass man da im schlimmsten Fall 4 Fälle unterscheiden muss ( /, \, jeweils mit + und -). Wenn man das vorher prüfen würde, könnte man das allgemein etwas eleganter machen, aber vielleicht willst du es ja erstmal so versuchen...
 

Degget

Mitglied
Das mit den vielen While-Schleifen war echt ne hirnrissige Idee. Hab es jetzt in etwa so gemacht, wie ihr vorgeschlagen habt.
Eine Methode zum Prüfen, ob die Position zulässig ist:
Java:
	public boolean pruefePosition(int zeilen, int spalten)
	{
		return (zeilen > 0 && zeilen < getZeilen() && spalten > 0 && spalten < getSpalten());
	}

Eine Methode, die insofern korrigiert, dass sie die Weite, die gezogen werden soll, abändert:
Java:
	public int korrigiere(int weite, Spielfeld brett)
	{
		int neueWeite = 0;
		if(weite > 0)
		{
			neueWeite = brett.getZeilen() - xPosition;
			if(neueWeite < (brett.getSpalten() - yPosition))
				neueWeite = brett.getSpalten() - yPosition;
		}
		else if(weite < 0)
		{
			neueWeite = xPosition * -1;
			if(neueWeite < (yPosition * -1))
				neueWeite = yPosition * -1;
		}
		else if (weite == 0)
			throw new IllegalArgumentException();
		return neueWeite;
	}

und zum Ende sieht es dann so aus:
Java:
 public void ziehe(int richtung, int weite, Spielfeld brett)
  {
      boolean inputOk = false;
      for(int i = 0; i < möglicheRichtungen.length; i++)
      	if(möglicheRichtungen[i] == richtung)
      		inputOk = true;
      if(inputOk)
      {
          switch(richtung)
          {
              case '/': 
              	if(!brett.pruefePosition(getxPosition() + weite, getyPosition() + weite))
              	{
              		int neueWeite = korrigiere(weite, brett);
                	setxPosition(getxPosition() + neueWeite);
                	setyPosition(getyPosition() + neueWeite);
              	} 
              	else
              	{
                	setxPosition(getxPosition() + weite);
                	setyPosition(getyPosition() + weite);
              	}
              	break;
              case '\\':
              	if(!brett.pruefePosition(getxPosition() + weite, getyPosition() + weite))
              	{
              		int neueWeite = korrigiere(weite, brett);
                	setxPosition(getxPosition() - neueWeite);
                	setyPosition(getyPosition() + neueWeite);
              	} 
              	else
              	{
                 setxPosition(getxPosition() - weite);
                 setyPosition(getyPosition() + weite);
              	}
                  break;
              case '-':
              	if(!brett.pruefePosition(getxPosition() + weite, getyPosition() + weite))
              	{
              		int neueWeite = korrigiere(weite, brett);
                	setxPosition(getxPosition() + neueWeite);
              	} 
              	else
              	{
                  setxPosition(getxPosition() + weite);
              	}
                break;
              case '|': 
              	if(!brett.pruefePosition(getxPosition() + weite, getyPosition() + weite))
              	{
              		int neueWeite = korrigiere(weite, brett);
                	setyPosition(getyPosition() + neueWeite);
              	} 
              	else
              	{
                  setyPosition(getyPosition() + weite);
              	}
                break;
              default:
                  System.out.println("Zug nicht moeglich!");
                  break;
          }
      } 
      else
      {
          System.out.println("Zug nicht moeglich!");
      }

Nun ist die ziehe-Methode ja ein ziemlich langes Teil geworden. Finde ich eigentlich nicht so schön. Fällt euch etwas ein, wie man das noch kürzer fassen könnte?
 

Marco13

Top Contributor
Manche Methoden sind einfach lang, aber meistens (wie auch in diesem Fall) kann man sie auf verschiedenSTe Arten "runterbrechen". In diesem Fall wäre es ja schonmal ganz trivial-brutal möglich, jeden "case" in eine eigene Methoden zu packen:
Java:
          switch(richtung)
          {
              case '/': 
                machAllesFürDiagonal(...);
                break;
              ....
          }
 

// Rausgezogen:
private void machAllesFürDiagonal(...)
{
                if(!brett.pruefePosition(getxPosition() + weite, getyPosition() + weite))
                {
                    int neueWeite = korrigiere(weite, brett);
                    setxPosition(getxPosition() + neueWeite);
                    setyPosition(getyPosition() + neueWeite);
                } 
                else
                {
                    setxPosition(getxPosition() + weite);
                    setyPosition(getyPosition() + weite);
                }
}

Aber in diesem Fall geht das sicher noch deutlich eleganter. Viel könnte man vermutlich schon spraren, wenn man dafür sorgen würde, dass die "korrigiere"-Methode auch selbst die Prüfung macht: Man könnte sie so implementieren, dass sie die übergebene 'weite' zurückgibt, wenn alles in Ordnung ist, und ansonsten eben die kirrigierte, damit man sie GROB so verwenden kann wie
Code:
int neueWeite = korrigiere[b]WennNotwendigUndAnsonstenGibtEinfachDieWeiteWiederZurück[/b](weite, brett);
setxPosition(getxPosition() + neueWeite);
setyPosition(getyPosition() + neueWeite);

Falls es nicht klappt, kann ich bei Gelegenheit nochmal genauer schauen. Irgendwie glaube ich, dass man da nicht sooo viel mehr als 10 Zeilen braucht ;)
 

Degget

Mitglied
Deine Idee ist gut, leider habe ich gerade gemerkt, dass meine korrigiere-Methode einen Fehler hat. Bei der Eingabe von "\\" kann man die Züge ja leider nicht mehr in positive und negative Richtung unterscheiden, wodurch letztendlich Käse rauskommt. Wie könnte man die Methode möglichst einfach umgestalten? Irgendwie steh ich heute ziemlich aufn Schlauch...
 

Marco13

Top Contributor
Versuch' erstmal NICHT, sie "einfach" zu machen. Versuche zuerst, die so zu machen, dass sie funktioniert. So, dass sie für JEDEN Fall das richtige Ergebnis liefert.

Danach kann man weitersehen.


------------- (A tribute to SlaterB ;))


Dannn geht es noch um die Frage, was "einfach" heißt. Heißt das "leicht zu schreiben" oder "leicht nachzuvollziehen", oder "kompakt"?

Die Frage, das positiv und negativ bei den Diagonalen denn nun bedeutet, hatte ich mir auch gestellt, aber das kann man ja "irgendwie festlegen":
'/' positiv: Gehe nach rechts oben
'/' negativ: Gehe nach links unten
'\' positiv: Gehe nach rechts unten
'\' negativ: Gehe nach links oben
(Alternativen wären denkbar)


Wenn man's drauf anlegt, kann man das wirklich ziemlich "kompakt" schreiben. Aber erstmal sollte es funktionieren und nachvollziehbar und verständlich sein.

Sowas hier ist wohl nicht Sinn der Sache... ;)

Java:
class SchachTest
{
    public static void main(String args[])
    {
        SchachTest st = new SchachTest();
        st.print();
        st.ziehe('-',   6);
        st.ziehe('-',  -6);
        st.ziehe('|',   6);
        st.ziehe('|',  -6);
        st.ziehe('/',   6);
        st.ziehe('/',  -6);
        st.ziehe('\\',  6);
        st.ziehe('\\', -6);

        st.ziehe('-',   1);
        st.ziehe('-',  -1);
        st.ziehe('|',   1);
        st.ziehe('|',  -1);
        st.ziehe('/',   1);
        st.ziehe('/',  -1);
        st.ziehe('\\',  1);
        st.ziehe('\\', -1);
    }

    int zeilen = 8;
    int spalten = 8;
    private int xPosition = 3;
    private int yPosition = 2;

    public SchachTest()
    {
    }

    private void print()
    {
        for (int y=0; y<getZeilen(); y++)
        {
            for (int x=0; x<getSpalten(); x++)
            {
                if (x == getxPosition() &&
                    y == getyPosition())
                {
                    System.out.print("X ");
                }
                else
                {
                    System.out.print(". ");
                }
            }
            System.out.println();
        }
    }


    public int getZeilen()  { return zeilen;  }
    public int getSpalten() { return spalten; }
    public int getxPosition() { return xPosition; }
    public int getyPosition() { return yPosition; }
    public void setxPosition(int x) { xPosition = x; }
    public void setyPosition(int y) { yPosition = y; }


    private int berechneWeite(int weite, int dx, int dy)
    {
        int m=Integer.MAX_VALUE;
        m = dx<0?min(m,-dx,getxPosition()):m;
        m = dy<0?min(m,-dy,getyPosition()):m;
        m = dx>0?min(m, dx,getSpalten()-getxPosition()-1):m;
        m = dy>0?min(m, dy,getZeilen() -getyPosition()-1):m;
        return weite<0?-m:m;
    }

    private static int min(int a, int b, int c)
    {
        return Math.min(a, Math.min(b, c));
    }


    public void ziehe(int richtung, int weite)
    {
        System.out.println("");
        System.out.println("  Richtung: "+(char)richtung);
        System.out.println("     Weite: "+weite);
        if (weite != 0)
        {
            switch(richtung)
            {
                case '/' :
                    weite = berechneWeite(weite, weite,-weite);
                    System.out.println("neue Weite: "+weite);
                    //setxPosition(getxPosition()+weite);
                    //setyPosition(getyPosition()-weite);
                    break;

                case '\\':
                    weite = berechneWeite(weite, weite, weite);
                    System.out.println("neue Weite: "+weite);
                    //setxPosition(getxPosition()+weite);
                    //setyPosition(getyPosition()+weite);
                    break;

                case '-' :
                    weite = berechneWeite(weite, weite, 0);
                    System.out.println("neue Weite: "+weite);
                    //setxPosition(getxPosition()+weite);
                    break;

                case '|' :
                    weite = berechneWeite(weite, 0, weite);
                    System.out.println("neue Weite: "+weite);
                    //setyPosition(getyPosition()+weite);
                    break;

                default:
                    System.out.println("Zug nicht moeglich!");

            }
        }
    }
}
 

Marco13

Top Contributor
In diesem Fall ist er eigentlich eher überflüssig, und objekttiv betrachtet ist er da sogar ziemlich blöd:
Code:
m = dx<0?min(m,-dx,getxPosition()):m;
Bedeutet ja sowas wie
Code:
if (dx<0)
{
    m = min(m,-dx,getxPosition())
}
else
{
    [b]m = m;[/b] // Unfug
}

Das diente nur dem Zweck, das kompakter aussehen zu lassen :D :oops:
 

Ähnliche Java Themen


Oben