位棋盘表示法中车和炮的着法生成
这里没有采用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)
----

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
2010-09-14 由极点五笔到QQ五笔的转换想到的