发新话题
打印

"五位马表",终结马的走法

本主题由 monarch 于 1-18-2008 17:55 加入精华

"五位马表",终结马的走法

"五位马表",终结马的走法

以前介绍过折叠位棋盘的技术,由于位棋盘的速度问题,而暂时冷落下来,真正使用折叠位棋盘的人不多。下面介绍一种技术,从位棋盘的思想演变而来,但不需要在位棋盘上实现。为了使用方便将其称为“5位马表”。(名称如有更好,欢迎提供)
首先,预置一个如下的数组(如下图,贴上来没有表格,不好看),棋盘的坐标可以从下到上,也可以从左到右,但是里面的值一定要从下到上,以前讲折叠位棋盘时,共需要8位,有3位是冗余的,并且棋盘的坐标要求从下到上,现在没有这个要求,并且只要求5位,没有冗余,这样会产生冲突吗?先了解一下构成该表的原则:任意一个格子的四周不能有相同的值,加上格子自身需要一个值,就是说最少需要5个不同的值,将4个不同的值精心排列在周围,使其不发生冲突,就得到下表(你也可以自己排列下表)。
我们将表中为数值1的定义为1号格子,为2的定义为2号格子,为4的定义为4号格子,等等。观察表可知,1号的左边是4,右边是8,上边是2,下边是16。所有的1号格子都是一样,这样保证了走步的一致性。
如果某格有子,其值等于0,如果没有子,其值就是表格的数值。
该表对马的走步和计算马的灵活度都很快捷。

16        4        1        8        2        16        4        1        8
8        2        16        4        1        8        2        16        4
4        1        8        2        16        4        1        8        2
2        16        4        1        8        2        16        4        1
1        8        2        16        4        1        8        2        16
16        4        1        8        2        16        4        1        8
8        2        16        4        1        8        2        16        4
4        1        8        2        16        4        1        8        2
2        16        4        1        8        2        16        4        1
1        8        2        16        4        1        8        2        16

首先定义一个表int table[90][32][8],并进行初始化。例如兰色的格子(其下标值=20)
table[20][1] = {9,18} , 意思是等于1时可以往左走
table[20][2]={13,22}
table[20][4]={1,3}
table[20][16]={37,29}
table[20][1|2]={9,18,13,22}, 意思是等于3时可以往左和往右走
下面的值就不一一列举了。

有了这样的数组就可以走子了。还是以蓝格子为例。
1、        计算occupy_board的值,如果有子=0,没有子=table,实际中occup_board可以随时更新.
2、        计算索引值index= occupy_board[20-1]| occupy_board[20+1]| occupy_board[20-9]| occupy_board][20+9]
3、        查表即可得到值。
旧画一堂,龙不吟,虎不啸,花不闻香鸟不叫,见此小子,可笑,可笑;
残棋半局,车无轮,马无鞍,炮无烟火卒无粮,喝声将军,提防,提防。

世事如棋,一局争来千秋业;
柔情似水,几时流尽六朝春。

TOP

前段时间忙~没空看,今天看了一下~感觉还是蛮有新意的~好东西当然要大家分享啦~,独乐乐不如众乐乐,说一说我的马和象是怎么做的,其实跟马路天使兄是差不多的吧~。
HORSE_POS[256][16][12],(名字是举例子的,12是马可以走的步数,具体自己定啦~)主要问题就是马周围四个地方是否有子和马的位置决定了马的走子步数, 位置好弄啦~周围如何求呢?

int num = (0 != SQUARE[pos +HOR_LEG_UP];
num |= (0 != SQUARE[pos +HOR_LEG_RIGHT]) << 1;
num |= (0 != SQUARE[pos +HOR_LEG_DOWN]) << 2;
num |= (0 != SQUARE[pos +HOR_LEG_LEFT]) << 3;

前提是 SQUARE无子情况下一定要为0!
应该都能编译过的,如果不行,手写~以DOWN为例(举个例子,格式是不对的)
xor ecx, ecx
cmp SQUARE[pos + HORES_LEG_DOWN], ecx
setne cl
shl ecx, 2
or num, ecx
这里主要是利用了两条汇编指令:
cmp 和 setne

希望大家看了后能够举一反三吧~
旧画一堂,龙不吟,虎不啸,花不闻香鸟不叫,见此小子,可笑,可笑;
残棋半局,车无轮,马无鞍,炮无烟火卒无粮,喝声将军,提防,提防。

世事如棋,一局争来千秋业;
柔情似水,几时流尽六朝春。

TOP

使用位行与位列虽然抽象,可能更简单,而且无数据冗余,无需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增加,也未见减少,只作为算法的艺术吧。
旧画一堂,龙不吟,虎不啸,花不闻香鸟不叫,见此小子,可笑,可笑;
残棋半局,车无轮,马无鞍,炮无烟火卒无粮,喝声将军,提防,提防。

世事如棋,一局争来千秋业;
柔情似水,几时流尽六朝春。

TOP

发新话题