ฉันจะแปลงการเคลื่อนไหวของชิ้นส่วนที่เป็นไปได้ให้เป็นการเคลื่อนไหวจริงในบิตบอร์ดได้อย่างไร

Jan 09 2021

ถ้าฉันมีบิตบอร์ด (เช่นอัศวินสี่เหลี่ยมเขาสามารถย้ายไปได้) เช่นนี้:

00000000
00000000
00000000
00000000
00000000
01000000
00100000
N0000000

ฉันจะ "แปลง" เป็นการย้ายหรือ "ใช้" การย้ายนั้นได้อย่างไร

คำตอบ

2 AryanParekh Jan 09 2021 at 19:28

มีคำถามสองข้อในโพสต์ของคุณ

  • จะแปลงการโจมตีใน Bitboards เป็นรายการการเคลื่อนไหวได้อย่างไร?

  • จะแสดงถึงการเคลื่อนไหวเหล่านั้นได้อย่างไร?


  • จะแสดงถึงการเคลื่อนไหวเหล่านั้นได้อย่างไร?

คำถามนี้ได้รับการกล่าวถึงที่นี่และที่นี่อย่างละเอียด แต่เพื่อให้บริบทบางอย่างแก่ผู้อ่านโพสต์นี้วิธีง่ายๆในการทำเช่นนี้คือการใช้คลาส / โครงสร้างเพื่อแสดงการเคลื่อนไหว

  • จาก (ชิ้นส่วนที่เคลื่อนที่ได้)
  • ถึง (ชิ้นส่วนที่เคลื่อนที่จะอยู่ที่ไหน)
  • Special Move Flag (ไม่ว่าการเคลื่อนไหวนั้นจะเป็นการเคลื่อนไหวพิเศษเช่น enpassant การคัดเลือกนักแสดงการเลื่อนตำแหน่ง)
  • ชิ้นส่วนที่ได้รับการเลื่อนขั้น (หากการเคลื่อนไหวเป็นการเลื่อนขั้นเลื่อนตำแหน่งชิ้นส่วนใดที่ส่งเสริม)

คุณยังสามารถมีคุณสมบัติพิเศษเช่นชิ้นส่วนที่จับได้ประเภทของปราสาทเป็นต้น แต่ข้อมูลนั้นสามารถอนุมานได้โดยใช้FromและToกำลังสอง

ดังนั้นเมื่อพิจารณาจากข้างต้นเราสามารถแสดงการย้ายได้ดังนี้

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

อย่างไรก็ตามเครื่องมือหมากรุกจำนวนมากรวมถึงของฉันใช้วิธีอื่นที่สามารถบีบอัดการเคลื่อนไหวให้เป็น16บิตได้ อ่านข้อมูลเพิ่มเติมเกี่ยวกับที่นี่

เมื่อเรารู้ว่าการเคลื่อนไหวคืออะไรเราสามารถตอบคำถามต่อไปได้


  • จะแปลงการโจมตีใน Bitboards เป็นรายการการเคลื่อนไหวได้อย่างไร?

ลองพิจารณาว่าเรามีอัศวินในตารางd4 นอกจากนี้เรายังมีฟังก์ชั่นที่ส่งกลับการโจมตีของอัศวินที่ได้รับจากจัตุรัส

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

ลองเก็บสิ่งนี้ไว้ในตัวแปร knightAttacks

uint64_t knightAttacks = getKnightAttacksBB(SQ_D4);

ถ้าคุณสังเกตเห็นอย่างรอบคอบเรามีอยู่แล้ว 1 ของคุณลักษณะ 4 เราต้องเป็นตัวแทนของการย้ายซึ่งเป็นFromตาราง D4- ตอนนี้สิ่งที่เราต้องทำก็คือทำให้สToแควร์เสร็จสมบูรณ์เนื่องจากอัศวินไม่สามารถเคลื่อนไหวพิเศษใด ๆ ได้

วิธีการทั่วไปคือการแสดงบิตที่มีนัยสำคัญน้อยที่สุดจนกว่าคุณknightAttacksจะไม่เหลืออะไร0เลย

0000011100001000 
            ^
            Least significant bit (lsb)

คุณสามารถไปตามลิงค์ที่ฉันให้ไว้เพื่อทราบว่าคุณสามารถดำเนินการนี้ได้อย่างไรหรือมีโอกาสที่คอมไพเลอร์ของคุณอาจให้ข้อมูลแก่คุณอยู่แล้ว

คุณต้องสร้างฟังก์ชันที่ล้าง lsb ของ bitboard และส่งกลับดัชนี ขอเรียกว่าpoplsb().

โดยรวมแล้วรหัสของคุณอาจมีลักษณะเช่นนี้

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
}

สิ่งนี้ใช้ได้ผลเพราะทุกครั้งที่คุณเปิด lsb บิตจะถูกล้างจนกว่าตัวเลขจะเป็น == 0 นั่นคือเวลาที่ลูปหยุดลงและคุณมีรายการการเคลื่อนไหวที่ดีอย่างสมบูรณ์แบบ แนวคิดเดียวกันนี้ใช้กับการเคลื่อนไหวทุกประเภทที่คุณสร้างขึ้นโดยใช้ Bitboards