Wie kann ich die Bewegungen eines möglichen Teils in einen tatsächlichen Zug in einem Bitboard umwandeln?

Jan 09 2021

Wenn ich ein Bitboard habe (z. B. für Ritterquadrate, zu denen er sich bewegen kann), dann:

00000000
00000000
00000000
00000000
00000000
01000000
00100000
N0000000

Wie kann ich es in einen Zug "umwandeln" oder diesen Zug "anwenden"?

Antworten

2 AryanParekh Jan 09 2021 at 19:28

Es gibt tatsächlich zwei Fragen in Ihrem Beitrag

  • Wie konvertiere ich Angriffe in Bitboards in eine Liste von Zügen?

  • Wie kann man diese Bewegungen darstellen?


  • Wie kann man diese Bewegungen darstellen?

Diese Frage wurde hier und hier gründlich diskutiert . Um den Lesern dieses Beitrags einen Kontext zu bieten, kann ein sehr einfacher Weg, dies zu tun, darin bestehen, eine Klasse / Struktur zu verwenden, um einen Zug darzustellen

  • Von (wo das bewegliche Stück war)
  • Nach (wo das bewegliche Stück sein wird)
  • Special Move Flag (ob der Move ein Special Move war, dh Enpassant, Casting, Promotion)
  • Gesponsertes Stück (wenn der Zug ein Beförderungszug war, zu welchem ​​Stück wurde er befördert)

Sie können auch zusätzliche Attribute wie erbeutetes Stück, Art der Burg usw. haben. Diese Informationen können jedoch auch mithilfe der Quadrate Fromund abgeleitet werden To.

In Anbetracht des oben Gesagten können wir den Schritt wie folgt darstellen

struct Move {
    char from; 
    char to;   
    char spMoveFlag;
    char promotedPiece;
};

Viele Schach-Engines, einschließlich meiner, verwenden jedoch eine andere Methode, mit der die Bewegung in kleine 16Teile komprimiert werden kann . Lesen Sie mehr darüber hier .

Sobald wir wissen, was ein Schritt ist, können wir die nächste Frage beantworten


  • Wie konvertiere ich Angriffe in Bitboards in eine Liste von Zügen?

Nehmen wir an, wir haben einen Ritter auf dem Feld d4 . Wir haben auch eine Funktion, die die Angriffe eines Ritters angesichts des Quadrats zurückgibt.

. . . . . . . . 
. . . . . . . . 
. . 1 . 1 . . . 
. 1 . . . 1 . . 
. . . n . . . .   =  knightattacks(SQ_D4)
. 1 . . . 1 . . 
. . 1 . 1 . . . 
. . . . . . . . 

Speichern wir dies also in einer Variablen knightAttacks

uint64_t knightAttacks = getKnightAttacksBB(SQ_D4);

Wenn Sie genau bemerken, haben wir bereits 1 der 4 Attribute, die wir benötigen, um den Zug darzustellen, der das FromQuadrat ist - D4. Jetzt müssen wir nur noch das ToQuadrat schaffen, um dies zu vervollständigen, da ein Ritter keine besonderen Bewegungen ausführen kann.

Eine sehr gebräuchliche Methode ist es, das niedrigstwertige Bit zu platzieren, bis knightAttacksnichts mehr übrig ist, d 0. H.

0000011100001000 
            ^
            Least significant bit (lsb)

Sie können dem von mir bereitgestellten Link folgen, um zu erfahren, wie Sie dies ausführen können, oder es besteht die Möglichkeit, dass Ihr Compiler Ihnen dies bereits zur Verfügung stellt.

Sie müssen lediglich eine Funktion erstellen, die das lsb eines Bitboards löscht und dessen Index zurückgibt. Nennen wir es poplsb().

Insgesamt kann Ihr Code so aussehen

int from = SQ_D4;
uint16_t knightAttacks = getknightAttacks(from);

while (knightAttacks)  {
     int to = poplsb(knightAttacks);
     MyMoveList.Add( NewMove(from, to, 0, 0) ); // The last two 0's denote that there is no special move
}

Dies funktioniert, weil jedes Mal, wenn Sie den lsb platzen lassen, ein Bit gelöscht wird, bis die Zahl == 0 ist. Dann stoppt die Schleife und Sie haben eine perfekte Liste von Zügen. Die gleiche Idee gilt für alle Arten von Bewegungen, die Sie mit Bitboards erstellt haben.