【问题标题】:How can I implement a Bitboard in VB.NET?如何在 VB.NET 中实现 Bitboard?
【发布时间】:2012-03-17 20:49:00
【问题描述】:

我的问题是:

  1. 是否可以在 vb.net 中实现bitboard
  2. 在 VB 中做 bitboard 的任何教程/参考资料?

C# 答案是可以接受的,因为它并不难翻译。

【问题讨论】:

  • 嗯,很好。不知道他们。但是根据维基百科页面上的描述,想出一个实现并不难。
  • 是的,这是一个国际象棋游戏。
  • 您需要使用逻辑位运算符,例如:Absolute Beginner's Guide to Bit Shifting?
  • @AVIDeveloper Tnx 回复它的帮助:D

标签: c# .net vb.net


【解决方案1】:

要在 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];
 }

【讨论】:

  • 嘿@RoadWarrior,这是您发布的非常有趣的一段代码,您是否在任何地方发布了完整的源代码?
  • @Lu4:Amaia 目前是一个私有的象棋程序,所以没有完整的源代码。
【解决方案2】:

从维基百科的文章中,位板似乎是一个简单的位数组。 .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

【讨论】:

  • 国际象棋中位板的重点在于某些操作的可用性和速度。对于这两个方面,BitArray 明显不如简单的 UInt64。我将很快通过一些示例添加答案。
  • 同意上面的RoadWarrior。出于可扩展性的原因,BitArray 可能是一个不错的选择,它不适用于国际象棋,因为总会有 64 个方格。然而更重要的是,大多数涉及 UInt64 的二进制操作将在 x64 架构上的单个 CPU 周期内完成,我怀疑 BitArray 不能保证这一点。
【解决方案3】:

这里还有一些其他关于此的帖子,其中包含一些有用的信息,希望它们有所帮助。

How hard is it to implement a chess engine?

Chess Optimizations

【讨论】:

  • 我稍后会尝试应用第一个链接..这次我必须去
【解决方案4】:

怎么样...

Dim mArray(8,8) As Boolean

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

【讨论】:

    【解决方案5】:

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

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

    例如,Pawns 可以“向上”移动一个空间(相对于它们的棋盘),如果它们尚未移动,则可以移动两个空间,或者可以捕获。因此,要检查有效的移动,您可以将棋子的位置移动 8(一个空格)、16(两个空格,首先检查是否还没有移动)或 7/9(捕获)。对于一个或两个空格移动,你必须在你的棋盘和对手棋盘上按位 & 来获取新的“位置”,并检查它是否大于 0(表示有人占据了空间,所以无效移动)。对于捕获移动,你只检查你的对手棋盘,并且只有当结果 & 大于 0 时才允许移动。对于两个空格,你首先必须对初始棋子“行”(255

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多