位棋盘表示法中车和炮的着法生成
这里没有采用Magic Bitboard技术,采用了4个方向扫描最高1位或最低1位的办法,效率虽然比magic bitboard低一点,但代码还是比较容易理解的。
occupied |
attacks = PRESET_RAY_NORTH[fromPos]; |
blockers = attacks & occupied; |
|
9 8 7 6 5 4 3 2 1 0 |
000000000 001000000 001100100 000000000 001001000 000000000 000000000 010010110 000000000 001000000 ABCDEFGHI |
001000000 001000000 001000000 001000000 001000000 001000000 001000000 000000000 000000000 000000000 ABCDEFGHI |
000000000 001000000 001000000 000000000 001000000 000000000 000000000 000000000 000000000 000000000 ABCDEFGHI |
一个位棋盘,1表示有棋子占据,0表示无棋子。这里的fromPos是C2位置。 |
C2格子的正北面的格子都可以攻击到 |
blockingPos = blockers.GetLowestBit( );
此例中表示C5格阻碍了车的前进 |
PRESET_RAY_NORTH[blockingPos] |
attacks ^= PRESET_RAY_NORTH[blockingPos]; |
||
9 8 7 6 5 4 3 2 1 0 |
001000000 001000000 001000000 001000000 000000000 000000000 000000000 000000000 000000000 000000000 ABCDEFGHI |
000000000 000000000 000000000 000000000 001000000 001000000 001000000 000000000 000000000 000000000 ABCDEFGHI |
上面一系列的位运算处理了正北方可以攻击到的位置,同理再处理东面、南面和西面的情况,就可以得到所有可以攻击到的格子的位棋盘 |
C5格正北方的格子 |
异或后,正好就是位于C2格子的车向北方前进时可以攻击到的所有位置的位棋盘 |
1 /*! 车的着法生成 2 * \param fromPos 出发位置 3 * \param occupied 棋子占据情况的位棋盘 4 * \return 可到达位置组成一个位棋盘 5 */ 6 BitBoard MoveGenerator::RookAttacks( int fromPos, BitBoard occupied ) 7 { 8 int blockingPos; 9 BitBoard attacks, partAttacks, blockers; 10 11 12 // 向北扫描 13 attacks = PRESET_RAY_NORTH[fromPos]; 14 blockers = attacks & occupied; 15 if ( blockers.H | blockers.L) 16 { 17 blockingPos = blockers.GetLowestBit( ); 18 attacks ^= PRESET_RAY_NORTH[blockingPos]; // mask off beyond blocking square 19 } 20 21 22 // 向东扫描 23 partAttacks = PRESET_RAY_EAST[fromPos]; 24 blockers = partAttacks & occupied; 25 if ( blockers.H | blockers.L) 26 { 27 blockingPos = blockers.GetLowestBit( ); 28 partAttacks ^= PRESET_RAY_EAST[blockingPos]; 29 } 30 attacks |= partAttacks; 31 32 // 向南扫描 33 partAttacks = PRESET_RAY_SOUTH[fromPos]; 34 blockers = partAttacks & occupied; 35 if ( blockers.H | blockers.L) 36 { 37 blockingPos = blockers.GetHighestBit( ); 38 partAttacks ^= PRESET_RAY_SOUTH[blockingPos]; 39 } 40 attacks |= partAttacks; 41 42 // 向西扫描 43 partAttacks = PRESET_RAY_WEST[fromPos]; 44 blockers = partAttacks & occupied; 45 if ( blockers.H | blockers.L) 46 { 47 blockingPos = blockers.GetHighestBit( ); 48 partAttacks ^= PRESET_RAY_WEST[blockingPos]; 49 } 50 51 return attacks | partAttacks; 52 }
炮的着法生成可以类似的处理,但要处理吃子的情况。
occupied |
attacks = PRESET_RAY_NORTH[fromPos]; |
blockers = attacks & occupied; |
|
9 8 7 6 5 4 3 2 1 0 |
000000000 001000000 001100100 000000000 001001000 000000000 000000000 010010110 000000000 001000000 ABCDEFGHI |
001000000 001000000 001000000 001000000 001000000 001000000 001000000 000000000 000000000 000000000 ABCDEFGHI |
000000000 001000000 001000000 000000000 000000000 000000000 000000000 000000000 000000000 000000000 ABCDEFGHI |
一个位棋盘,1表示有棋子占据,0表示无棋子。这里的fromPos是C2位置。 |
C2格子的正北面的格子都可以走到 |
blockingPos = blockers.GetLowestBitWithReset( );
此例中表示C5格阻碍了炮的前进,同时要把此位置0 |
|
PRESET_RAY_NORTH_SELF[blockingPos] |
attacks ^= PRESET_RAY_NORTH |
如果有吃子的话 eatPos = blockers.GetLowestBit( ); 此例中为C7。 attacks.SetBit(eatPos); |
|
9 8 7 6 5 4 3 2 1 0 |
001000000 001000000 001000000 001000000 001000000 000000000 000000000 000000000 000000000 000000000 ABCDEFGHI |
000000000 000000000 000000000 000000000 000000000 001000000 001000000 000000000 000000000 000000000 ABCDEFGHI |
000000000 000000000 001000000 000000000 000000000 001000000 001000000 000000000 000000000 000000000 ABCDEFGHI |
上面一系列的位运算处理了正北方可以移动到或攻击到的位置,同理再处理东面、南面和西面的情况,就可以得到所有可以生成所有着法。 |
C5正北方的格子,包括C5位置 |
异或后,正好就是位于C2格子的炮向北方前进时可以移动到的所有位置的位棋盘 |
1 attacks = PRESET_RAY_NORTH[fromPos]; 2 blockers = attacks & occupied; 3 if ( blockers.H | blockers.L) 4 { 5 blockingPos = blockers.GetLowestBitWithReset( ); 6 attacks ^= PRESET_RAY_NORTH_SELF[blockingPos]; // mask off beyond blocking square 7 if ( blockers.H | blockers.L) { 8 eatPos = blockers.GetLowestBit( ); 9 attacks.SetBit(eatPos); 10 } 11 } 12 13 partAttacks = PRESET_RAY_EAST[fromPos]; 14 blockers = partAttacks & occupied; 15 if ( blockers.H | blockers.L) 16 { 17 blockingPos = blockers.GetLowestBitWithReset( ); 18 partAttacks ^= PRESET_RAY_EAST_SELF[blockingPos]; 19 if ( blockers.H | blockers.L) { 20 eatPos = blockers.GetLowestBit( ); 21 partAttacks.SetBit(eatPos); 22 } 23 } 24 attacks |= partAttacks; 25 26 partAttacks = PRESET_RAY_SOUTH[fromPos]; 27 blockers = partAttacks & occupied; 28 if ( blockers.H | blockers.L) 29 { 30 blockingPos = blockers.GetHighestBitWithReset( ); 31 partAttacks ^= PRESET_RAY_SOUTH_SELF[blockingPos]; 32 if ( blockers.H | blockers.L) { 33 eatPos = blockers.GetHighestBit( ); 34 partAttacks.SetBit(eatPos); 35 } 36 } 37 attacks |= partAttacks; 38 39 40 partAttacks = PRESET_RAY_WEST[fromPos]; 41 blockers = partAttacks & occupied; 42 if ( blockers.H | blockers.L) 43 { 44 blockingPos = blockers.GetHighestBitWithReset( ); 45 partAttacks ^= PRESET_RAY_WEST_SELF[blockingPos]; 46 if ( blockers.H | blockers.L) { 47 eatPos = blockers.GetHighestBit( ); 48 partAttacks.SetBit(eatPos); 49 } 50 } 51 52 return attacks | partAttacks;
----==== Email: slofslb (GTD) qq.com 请将(GTD)换成@ ====----
版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
作者:申龙斌的程序人生
---- 魔方、桥牌、象棋、游戏人生...
---- BASIC、C++、JAVA、C#、Haskell、Objective-C、Open Inventor、程序人生...
---- GTD伴我实现人生目标
---- 区块链生存训练
---- 用欧拉计划学Rust编程
---- 申龙斌的读书笔记(2011-2019)
----