Einzelnen Beitrag anzeigen

Benutzerbild von JasonDX
JasonDX
(CodeLib-Manager)

Registriert seit: 5. Aug 2004
Ort: München
1.062 Beiträge
 
#14

Re: Schach: Überprüfung, ob Zug erlaubt

  Alt 5. Jun 2005, 19:34
Sry, dasses jetzt so lang gedauert hat, das zu schreiben, aber ich lieg (vom Schulischen her) eher im Stress

Hier mal die Erklärung ca. in Worten, ich hoffe sie ist verständlich, ansonsten könnt ihr Fragen soviel ihr wollt

Die Richtung
Vorab: hier kanns hilfreich sein, in den Anhang zu schaun, womit ihr vielleicht auch den Grund für die bunte Farbmischung erkennt
Wenn sich eine Figur bewegt, bewegt sie sich in eine bestimmte Richtung und um eine bestimmte Anzahl Felder.
Jede Figur kann sich nur in eine bestimmte Richtung bewegen. Liegt das Ziel in einer anderen Richtung, darf sich die Figur nicht dorthin bewegen.
Sehen wir uns das Schachbrett von oben an und betrachten mal den Turm in der Mitte des Feldes:
Er kann nach rechts, oben, links und unten gehen.
Um das etwas mathematischer auszudrücken: Er kann sich in die Richtungen 0°, 90°, 180° und 270° bewegen.
Betrachten wir nun den Läufer: Er kann sich nur Diagonal bewegen. Das wiederum in Winkel ausgedrückt: 45°, 135°, 225° und 315°.
Beim Springer wirds etwas komplizierter:
Dieser kann in 8 Richtungen laufen:
  • 2 Rechts, 1 Hoch
  • 2 Oben, 1 Rechts
  • 2 Oben, 1 Links
  • 2 Links, 1 Oben
  • 2 Links, 1 Unten
  • 2 Unten, 1 Links
  • 2 Unten, 1 Rechts
  • 2 Rechts, 1 Unten
Wenn man ein bisschen arcSin und Pythagoras rechnet, kriegt man folgende Winkel (gerundet):
26°, 64°, 116°, 154°, 206°, 244°, 296° und 334° (wenn ich mich nicht ganz verrechnet hab )
Wenn wir mal (wie immer) den Bauern außer acht lassen, ist in jedem Quadranten so ziemlich das selbe. (Wie man im Anhang vielleicht erkennen kann.)
Damit wir die Überprüfung nicht für alle Quadranten machen müssen, beschränken wir uns auf den ersten.
Soll heißen: Wir wandeln z.B. alle Winkel des Läufers in den Winkel des ersten Quadranten um. Der Winkel des Läufers im ersten Quadranten ist 45°. D.h. für uns gilt 45° = 135° = 225° = 315. Das selbe mit den Graden des Turms.
Beim Springer müssen wir wieder schaun. Bei Läufer und Turm haben wir 4 Winkel. Beim Springer haben wir 8. Volkschul-EinMalEins: 2*4=8. Der Springer hat also doppelt so viele Möglichkeiten zu laufen wie andere Figueren. Wenn wir jeweils die richtigen Richtungen raussuchen, können wir folgendes für den Springer aufstellen:
26° = 116° = 206° = 296° und
64° = 154° = 244° = 334°
(modulo 90 dürfte hier eine Bedeutung haben )
So, jetzt haben wir mal die verschiedenen Winkel. Was können wir damit machen? Damit können wir mal die Bewegung einschränken, die die Figuren machen dürfen.
Dafür müssen wir dann logisch auch schaun, welchem Winkel unser Winkel ca. entspricht. (Die Richtung (=Winkel), in die sich die Figur bewegt kriegt man leicht mit Pythagoras & co. raus)
Diese Richtung muss einer der Richtungen für die Figuren entsprechen. Wenn nicht, ist der Zug automatisch nicht erlaubt.
Nun gehen wir ein bisschen in die Richtung des Quellcodes:
Wir definieren uns ein set für Richtungen.
Eins für den Turm, eins für den Läufer, und eins für den Springer. Warum keins für Dame und König? Für uns sind die ne Mischung aus Turm und Läufer Und der Bauer ist sowieso unser globaler Außenseiter
Dadurch kommen wir auf das TChessDirection = (cdRook, cdKnight1, Knight2, cdBishop, cdNone);
Nebenbei zur Erklärung: Rook = Turm; Knight = Springer; Bishop = Läufer. None? Diese Richtung brauchen wir um zu sagen, dass es sich um eine ungültige Richtung handelt, also um eine, in die sich keine Figur bewegen darf.
Wie wir sehen können, brauchen wir für unsren Springer zwei Richtungen. In der Zeichnung Lila und Blau
Deshalb kommen wir dann auch auf folgendes:
Delphi-Quellcode:
const
  PossibleDirections: array[TChessFigures] of TChessDirections =
      ([], //Pawn - Ausnahme
       [cfRook], //Rook
       [cfKnight1, cfKnight2], //Knight
       [cfBishop], //Bishop
       [cfRook, cfBishop], //Queen
       [cfRook, cfBishop]); //King
Damit legen wir fest, wer wohinlaufen darf. Der Turm darf nur in Richtung des Turm laufens, der Springer in die 2 Richtungen des Springers, und der Läufer in die des Läufers. Dame und König sind wie gesagt eine Mischung aus Turm und Läufer.

Damit wir aber noch wissen, welche Richtung das jetzt ist, in die sich die Figur bewegen will, muss unser Programm auch wissen, welche Richtung jetzt welcher Winkel ist. Deshalb brauchen wir die Konstante: DirectionAngles: array[TChessDirection] of integer = (463, 463, 1107, 785, 21351);
Warum sind das jetzt nicht die Werte, die wir oben gesehenhaben? Diese werte sind erstens in Radiant gemessen. Warum? sinus und seine Freunde ham das lieber . Bloß schaun die Werte auch nicht danach aus. Nachdem mir reals ect. beim vergleichen und bez. Genauigkeit manchmal Sorgen bereiten, sind die Werte mit 1000 multipliziert. d.h. die Ursprünglichen Werte für die Konstante wären (0.463, 0.463, 1.107, 0.785, 21.351) gewesen. Da fällt aber auch gleich was auf: ein Radiantenwinkel von >21?? das ist unsre none-Direction, ein bloßer Wert, der nie bei einer errechneten Richtung auftreten kann.
Wenn oben bei den PossibleDirections irgendwo ein cdNone stehen würde, könnte diese Figur in alle Richtungen laufen, in die sonst keine der anderen Figuren laufen kann.
In der Funktion, die uns zurückgibt, in welche Richtung grad gelaufen wird, wird dann nach der reihe überprüft: Ist die Richtung die des Turms? oder die des Läufers? Oder passt sie zum Springer? Wenn sie zu keinem der Richtungen gehört, ist sie cdNone.
Wenn wir die Richtung haben, schauen wir, ob die Figur auch in die Richtung laufen darf. Das steht in den PossibleDirections und kann einfach mit dem in-Operator überprüft werden.


Entfernung
Nachdem wir jetzt durch die Richtung, in die sich eine Figur bewegen kann, bereits die meisten Bewegungen einschränken können, fehlt doch noch was. z.B. kann unser König noch gleich laufen wie die Dame. Oder wenn jemand den Quellcode ohne Distances probiert, kann mit dem Springer auch 2 nach links und 4 nach oben gehen, und keiner sagt er dürfe nicht.
Deshalb müssen wir eine zweite einschränkung einführen: Manche Figuren können nicht 100km laufen, bei denen is nach ein paar Feldern die Batterie leer.
Diese Einschränkung kriegen wir, wenn wir noch für jede Figur eine Streckenbegrenzung einführen. Das ist in MaxDistances deklariert. Da haben wir aber auch 15 stehen - Welche Figur kann 15 Felder laufen? So gesehen: keine. Aber wir müssen auch bedenken, dass Diagonal die Felder etwas länger sind (zumindest vom Aspekt der Geometrie her). Hier ist die Hauptsache: Für Figuren, die übers ganze Spielfeld laufen können, den Wert einfach nur groß genug wählen. Wichtig ist der Wert beim Springer und beim König. Wenn wir genau hinschauen: der Springer kann eigentlich genau entlang eines Kreises hinlaufen. Der Kreis hat ca. einen Radius von knapp kleiner als 2.3. Also sagen wir: Der springer darf nicht weiter als 2.3 Felder laufen. Nachdem im weiter oben genannten Beispiel der Zug um 2 Felder nach links und 4 nach oben etwas weiter weg ist, darf der Springer das nun auch nicht mehr. Der König bekommt noch eine engere Beschränkung. Weil seine Krone und der Apfel so schwer sind, kann er max. 1.5 Felder laufen. Dies reicht knapp aus, dass er auf ein Diagonales Feld laufen kann, was ca. 1.41 Felder weit weg ist. Wir könnten die Begrenzung auch auf 1.9 Felder legen, die Hauptsache ist, dass sie < 2 ist, da er ansonsten Horrizontal oder vertikal 2 Felder laufen könnt. Und das darf er einfach nich.
Der Bauer ist nach wie vor noch ein armes Schwein, der darf noch gar nix machen. Ich werd mir aber auch über den Gedanken machen, und wenn mir was einfällt, schreib ichs hier


Ich hoff, das war etwas verständlicher, aber mein Info-Lehrer hat auch irgendwie schon bemerkt, dass ich mein Erklären so manche Probleme habe



@mr47: ich hab dein Prinzip knapp falsch verstanden (ich dachte bspw. du machst das alle möglichen felder, nicht nur die maximalen )
Mike
Passion is no replacement for reason
  Mit Zitat antworten Zitat