如何在VB.NET中实现Bitboard?

时间:2012-03-09 13:58:58

标签: c# .net vb.net

我的问题是:

  1. 是否可以在vb.net中实现bitboard
  2. 在VB中做位板的任何教程/参考?
  3. C#答案是可以接受的,因为翻译并不难。

5 个答案:

答案 0 :(得分: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];
 }

答案 1 :(得分: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

答案 2 :(得分:0)

此处有一些关于此的帖子在答案中有一些有用的信息,希望他们有所帮助。

How hard is it to implement a chess engine?

Chess Optimizations

答案 3 :(得分:0)

怎么样......

Dim mArray(8,8) As Boolean

Boolean替换为您自己的类或结构,并将功能扩展到您的要求。

答案 4 :(得分:0)

如果您不想使用数组,另一个选项是简单地创建一个类/结构,其中包含您想要指定的许多“扇区”中的板或状态。例如,您可以指定4个long来表示128x128板,每个long代表一个“扇区”(假设32位处理器)。然后,您所要做的就是覆盖Equals方法(或==运算符)以运行直接比较以检查每个“section”IE this.Quadrant1 == that.Quadrant1的相等性。

最终,位板的整个概念是您使用数据类型本身的位来表示环境的位置/状态(int = 32bits = 32位,long = 64bits = 64位等)。对于数值类型,这意味着您可以轻松地进行直接相等比较(x == y)以查看位是否相等。这也使得检查有效移动非常容易,因为它只需要移动位X数量的位置来表示移动,并且做一个按位&amp;反对对手板。

例如,Pawns可以向上移动一个空间(相对于他们的棋盘),如果他们尚未移动,则可以移动两个空间,或者可以捕获。因此,要检查有效移动,您可以移动棋子位置8(一个空格),16(两个空格,检查是否先没有移动),或7/9(捕获)。对于一个或两个空间移动,你必须做一个按位&amp;在你的棋盘和对手板上为新的“位置”并检查它是否大于0(表示有人占据了空间,因此无效移动)。对于捕获移动,您只需检查对手板并允许移动仅在结果&amp;对于两个空格,首先必须对初始pawn“row”(255 <&lt;&lt;&lt; 8&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; 48&gt看看是否可能。如果您要为每个棋子创建对象,您只需检查Pawn对象本身的布尔值,指示它是否已经移动过。

使用位板时要考虑的最后一件事是你是否使用有符号值(至少在.NET中)。这很重要,因为如果负位设置在有符号值上,则此负位将在右移位传播(意味着它将在值中引入与您移位的数字一样多的1)。绝对考虑在这种情况下使用无符号值类型,否则你会得到一些时髦的结果。