当前位置: 首页 > 知识库问答 >
问题:

使用magic bitboard生成滑动移动

胡元明
2023-03-14

这是一个关于如何使用魔法棋盘在国际象棋中验证滑动棋子移动的大局的问题。我只是想澄清一下,我不是在问魔法比特板在内部是如何工作的。

现在,关于这个问题的更多细节。我正在使用位板编写棋盘表示,我想使用魔术位板验证滑块移动。有人能列出如何实现这一目标的主要步骤吗?作为一个例子,考虑以下棋盘位置:

假设我们已经初始化并准备好使用所有魔术位板函数和数据结构。因此,仅使用魔法比特板的函数签名,您能否列出验证g3上白车的给定移动的步骤(伪代码或任何语言)?

共有3个答案

钮边浩
2023-03-14

哈哈,从没听说过“魔法比特板”。用谷歌搜索一下,这正是我所期待的。虽然我看不出它有什么魔力。无论如何,要回答您的问题,您需要生成当前选定工件的可用移动位位置。不确定还需要什么。

至于psuedo代码,我猜是这样的:

Positions KingChessPiece::getMovablePositions(){
   (x,y) = current bit position in the bitboard
   availablePosition = [ (x+1,y),(x-1,y),(x,y+1),(x,y-1) ]
   for each position in availablePosition
      if p_i is occupied then remove it from list

   return availablePosition
   }

我的意思是这没有什么难的,你只需要确保你得到和设置的位置与你使用的内部结构兼容。

编辑:

女王的例子:

Position QueenChessPiece::getMovablePosition(){
     (x,y) = queens current position
      availablePosition = []; //empty list
     //check diagonal positions
     //move top left diagonal 
     availablePosition.concat( this.generateAvailablePosition(x,y,-1,1);
     //move top right diagonal 
     availablePosition.concat( this.generateAvailablePosition(x,y,1,1);
     //move bottom right diagonal 
     availablePosition.concat( this.generateAvailablePosition(x,y,1,-1);
     //move bottom left diagonal 
     availablePosition.concat( this.generateAvailablePosition(x,y,-1,-1);

    //move straight up 
    availablePosition.concat( this.generateAvailablePosition(x,y,0,1) )
    //move straight down 
    availablePosition.concat( this.generateAvailablePosition(x,y,0,-1) )

    //move left 
    availablePosition.concat( this.generateAvailablePosition(x,y,-1,0) )
    //move right
    availablePosition.concat( this.generateAvailablePosition(x,y,1,0) )

  return availablePosition;
}
Position QueenChess::generateAvailablePosition(x,y,dx,dy){
  availPosition = [];
  while( !isSpaceOccupied(x + dx , y + dy)) 
    availPosition.add( position(x + dx ,y + dy) );
    x += dx;
    y += dy;
  endWhile
  return availPosition;
   }
司徒博容
2023-03-14

很好,我们可以假设魔术位板函数可用,但一般来说,位板移动生成函数可以接受任何生成位板的技术,该位板给出了可能移动到的方块。假设RookMoves是这样一个函数,那么您将填充移动列表如下:

UInt64 pieceBitboard = Bitboard[SideToMove | Piece.Rook];
UInt64 targetBitboard = ~Bitboard[SideToMove | Piece.All];

while (pieceBitboard != 0) {
   Int32 from = Bit.Pop(ref pieceBitboard);
   UInt64 moveBitboard = targetBitboard & RookMoves(from, OccupiedBitboard);

   while (moveBitboard != 0) {
       Int32 to = Bit.Pop(ref moveBitboard);
       moveList[index++] = Move.Create(this, from, to);
   }
}

其中位。Pop(ref x)返回x中的最低有效位,同时将其从x中“弹出”(删除)。

要验证移动(我将其解释为确认移动有效性),您可以检查移动是否在移动列表中,或者执行移动并查看是否让您处于检查状态。当然,您可能需要检查它是否遵守工件的运动规则,但这很简单。

if ((RookRays[move.From] & Bit.At[move.To]) == 0)
   return false;

Int32 side = SideToMove;
position.Make(move);
Boolean valid = position.InCheck(side);
position.Unmake(move);

return valid; 
鄂坚
2023-03-14

简单地说,魔术比特板是一种有效的方式来获取位置并获得滑动块的合法移动。

首先,你需要找到一些神奇的数字。当你使用幻数时,你为寻找幻数而编写的一些代码也会被重复使用。

首先,你需要编写5个函数。这些不需要特别快,因为你只会在寻找魔法数字时使用它们,并且在程序启动时使用一次,然后再使用你的魔法数字。你可以在这些函数中使用任何旧的技术。

uint64_t blockermask_rook   (int square);
uint64_t blockermask_bishop (int square);
uint64_t moveboard_rook     (int square, uint64_t blockerboard);
uint64_t moveboard_bishop   (int square, uint64_t blockerboard);
uint64_t blockerboard       (int index, uint64_t blockermask);

所以你可能会问自己,daf%q是一个屏蔽板,移动板,和屏蔽板?我只是编造了一些术语,但我的意思是:

/* Example, Rook on e4:
 *  
 *    The blocker mask        A blocker board         The move board
 *    0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
 *    0 0 0 0 1 0 0 0         0 0 0 0 1 0 0 0         0 0 0 0 0 0 0 0 
 *    0 0 0 0 1 0 0 0         0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
 *    0 0 0 0 1 0 0 0         0 0 0 0 1 0 0 0         0 0 0 0 1 0 0 0 
 *    0 1 1 1 0 1 1 0         0 1 1 0 0 0 0 0         0 0 1 1 0 1 1 1 
 *    0 0 0 0 1 0 0 0         0 0 0 0 0 0 0 0         0 0 0 0 1 0 0 0 
 *    0 0 0 0 1 0 0 0         0 0 0 0 1 0 0 0         0 0 0 0 1 0 0 0 
 *    0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
 */

阻挡者面具是所有可以占据的方块,可以阻止你的作品进一步移动。边缘方块不需要是其中的一部分,因为你的作品无论如何都不能再经过那个方块了。此位板中1的数量决定了这一块所需的查找表的大小

拦截器板就是其中之一。在本例中,有b4、c4、e2、e5和e7上的碎片。这些是敌方和友方的棋子。拦截器板始终是拦截器掩码的子集(它不需要在其他方块上显示碎片(例如,blockers=occulation)

移动棋盘是你的棋子在给定的拦网棋盘上的可用移动。这包括你的作品可能的捕捉。请注意,它还包括捕获您自己的片段(但您可以使用一个非您自己的片段位置来删除这些片段)。

所以,基本上,你需要在所有的方块上生成拦截器面具,无论是车还是主教。你还需要在每个方块上生成所有可能的拦截器板,用于rook和bishop。生成拦截器板时,还应生成生成的移动板。将所有这些存储在数组中,以备将来使用。

现在您已经完成了,对于每个方块/块组合,您可以尝试随机的64位数字,看看它们是否神奇。通过使用魔法公式,return((Blockboard*magic),你就会知道它们是否神奇

一旦你记下来,你会有64个魔术车号码和64个魔术主教号码。要使用它们,在程序启动时,您将初始化所有屏蔽板、屏蔽板和移动板。现在,你的程序可以高效地在任何广场上(以及皇后区)查找主教和车的移动板。代码如下所示:

/* Retrieves the move board for the given square and occupancy board. */
uint64_t magic_move_rook  (int8_t square, uint64_t occupancy)
{
    /* Remove occupants that aren't in the blocker mask for this square. */
    occupancy &= Rook.blockmask[square];
    /* Calculate the magic move index. */
    int index = (occupancy*Rook.magic[square]) >> (64-Rook.bits[square]);
    /* Return the pre-calculated move board. */
    return Rook.moveboard[square][index];
}

 类似资料:
  • 在我的国际象棋引擎中,它使用比特板来表示棋盘的状态,一次生成一大块伪合法的棋步,结果就是一个比特板。例如: 典当: 稍后有点比特板魔术: 末尾的位板只是一大块可能的移动。引擎通常如何使用这个位板并从中生成单独的移动?我是否必须遍历每一位来检查它是否设置好?不过,在位板上迭代似乎违背了使用位板的目的,这就是为什么我有点怀疑。 有更好的办法吗?

  • 问题内容: 我想做的只是为移动设备添加左/右触摸滑动功能。我怎样才能做到这一点? 另外,如何使显示在悬停时的上一个/下一个按钮变小,以用于移动/ ipad版本? 谢谢 问题答案: 更新: 当我刚接触Web设计时,我想到了此解决方案。既然我年纪大一些又聪明了, 马克·希尔拉迪 ( Mark Shiraldi) 给出的答案似乎是一个更好的选择。参见下一个最佳答案;这是一个更有效率的解决方案。 我最近参

  • 我试图了解国际象棋编程中的位板表示是如何工作的,但我找不到关于一个细节的有用信息(或者只是无法正确翻译它^^)。我的问题是,如何自动生成掩码,以便在每个位置上移动每一个棋子。我假设它是一个矩阵,其中每个棋子类型都定义了他可以从该位置移动的每个字段(wP、bP、K、R、N、B的数组[5][64])。例如,对于下面的Rook on位置,只允许位置是: 我假设我必须为每一块类型和每一块瓷砖创建类似的东西

  • 引用自C Primer 如果我们显式地要求编译器使用生成移动操作,并且编译器无法移动所有成员,那么移动操作将被定义为删除 如果类有一个定义自己的复制构造函数的成员,但不定义移动构造函数,或者如果类有一个不定义自己的复制操作的成员,并且编译器无法合成,则移动构造函数被定义为删除移动构造函数 有些代码似乎违反了这条规则: X没有定义移动构造函数,编译器不能为它合成一个。 根据上述规则,的移动构造函数被

  • 问题内容: 我想制作selenium脚本,该脚本移动以下站点上给出的滑块 示例名称是如何更改jQuery UI Slider的方向 http://jqueryui.com/demos/slider/ 我不知道该怎么做 问题答案: 产生行动链 Actions链生成器实现了Builder模式,以创建包含一组其他操作的CompositeAction。这应该通过配置一个Actions链生成器实例并调用它的

  • 目前我读了Scott Meyers的有效现代C一书,现在我在:第17项:理解特殊成员函数的生成。 我的误解来自以下部分(理由): 这两个复制操作是独立的:声明一个并不会阻止编译器生成另一个。因此,如果您声明了复制构造函数,但没有复制赋值操作符,然后编写需要复制赋值的代码,编译器将为您生成复制赋值操作符。类似地,如果您声明了复制赋值操作符,但没有复制构造函数,但代码需要复制构造,编译器将为您生成复制