使用魔术位板滑动移动生成

时间:2013-06-04 18:42:59

标签: chess bitboard

这是关于如何使用魔术位板在国际象棋中验证滑动棋子移动的大图片的问题。为了澄清一点,我并不是要求 魔术位板如何在内部工作。

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

White to move. Validate a given move for the rook on g3

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

3 个答案:

答案 0 :(得分:23)

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

首先,你需要找到一些神奇的数字。当您使用幻数时,您写入查找幻数的部分代码也将被重复使用。

首先,您需要编写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);

所以你可能会问自己,da f%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的数量决定了这件作品所需的查找表的大小。方组合。在这种情况下,有10个,所以有2 ^ 10(1024)个可能阻止e4车的排列。

阻挡板是这些排列中的一种。在这个例子中,在b4,c4,e2,e5和e7上有片段。这些是敌人友好的作品。阻挡板始终是阻挡掩模的子集(不需要在其他方块上显示碎片(例如,blockers = occupancy & blockermask;))。

对于给定的阻挡板,移动板是您的作品的最终可用移动。这包括您作品的可能捕获。请注意,它还包括捕获您自己的碎片(但您可以使用不属于您自己的碎片位置来取消它们)。

所以,基本上你需要在所有方块上为车和主教生成阻挡掩码。而且你还需要为每个方块生成所有可能的阻挡板,用于车和主教。在生成阻挡板时,还应生成生成的移动板。将所有这些东西存储在数组中供以后使用。

现在你已经完成了,对于每个方块/组合,你可以尝试随机的64位数字,看看它们是否具有魔力。你可以通过使用神奇的公式return ((blockerboard*magic) >> (64-bits));知道它们是否具有魔力,这将创建一个从0..2 ^位(在e4车的情况下为0..1024)的神奇索引。对于某个棋子/方块,如果两个阻挡板产生相同的魔法指数这两个阻挡板有不同的移动板,那么这是一个麻瓜牌号,你应该尝试一个新的。

一旦你失败了,你将拥有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];
}

答案 1 :(得分:4)

我们可以假设魔术位功能可用,这是很好的,但一般来说,位板移动生成功能可以接受任何产生位板的技术,该位板可以移动到可能的方块。假设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);
   }
}

其中Bit.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; 

答案 2 :(得分:-9)

哈哈从来没有听说过“魔术位”。谷歌它,它正是我的预期。虽然我没有看到任何关于它的魔法。无论如何要回答你的问题,你需要生成当前所选作品的可用移动位位置。不确定还需要什么。

对于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;
   }