Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Schach: Überprüfung, ob Zug erlaubt (https://www.delphipraxis.net/46970-schach-ueberpruefung-ob-zug-erlaubt.html)

fkerber 3. Jun 2005 22:53


Schach: Überprüfung, ob Zug erlaubt
 
Hallo!

Ich programmiere gerade ein Schachspiel (Human vs. Human, keine KI)
Wie stelle ich am effizientesten fest, ob ein Zug augeführt werden darf (also die Figur dorthin bewegt werden darf)?
Es geht sicherlich mit einigen If-Abfragen, aber vielleicht gibt es ja da noch was Schöneres?

Ciao und Danke
Frederic

sniper_w 3. Jun 2005 23:08

Re: Schach: Überprüfung, ob Zug erlaubt
 
Es wird dir kaum gelingen, irgendwas ohne if-s zu machen. Und dir weiter zu helfen, könntest du uns etwas von der SchachFieldDefinition ( aka Code ) schicken.

mr47 3. Jun 2005 23:27

Re: Schach: Überprüfung, ob Zug erlaubt
 
Mein Ansatz wäre dass mit einem Koordinatensystem zu machen. Jedes Feld hat zwei Nummern (Also x und y). Dann schreibst du für jede Figurenart eine kleine Liste, was erlaubt ist. Also für das Pferd ist
z.B. y+2 und x+1 oder y+2 und x-1 oder so ähnlich.....

Für den Bauern ist immer nur y+1 erlaubt. Allerdings gibts ja dann die Ausnahme mit dem Schlagen.... Da wäre ja dann x+1 und y+1 auch erlaubt. hm...

mfg mr47

JasonDX 4. Jun 2005 00:01

Re: Schach: Überprüfung, ob Zug erlaubt
 
Eine andere Möglichkeit, die es gäbe, wäre die möglichen Richtungen und Distanzen zu speichern. d.h. "Diese Figur kann in diese und diese Richtung so und so weit laufen".
(nähere Details kriegste, nachdem ich mir das morgen in der Schule nochmal genauer durchdacht hab ;) )

Das if beim Schlagen&Starten mit dem Bauern wirst du allerdings nicht wegkriegen, außer du kommst auf ne ganz tolle idee, die aber ws um einiges komplizierter ist :stupid:

@mr47: Beim aufschreiben der der Möglichkeiten durch X+1&Y+0 musst du über 100 Möglichkeiten aufschreiben (da sind ein paar ifs fast schöner :zwinker: )

Sharky 4. Jun 2005 00:47

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

ich kenne mich in diesem Gebiet zwar nicht aus. Aber eine Überlegung:

Das Feld von 8x8 kannst Du ja auch als Linearesfeld mit 64 feldern abbilden.
Jetzt überlege mal wie z.B. ein "Springer" sich auf diesem "eindimensiomale" Array bewegen kann.

Er kan nur 4 mögliche Felder vor oder 4 mögliche Felder zurück. (wenn ich mich nicht verzählt habe)

Aber das wäre doch ein Ansatz?

JasonDX 4. Jun 2005 08:37

Re: Schach: Überprüfung, ob Zug erlaubt
 
So, eine Stunde Deutsch ist um und hatte somit genug Zeit, über meine Idee nachzudenken :mrgreen:

Kurz eine Erklärung zum Prinzip von Distances und Directions:

Jede Figur kann in bestimmte Richtungen bewegen. Der Turm nur Waag- und Senkrecht, der Läufer nur Diagonal, Königin und König beides; Der Springer nur in einem anderen Winkel, und den Bauern sehn wir mal als Ausnahme.
Damit können wir uns folgendes Set von Richtungen Definieren
Delphi-Quellcode:
  TChessDirection = (cdRook, cdKnight1, Knight2, cdBishop, cdNone);
die None-Direction brauchen wir für den Fall, dass die Richtung keiner Bekannten entspricht, und wir haben 2 Richtungen für den Springer, warum sehen wir später

Um nun angeben zu können, wer wohin laufen kann, brauchen wir ein set of, wo wir dann auch die Richtungen der Figuren bereits definieren können
Delphi-Quellcode:
  TChessDirections = set of TChessDirection;
  TChessFigures = (cfPawn, cfRook, cfKnight, cfBishop, cfQueen, cfKing);
 
const
  PossibleDirections: array[TChessFigures] of TChessDirections =
      ([], //Pawn - Ausnahme
       [cfRook], //Rook
       [cfKnight], //Knight
       [cfBishop], //Bishop
       [cfRook, cfBishop], //Queen
       [cfRook, cfBishop]); //King
Damit das nun langsam Werte werden, die wir brauchen können, definieren wir Konstanten, welche Richtung welchem Winkel entspricht:
Delphi-Quellcode:
const
  DirectionAngles: array[TChessDirection] of integer = (1570, 463, 1107, 785, 21351);
Hier brauchen wir für den Springer eben nur 2 Richtungen, weil er im Bereich von 90° in 2 Richtungen laufen kann. (2 nach oben, 1 links, oder 1 nach oben und 2 links)

Damit wir nun aber das aber auch was bringt, brauchen wir eine Funktion, die uns sagt, welche Richtung das ist.
Delphi-Quellcode:
function GetDirection(Source: TPoint; Destiny: TPoint): TChessDirection;
var
  angle: real;
  i: TChessDirection;
begin
  result := cdNone;
  //Winkel ausrechnen
  angle := arcsin(abs(Source.Y - Destiny.Y) / sqrt(sqr(Source.X - Destiny.X) + sqr(Source.Y - Destiny.Y))) + 4*Pi;
//Hier bin ich mir nicht sicher, ob der folgende Teil stimmt. am ende soll halt folgendes gelten: 0 < angle <= Pi / 2
  while angle > 1.5707 do
    angle := angle - 1.570
  for i := cdRook to cdBishop do
    if trunc(angle * 1000) = DirectionAngles[i] then
      result := i;
end;
Hier wird nun rausgefunden, welche Richtung bewegt wurde. Im fall dass nix passt, ist es cdNone. Dafür brauchen wir das. Wenn nun bei PossibleDirections irgendwo cdNone vorkommt, kann er überall hinbewegen, wo sonst keiner hin kann.

Damit hätten wir mal die Richtungen abgeschlossen.
Nun brauchen wir noch die Distanzen:
Jede Figur hat eine Maximale Reichweite. Der König kann maximal 1 Feld gehen, auch diagonal, also ist die Maximale distanz ca. 1.5, Der Springen kann schon etwas weiter laufen, ca. 2.3, und die restlichen Figuren (Der Bauer ist immernoch die Ausnahme) können auch 15 Felder laufen, wenn nicht das Spielfeld vorher fertig wär ;)
Die Distanzen können wir ganz einfach in einer Konstante speichern:
Delphi-Quellcode:
const
  MaxDistances: array[TChessFigures] of real = (1, 15, 2.3, 15, 15, 1.7);
Ob nun die Bewegung von der Distanz her auch passt, können wir ganz einfach überprüfen:
Delphi-Quellcode:
function GetDistance(Source: TPoint; Destiny: TPoint): real;
begin
  result := sqrt(sqr(Source.X - Destiny.X) + sqr(Source.Y - Destiny.Y));
end;

Mit diesem ganzen Rast können wir nun (bis auf unsre Ausnahme, den Bauern) überprüfen, ob der Zug möglich ist
Delphi-Quellcode:
function IsDirectionPossible(Source: TPoint; Destiny: TPoint; Figure: TChessFigure): boolean;
begin
  result := (GetDirection(Source, Destiny) in PossibleDirections[Figure]) //die Richtung
    and (GetDirection(Source, Destiny) < MaxDistance[Figure]); //und die Entfernung muss passen
end;
Was du noch überprüfen musst ist, ob eine Figur auf dem Zielfeld steht, und v.a. ob sich eine Figur dazwischenbefinden, wofür dir die Directions auch zuhilfe kommen könnten ;)


Die ganzen Quellcodes hab ich nicht probiert, als keine Garantie, dass sie laufen. Das ganze soll eine Anregung sein, wie du sowas machen könntest. Und Fragen dazu kannst du mir jederzeit stellen ;)


[edit=sakura] *wuppdi* Mfg, sakura[/edit]

fkerber 4. Jun 2005 08:42

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

Danke für die vielen Infos, insbesondere die von Mike.
Ich lasse es mir durch den Kopf gehen. Danke.

Ciao Frederic

MarkusB 4. Jun 2005 14:52

Re: Schach: Überprüfung, ob Zug erlaubt
 
Moin fkerber!

Also ehrlich gesagt viel von dem Chimaira Posting habe ich nicht verstanden (mag sein, dass das an meiner begrenzten Vorstellungsmöglichkeiten liegt). Deswegen habe ich versucht eine einfachere Lösung zu finden.

Als Grundlage der ganzen Analyse würde ich das reale Schachbrett nehmen. Das heißt ein Quadrat mit den Abmaßen: A bis H und 1 bis 8. Jede Spielfigur kann sich nur in diesen Grenzen bewegen, also die Definition der Position einer Figur lautet:
Delphi-Quellcode:
  TPosition = record
    letter: (A, B, C, D, E, F, G, H);
    number: 1..8;
  end;
Bei einem Zug sind zwei Positionen gegeben: Start und Ende die abhängig von der Figur unterschiedlich geprüft werden müssen. In Falle eines Springers würde ich folgende Prüfung vorschlagen. Die Funktion CheckSpringer liefert “true” zurück, wenn der Zug gültig ist oder “false” wenn nicht. Natürlich ist das nicht alles was man bei einem Springerzug prüfen muss.

Delphi-Quellcode:
function TForm1.CheckSpringer(Start, Ende: TPosition): boolean;
begin
  // pessimistische Annahme
  CheckSpringer:= false;

  // Bewegung: 1 Feld Rechts bzw. Links und dann 2 Felder Hoch bzw. Runter
  if (
        (Ende.letter = succ(Start.letter))
        or
        (Ende.letter = pred(Start.letter))
     )
     and
     (
        (Ende.number = Start.number + 2)
        or
        (Ende.number = Start.number - 2)
     )
  then CheckSpringer := true;

  // Bewegung: 2 Felder Rechts bzw. Links und 1 Feld Hoch bzw. Runter
  if (
        (Ende.letter = succ(succ(Start.letter)))
        or
        (Ende.letter = pred(pred(Start.letter)))
     )
     and
     (
        (Ende.number = Start.number + 1)
        or
        (Ende.number = Start.number - 1)
     )
  then CheckSpringer := true;
end;
Viele Grüße
Markus
:gruebel:

fkerber 4. Jun 2005 14:58

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

Jepp, ich blicke bei Chimaira auch noch nicht ganz durch, aber ich werde mir das sicherlich noch in Ruhe ansehen.
Dein Vorschlag Markus ist ja das, was ich mit xxx If-Abfragen meine.
Oder ist das doch sinnvoller?

Ciao Frederic

malo 4. Jun 2005 15:25

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

Zitat von fkerber
Oder ist das doch sinnvoller?

Das ist IMHO einfacher ;)

Allerdings sollte man auch noch beachten, dass man prüfen muss, ob eines der Felder bereits besetzt ist, auf die man kommt. Das ist beim Springer recht einfach (man muss nur den Endpunkt überprüfen, ob da jemand steht). Aber bei anderen Figuren muss man rekursiv jedes einzelne Feld überprüfen, ob eine eigene oder eine gegnerische Figur dort steht (für den Anfang reicht, ob überhaupt eine dort steht). ;)

JasonDX 4. Jun 2005 15:40

Re: Schach: Überprüfung, ob Zug erlaubt
 
@MarkusB: Das mit den Springern ginge z.B. einfacher:
Delphi-Quellcode:
function CheckKnight(Start: TPoint; End: TPoint): boolean;
begin
  result := (abs(Start.X - End.X) + abs(Start.Y - End.Y) = 3) and (abs(Start.X - End.X) > 0)
end;
Das ganze basiert darauf, dass der Springer immer 3 Schritte macht, wobei er aber mindestens 1 schritt in eine Richtung machen muss
Man könnte versuchen, alle Figuren so zu kürzen, wär aber auch wieder ein Aufwand.

Zudem würd ich empfehlen, nur mit Zahlen zu rechnen, mit Buchstaben wirds nur chaotischer ;)


Was sinnvoller ist, ifs oder kompliziert... hängt davon ab, was du unter sinnvoll verstehst.
Die If-Methode ist einfach, schnell, lang und "unschön"
Die Distance+Direction-Methode ist kompliziert, lang, aber elegant und dynamisch, v.a. wenn du z.B. einen König haben willst, der wie ein Turm, ein Springer und ein Läufer laufen kann ;)

Wenn du willst, kann ich versuchen, dir eine (halbwegs) verständliche Erklärung zu meiner Lösung zu schreiben

fkerber 4. Jun 2005 23:20

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

Eine Erklärung mit Worten (also weniger als Code) wär echt super!
Danke für deine Mühe.

Ciao Frederic

mr47 4. Jun 2005 23:27

Re: Schach: Überprüfung, ob Zug erlaubt
 
Man braucht nicht über 100. Man braucht für einen Bauern genau eine + Schlagen

y ist die Position auf der y-Achse auf der der Bauer steht.

Zitat:

y+1
Wenn das für die Weißen steine gilt, muss man bei allen Schwarzen nur das Vorzeichen umdrehen. Die sollen ja dann von oben nach unten laufen :wink: also

Zitat:

y-1
Für einen Springer gäbe es dann 4 Möglichkeiten:

Zitat:

y+1 & x+1
y+1 & x-1
y-1 & x-1
y-1 & x+1
und dann halt immer noch prüfen: wenn y=maximum then y+1 nicht möglich wenn y=minimum then y-1 nicht möglich

Aber das von Chamiara sieht professioneller aus :wink:


mfg

edit 1+2+3: Die kleinen Fehler die niemand merkt hab ich entfernt :wink:

JasonDX 5. Jun 2005 19:34

Re: Schach: Überprüfung, ob Zug erlaubt
 
Sry, dasses jetzt so lang gedauert hat, das zu schreiben, aber ich lieg (vom Schulischen her) eher im Stress :kotz:

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 :stupid:
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 :wall:



@mr47: ich hab dein Prinzip knapp falsch verstanden ;) (ich dachte bspw. du machst das alle möglichen felder, nicht nur die maximalen :oops: )

fkerber 5. Jun 2005 19:41

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

Danke für die weitreichende Erklärung.
War bestimmt etwas Arbeit.

Ciao Frederic

alzaimar 6. Jun 2005 13:43

Re: Schach: Überprüfung, ob Zug erlaubt
 
Versuch doch auch mal Folgendes;
Es gibt ja für die Figuren verschiedene Zugmöglichkeiten, also z.B:
Delphi-Quellcode:
Const
ccXfwd : Array [0..7] Of TPoint= ( (1,0),.... ( 8,0) );
ccXbwd : Array [0..7] Of TPoint= ( (-1,0),.... (-8,0) );
ccYfwd : Array [0..7] Of TPoint ( (0,1) .... (0,8) );
ccYbwd : Array [0..7] Of TPoint ( (0,-1) .... (0,-8) );
ccKnight : Array [0..7] Of TPoint = ( (2,1),(1,2),(-1,2),(-2,1),(1,-2),(2,-1), (-2,-1), (-1,-2));

// Das gleiche noch für die Diagonalen (ccUL, ccDL, ccUR, ccDR für Up/Down Left/Right);

Procedure CheckMove (aFigur : TSchachFigur; aPosition : TPoint; aBrett : TSchachBrett);
Begin
  Case aFigure of
    Springer : CheckIt (aPosition, ccKnight, False );
    Turm : Begin    
      Checkit (aPosition, ccXfwd, True);
      Checkit (aPosition, ccXbwd, True);
      Checkit (aPosition, ccYfwd, True);
      Checkit (aPosition, ccYbwd, True);
      End;
    Dame : Begin
      Checkit (aPosition, ccXfwd, True);
      Checkit (aPosition, ccXbwd, True);
      Checkit (aPosition, ccYfwd, True);
      Checkit (aPosition, ccYbwd, True);
      Checkit (aPosition, ccUL, True);
      Checkit (aPosition, ccUR, True);
      Checkit (aPosition, ccDL, True);
      Checkit (aPosition, ccDR, True);
      End;
    Läufer : Begin ... nur die ccUL,ccUR,ccDL,ccDR etc. End;
...
End;
Damit erschlägst Du alles, bis auf en-passant und die Rochade. Da muss man ja extra testen.
Das CheckIt ist auch simpel, indem es zu der aPosition alle Elemente der Zugliste addiert. Der zweite (Bool-) Parameter gibt an, ob der Weg bis zur Zielposition frei sein muss, oder nicht. Der Turm kann z.B. nicht 5 Felder nach rechts, wenn auf dem 3.Feld jemand steht. Beim Springer findet dieser Check nicht statt.

Mit dem Verfahren erstellst Du auch eine Liste aller legalen Züge.

Cöster 31. Jul 2006 16:10

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

Zitat von JasonDX
Delphi-Quellcode:
const
  DirectionAngles: array[TChessDirection] of integer = (463, 463, 1107, 785, 21351);

Ich hab's nicht geprüft, aber müsste die erste Zahl statt 463 nicht 1570 sein? Sie bezieht sich doch auf den Turm.
Noch ne Frage:
Die 21351 könnte doch eigentlich jede Zahl >=1571 sein, oder?

JasonDX 31. Jul 2006 16:33

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

Zitat von Cöster
Zitat:

Zitat von JasonDX
Delphi-Quellcode:
const
  DirectionAngles: array[TChessDirection] of integer = (463, 463, 1107, 785, 21351);

Ich hab's nicht geprüft, aber müsste die erste Zahl statt 463 nicht 1570 sein? Sie bezieht sich doch auf den Turm.

:oops: Ja, stimmt. Da hab ich mich vertan, ich lass es gleich ausbessern. Danke für den Hinweis :thumb:

Zitat:

Zitat von Cöster
Die 21351 könnte doch eigentlich jede Zahl >=1571 sein, oder?

Jup, das is korrekt.

greetz
Mike

alzaimar 31. Jul 2006 16:41

Re: Schach: Überprüfung, ob Zug erlaubt
 
Ich hab mir das eben mal alles durchgelesen.... Sagt mal, ist es nicht ein wenig -äh- suboptimal, mit irgendwelchen winkeln zu arbeiten? Ich meine, wir haben hier ein Schachbrett, das ist entweder eine 8x8 Matrix, oder ein [0..63] Feld. Dann hat man mögliche Bewegungsrichtungen und das war es dann. Wie man da mit ArcSin rumhantiert, ist mir ein Rätsel...

Aber vielleicht bin ich auch nur zu :wall:

Der_Unwissende 31. Jul 2006 16:54

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

Zitat von alzaimar
oder ein [0..63] Feld. Dann hat man mögliche Bewegungsrichtungen und das war es dann. Wie man da mit ArcSin rumhantiert, ist mir ein Rätsel...

Jap, das hab ich doch schon gelesen...


Zitat:

Zitat von Sharky
Das Feld von 8x8 kannst Du ja auch als Linearesfeld mit 64 feldern abbilden.
Jetzt überlege mal wie z.B. ein "Springer" sich auf diesem "eindimensiomale" Array bewegen kann.

Er kan nur 4 mögliche Felder vor oder 4 mögliche Felder zurück. (wenn ich mich nicht verzählt habe)

Aber das wäre doch ein Ansatz?

Ich würde mal auch sagen, wenn es nicht einen Grund gibt hier nicht mit diskreten Werten zu arbeiten (und es sind wirklich wenige), dann solltest du dir einen der Tipps von alzmaimar oder Sharky greifen und es einfach (hier wörtlich zu verstehen) mit diesen Möglichkeiten versuchen. Letztlich bleibt dir nur die Speziallfälle (auch sehr sehr sehr wenige) zu prüfen und für jede Klasse von Schachfigur die mögichen Richtungen fest zu legen. Wie hier schon gesagt wurde hat stellt der Springer nochmal eine Ausnahme dar, er kann auch über Figuren springen die im Weg sind.
Aber einfacher ist sicherlich keine der anderen Lösungen (sorry an die anderen, es sind ja auch interessante Ansätze, irgendwie).

Gruß Der Unwissende

fkerber 1. Aug 2006 00:25

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

Lang, lang ists her...
Ich bin mir nicht mehr hundertprozentig sicher, wie ich es gelöst habe, aber sicher bin ich mir, dass keine Winkel mehr darin vorkamen :mrgreen:
Ich kann leider jetzt nicht nachschauen, da das Programm auf einer ausgebauten Festplatte im Archiv ruht - aber soweit ich mich erinnere waren es dann doch die if-Abfragen. Meine Hürde war anfangs, dass ich die Befürchtung hatte z.B. bei der Dame nahezu alle Felder überprüfen zu müssen. Durch etwas logisches Nachdenken und zunehmendem Verständnis für rekursive (und andere) Funktionsaufrufe ist damals ein recht schlanker Code entstanden, der auch streng OOP-konform war.


Ciao, Frederic

alzaimar 1. Aug 2006 07:29

Re: Schach: Überprüfung, ob Zug erlaubt
 
Ich würde mal versuchen, einen Zuggenerator zu entwerfen. Er erzeugt für alle Steine einer Farbe alle legalen Züge. Dieser Zuggenerator ist neben der Stellungsbewertung der zentrale Bestandteil eines Schach (oder Brettspiel-) Programmes.

So schwer ist das ja nicht.

Delphi-Quellcode:
Type
  TChessPos = Record
    cpRow, cpCol : Byte;
    End;
  TChessMove = Record
    cmPiece : TChessPiece;
    cmFrom,
    cmTo : TChessPos;
  End;

  TChessMoves : Array Of TChessMove;

Procedure MakeAllMoves (aBoard : TChessBoard; aColor : TChessColor; Var aMoveList : TChessMoves);
Var
  r,c : Integer;

Begin
  For r :=0 to 7 do
    For c := 0 to 7 do
       If aBoard[r,c].Color = aColor then
         Case aBoard[r,c].Piece Of
            ...
         End;
End;
Für jeden Spielstein (Bauer, Turm etc.) müssen dann eben einfach alle möglichen Züge durchprobiert werden. Klar kommt da Einiges zusammen, das ist ja gerade der Grund, warum erst jetzt, mit superparallelen und superschnellen Rechnen, ein Computer besser spielen kann, als ein Mensch.

Schach ist nun mal nicht trivial.

C_NO_THANKS 2. Aug 2006 21:01

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

ich versuche mal eine Antwort ohne Code.

Ich würde aus jeder Figur ein Objekt machen. (logische und grafische Implementierung unter einem Dach)
Jedes Objekt wird so programmiert, dass es selber weiss wie es sich bewegen darf. Stösst es im Bewegungsablauf auf ein anderes Objekt oder an die Grenzen des Brettes, dann werden entsprechende Ereignisse ausgelöst.
Logik in der Bewegung:
- Richtung
- Anzahl der Felder in dieser Richtung?
- Grenze erreicht?
- Kollision mit einer anderen Figur?
- Sonderfälle wie beim Bauern 2 Felder vor wenn auf Grundposition, Rochade Turm mit König berücksichtigen... u.v.m.

Trifft die sich virtuell bewegende Figur auf eine andere, tauschen diese dann Informationen über diverse Properties aus.
Z.B. die Identität oder Wertigkeit.
"Bist Du weiss oder schawrz?"
"Wenn schwarz - dann - bist Du nicht der gegnerische König?"
"Wenn wahr dann schlage .... (löse Ereignis "Schlage Figur aus")

Ohne ifs kann ich es mir nicht vorstellen (im richtigen Leben gehts ja auch nicht ohne ifs - nur denken wir nicht drüber nach) Aber Du kannst die ifs auf die Object-Prototypen begrenzen. Dein Schachspiel-Object macht dann nichts anderes, als die geplanten Züge an die entsprechenden Figuren-Objekte zu übergeben und wartet dann auf die Nachricht von der Figur ob Sie das so durchführen könnte.

Die Definition einer Figur im "TSchachspiel"-Object könnte dann folgendermassen lauten:
Pferd_Schwarz_01 : TPferd_Schwarz_01; (Wobei TPferd_Schwarz_01 von TPferd abgeleitet sein sollte)

Man kann die Objekte soweit verfeinern, dass eine Figur sogar seine Ausgangsposition kennt und sich beim Aufruf "Schachspiel:=TSchachspiel.create (self) entsprechend positioniert.

Zur späteren Weiterentwicklung des Programms, könntest Du im ersten Schritt ein Zugwertigkeit implementieren. Das heisst jede Figur kann einen Zug vorschlagen, den sie als am höchstwertigsten erkennt. Als Beispiel wäre das direkte Schlagen einer gegnerischen Figur denkbar.

So kommst Du von der rein mechanischen Anwendung, zur taktisch "mitdenkenden" Schachfigur. Wenn Du die Figuren zu guten Taktikern "ausgebildet" hast, kannst Du Dir über Strategie Gedanken machen. Die Figuren einer Farbe könnten über einen Kommunikationskanal (Broadcast-Messages) zusammen kommunizieren. In einer demokratischen Abstimmung würde dann der nächste Zug beschlossen :cheers:

Die Demokatie kann man beim Schach auch einfach weglassen. Die Figuren könnten Ihre Vorschläge auch an den König senden, und der trifft dann eine Entscheidung (er ist halt der Boss auf dem Brett).

Meine Anmerkungen lösen zwar nicht Deine Probleme im Detail, aber ich denke es wäre eine interessante Richtung.

Ausserdem finde ich es toll, dass Du so ein komplexes Problem angehst.

Viele Grüsse

C_NO_THANKS

Nils_13 2. Aug 2006 21:09

Re: Schach: Überprüfung, ob Zug erlaubt
 
1. Überprüfen, ob Feld belegt.
2. Farbe überprüfen.
3. Überprüfen, ob die Figur überhaupt so ziehen kann.
4. Noch die Überprüfungen: Matt, Patt etc.
5. Sonderzüge.
6. Würde ich diese Überprüfung, wenn jmd. die Figur über einem Feld losgelassen hat durchführen.

Ich wünsche dir noch viel Spaß, denn an zwei Sachen wirst du dich aufhängen: Patt und Matt.

fkerber 2. Aug 2006 23:22

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

Ja, die Situationen Patt und Matt habe ich damals nicht implementiert. Man sollte dazu sagen, dass es wirklich ein Schulprojekt im zweiten Jahr Info war und das solche Worte wie OOP bei anderen Kursteilnehmern nur ein :wiejetzt: ausgelöst haben :mrgreen: !


Ciao Frederic


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:12 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz