2012-03-09 33 views
1

我的問題是:如何在VB.NET中實現Bitboard?

  1. 是有可能實現在vb.net一個bitboard
  2. 任何教程/參考VB中做位板?

C#答案是可以接受的,因爲它不是很難翻譯。

+0

這是對一盤棋? – GrandMasterFlush 2012-03-09 14:10:40

+1

嗯,很好。不知道他們。但是,根據維基百科頁面上的描述,實現一個實現並不困難。 – Joey 2012-03-09 14:11:33

+0

是的,這是一個國際象棋遊戲。 – jasperagrante 2012-03-09 14:14:08

回答

3

從維基百科文章中,一個位板似乎是一個簡單的位數組。 .NET中有一個名爲BitArray的類,它具有執行按位操作的方法。

例如,對於白色車位置的棋盤可以聲明如下:

'Create bit array to store white rooks 
Dim whiteRooks As New BitArray(64) 

'Set white rooks at initial position 
whiteRooks(0) = True 'Corresponds to A1 on chess board 
whiteRooks(56) = True 'Corresponds to H1 on chess board 
+1

國際象棋中棋盤的全部重點是某些操作的可用性和速度。對於這兩個方面來說,BitArray比簡單的UInt64差得多。我將很快用一些例子添加一個答案。 – RoadWarrior 2012-03-16 11:16:21

+0

同意上面的RoadWarrior。 BitArray可能是不適用於國際象棋的可擴展性原因的一個好選擇,因爲總是有64個方格。但更重要的是,大多數涉及UInt64的二進制操作都將在x64架構的單CPU週期中完成,這是我懷疑BitArray保證的。 – bytefire 2013-05-31 13:28:01

0

......怎麼

Dim mArray(8,8) As Boolean 

替代Boolean爲自己的類或結構和functionalty擴展到您的要求。

0

另一種選擇,如果你不想使用數組,是簡單地創建一個類/結構包含董事會或州在你想指定的很多「行業」。例如,您可以指定4個long來表示128x128板,每個long代表一個「扇區」(假設爲32位處理器)。然後,您只需重寫Equals方法(或==運算符)以運行直接比較來檢查每個「部分」是否相等,即IE this.Quadrant1 == that.Quadrant1。最終,一個位板的整個概念是,你使用數據類型本身的位來表示你的環境的位置/狀態(int = 32bits = 32個位置,long = 64bits = 64個位置等)。對於數值類型,這意味着您可以輕鬆進行直接相等比較(x == y)以查看比特是否相等。這也使得檢查有效移動非常容易,因爲它只需要移動位X的位置來表示移動,並且對對手棋盤進行按位&。例如,棋子可以向上移動一個空間(相對於他們的棋盤),如果他們還沒有移動,或者可以捕捉,則棋子移動兩個。所以爲了檢查有效的移動,你需要移動小兵位置8(一個空格),16(兩個空格,檢查是否還沒有移動)或者7/9(捕捉)。對於一次或兩次空間移動,您必須在棋盤和對手棋盤上爲新「位置」執行一次按位&,並檢查它是否大於0(表示某人佔據空間,因此無效移動)。對於捕捉移動,你只能檢查你的對手棋盤,並且只有在結果&大於0時才允許移動。對於兩個空格,首先必須對初始棋子「行」進行按位比較(255 < < < 8代表白色,255代表< < 48代表黑色)與有問題的棋子一起看看是否可能。如果你爲每一個棋子創建對象,你可以簡單地檢查一下Pawn對象本身的布爾值,指出它是否已經移動。

使用位板時要考慮的最後一件事是您是否使用帶符號的值(至少在.NET中)。這一點很重要,因爲如果負數位被設置爲有符號值,則該負數位將傳播到右移位(意味着它將引入與移位數相同數量的1)。在這種情況下絕對考慮使用無符號值類型,否則你會得到一些時髦的結果。

8

要在VB(或C#)中實現位板,請使用System.UInt64。這可以容納64位,棋盤的每個方格都有1位。該值類型適用於許多快速按位操作。我不建議使用另一張海報推薦的BitArray,因爲它太慢了。任何像樣的象棋引擎的基本要求之一就是速度。

要回答你的第二個問題,這是一個good bitboard tutorial

下面是我自己的C#象棋引擎的一些例子。從代碼中可以看到,使用位板可能需要一段時間,但它們通常非常快,特別是對於位置評估。

實施例1 - 棋盤定義:

internal UInt64 WhiteKing; 
internal UInt64 WhiteQueens; 
internal UInt64 WhiteRooks; 
internal UInt64 WhiteBishops; 
internal UInt64 WhiteKnights; 
internal UInt64 WhitePawns; 
internal UInt64 WhitePieces; 

實施例2 - 棋盤初始化:

// Initialise piece bitboards using square contents. 
private void InitPieceBitboards() 
{ 
    this.WhiteKing = 0; 
    this.WhiteQueens = 0; 
    this.WhiteRooks = 0; 
    this.WhiteBishops = 0; 
    this.WhiteKnights = 0; 
    this.WhitePawns = 0; 

    for (Int16 i = 0; i < 64; i++) 
    { 
     if (this.Squares[i] == Constants.WHITE_KING) 
     { 
      this.WhiteKing = this.WhiteKing | Constants.BITSET[i]; 
     } 
     if (this.Squares[i] == Constants.WHITE_QUEEN) 
     { 
      this.WhiteQueens = this.WhiteQueens | Constants.BITSET[i]; 
     } 
     if (this.Squares[i] == Constants.WHITE_ROOK) 
     { 
      this.WhiteRooks = this.WhiteRooks | Constants.BITSET[i]; 
     } 
     if (this.Squares[i] == Constants.WHITE_BISHOP) 
     { 
      this.WhiteBishops = this.WhiteBishops | Constants.BITSET[i]; 
     } 
     if (this.Squares[i] == Constants.WHITE_KNIGHT) 
     { 
      this.WhiteKnights = this.WhiteKnights | Constants.BITSET[i]; 
     } 
     if (this.Squares[i] == Constants.WHITE_PAWN) 
     { 
      this.WhitePawns = this.WhitePawns | Constants.BITSET[i]; 
     } 

     this.WhitePieces = this.WhiteKing | this.WhiteQueens | 
          this.WhiteRooks | this.WhiteBishops | 
          this.WhiteKnights | this.WhitePawns; 
     this.BlackPieces = this.BlackKing | this.BlackQueens | 
          this.BlackRooks | this.BlackBishops | 
          this.BlackKnights | this.BlackPawns; 
     this.SquaresOccupied = this.WhitePieces | this.BlackPieces; 
    } 
} 

實施例3 - 移動代:

// We can't capture one of our own pieces. 
eligibleSquares = ~this.WhitePieces; 

// Generate moves for white knights. 
remainingKnights = this.WhiteKnights; 

// Generate the moves for each knight... 
while (remainingKnights != 0) 
{ 
    squareFrom = BitOps.BitScanForward(remainingKnights); 
    generatedMoves = Constants.ATTACKS_KNIGHT[squareFrom] & eligibleSquares; 
    while (generatedMoves != 0) 
    { 
     squareTo = BitOps.BitScanForward(generatedMoves); 
     moveList.Add(new Move(squareFrom, squareTo, Constants.WHITE_KNIGHT, 
           this.Squares[squareTo], Constants.EMPTY)); 
     generatedMoves ^= Constants.BITSET[squareTo]; 
    } 
    // Finished with this knight - move on to the next one. 
    remainingKnights ^= Constants.BITSET[squareFrom]; 
}  

實施例4 - 計算材料的分數:

// Material score from scratch, in centipawns from White's perspective. 
internal static Int32 ScoreMaterial(Board position) 
{ 
    return BitOps.BitCountWegner(position.WhitePawns) * Constants.VALUE_PAWN + 
      BitOps.BitCountWegner(position.WhiteKnights) * Constants.VALUE_KNIGHT + 
      BitOps.BitCountWegner(position.WhiteBishops) * Constants.VALUE_BISHOP + 
      BitOps.BitCountWegner(position.WhiteRooks) * Constants.VALUE_ROOK + 
      BitOps.BitCountWegner(position.WhiteQueens) * Constants.VALUE_QUEEN - 
      BitOps.BitCountWegner(position.BlackPawns) * Constants.VALUE_PAWN - 
      BitOps.BitCountWegner(position.BlackKnights) * Constants.VALUE_KNIGHT - 
      BitOps.BitCountWegner(position.BlackBishops) * Constants.VALUE_BISHOP - 
      BitOps.BitCountWegner(position.BlackRooks) * Constants.VALUE_ROOK - 
      BitOps.BitCountWegner(position.BlackQueens) * Constants.VALUE_QUEEN; 
} 

例5 - 計算一塊流動性:

// Calculate mobility score for white knights. 
remainingPieces = position.WhiteKnights; 
while (remainingPieces != 0) 
{ 
    squareFrom = BitOps.BitScanForward(remainingPieces); 
    mobilityKnight += BitOps.BitCountWegner(Constants.ATTACKS_KNIGHT[squareFrom] 
              & unoccupiedSquares); 
    remainingPieces ^= Constants.BITSET[squareFrom]; 
} 
+0

嘿@RoadWarrior,這是你發佈的一段非常有趣的代碼,你有沒有在任何地方發佈完整的源代碼? – Lu4 2013-08-29 13:21:32

+0

@ Lu4:Amaia目前是一個私人國際象棋程序,所以完整的源代碼不可用。 – RoadWarrior 2013-08-29 16:41:28

+0

我明白了,謝謝... – Lu4 2013-08-29 18:16:46