使用位行与位列虽然抽象,可能更简单,而且无数据冗余,无需if判断
看了作者的五位马表,构思是在精巧。但仍存在数据冗余,有无棋子需要if语句,二维数组寻址弈无优势,所以不能算作马的终结走法。tzhtzx兄的算法虽然直观,但需要4个if才能得到马腿的索引。
使用位行与位列,无需再定义新的数据结构,完全使用位运算应该可以的。以前有人提出过,只是算法复杂。例如马的预置走法:
unsigned char HorseMoves[256][16][12]; // 49152 Bytes,[16]为马腿信息,[12]中有4位冗余
用位行与位列获得马腿信息,4Bit,共16种组合:左上右下=>1248
// 使用位运算计算Bit马腿的位索引,下面的几种方式都可以,使用>>6以下会失败,因为-x<0 || 12-y<0,出现位移负数位。左移弈会失败!
//int nIndex = ( ((xBitBoard[y]<<(16-x)) & 0x5000) | ((yBitBoard[x]<<(17-y)) & 0xA000) ) >> 12; // 15,14,13,12
//int nIndex = ( ((xBitBoard[y]<<(15-x)) & 0x2800) | ((yBitBoard[x]<<(16-y)) & 0x5000) ) >> 11; // 14,13,12,11
//int nIndex = ( ((xBitBoard[y]<<(14-x)) & 0x1400) | ((yBitBoard[x]<<(15-y)) & 0x2800) ) >> 10; // 13,12,11,10
//int nIndex = ( ((xBitBoard[y]<<(13-x)) & 0xA00) | ((yBitBoard[x]<<(14-y)) & 0x1400) ) >> 9; // 12,11,10, 9
//int nIndex = ( ((xBitBoard[y]<<(12-x)) & 0x500) | ((yBitBoard[x]<<(13-y)) & 0xA00) ) >> 8; // 11,10, 9, 8
//int nIndex = ( ((xBitBoard[y]<<(11-x)) & 0x280) | ((yBitBoard[x]<<(12-y)) & 0x500) ) >> 7; // 10, 9, 8, 7
例如,马的非吃子移动算法:
for(nChess=5; nChess<=6; nChess++)
{
nSrc = Piece[king+nChess];
if( nSrc )
{
x = nSrc & 0xF; // 后4位有效
y = nSrc >> 4; // 前4位有效
pMove = HorseMoves[nSrc][( ((xBitBoard[y]<<(11-x)) & 0x280) | ((yBitBoard[x]<<(12-y)) & 0x500) ) >> 7];
while( *pMove )
{
nDst = *(pMove ++);
if( !Board[nDst] )
*(ChessMove ++) = (nSrc<<8) | nDst;
}
}
}
着法预产生数组对棋盘边界和马腿位置都进行了屏蔽,除了吃自己棋子的着法,都是合法的移动。
这个改动并未使NPS增加,也未见减少,只作为算法的艺术吧。