📄 解剖大象的眼睛——中国象棋程序设计探索(十):实用程序片段.htm
字号:
face="Times New Roman">LongMulMod()</FONT>函数来实现。这个算法在<FONT
face="Times New Roman">1969</FONT>年首先由<FONT
face="Times New Roman">Lewis</FONT>、<FONT
face="Times New Roman">Goodman</FONT>和<FONT
face="Times New Roman">Miller</FONT>提出,这里<FONT
face="Times New Roman"><EM>a</EM></FONT>和<FONT
face="Times New Roman"><EM>m</EM></FONT>的推荐值是:
<DD><FONT face="Times New Roman"><EM>a</EM> = 7<SUP>5</SUP> = 16807</FONT>
<DD><FONT face="Times New Roman"><EM>m</EM> = 2<SUP>31</SUP> </FONT><FONT
face=Symbol>-</FONT><FONT face="Times New Roman"> 1 = 2147483647</FONT>
<DT> 这就使得随机数<FONT face="Times New Roman"><EM>I</EM></FONT>的范围从<FONT
face="Times New Roman">1</FONT>到<FONT face="Times New Roman">2<SUP>31</SUP>
</FONT><FONT face=Symbol>-</FONT><FONT face="Times New Roman"> 2(</FONT>即<FONT
face="Times New Roman">31</FONT>位<FONT
face="Times New Roman">)</FONT>,初始化种子数时,可以用<FONT
face="Times New Roman">1</FONT>到<FONT face="Times New Roman">2<SUP>31</SUP>
</FONT><FONT face=Symbol>-</FONT><FONT face="Times New Roman">
2</FONT>中的任意一个数。<FONT face="Times New Roman">ElephantEye</FONT>在产生<FONT
face="Times New Roman">Zobrist</FONT>键值时,用<FONT
face="Times New Roman">1</FONT>作种子数,而用作其他用途时,用<FONT
face="Times New Roman">time()</FONT>作种子数。
<DT>
<DT><FONT face=Arial size=4><STRONG>10.5 </STRONG></FONT><FONT face=楷体_GB2312
size=4><STRONG>计时</STRONG></FONT><FONT face=Arial
size=4><STRONG>(timer.h)</STRONG></FONT>
<DT>
<DT> <FONT face="Times New Roman">C</FONT>语言里有很多计时函数,如<FONT
face="Times New Roman"><time.h></FONT>中的<FONT
face="Times New Roman">time()</FONT>、<FONT
face="Times New Roman">ftime()</FONT>、<FONT
face="Times New Roman">clock()</FONT>等,笔者认为能达到精确计时功能的只有<FONT
face="Times New Roman">ftime()</FONT>,为此针对该函数设计了<FONT
face="Times New Roman"><timer.h></FONT>,在调用时可以避开对<FONT
face="Times New Roman">btime</FONT>结构的直接处理。计时器是类型为<FONT
face="Times New Roman">TimerStruct</FONT>的对象,成员函数<FONT
face="Times New Roman">Init()</FONT>把当前时间写入该计时器,而<FONT
face="Times New Roman">GetTimer()</FONT>返回当前时间和该计时器的差值<FONT
face="Times New Roman">(</FONT>毫秒<FONT face="Times New Roman">)</FONT>。
<DT>
<DT><FONT face=Arial size=4><STRONG>10.6 </STRONG></FONT><FONT face=楷体_GB2312
size=4><STRONG>管道的行输入和行输出</STRONG></FONT><FONT face=Arial
size=4><STRONG>(pipe.h/pipe.cpp)</STRONG></FONT>
<DT>
<DT> <FONT face="Times New Roman">ElephantEye</FONT>是用“轮转”方式来接收行输入的<FONT
face="Times New Roman">(</FONT>从<FONT
face="Times New Roman">1.1</FONT>版本开始<FONT
face="Times New Roman">)</FONT>。轮转不需要增加线程,只需要每隔一定时间让搜索过程去处理一下接收命令的子过程就可以了。轮转的操作原理在每个操作系统下都是一样的,这种方式甚至能在不支持多任务的<FONT
face="Times New Roman">DOS</FONT>系统下运行。在轮转中调用<FONT
face="Times New Roman">ReadFile()(Windows</FONT>的标准库函数<FONT
face="Times New Roman">)</FONT>或<FONT
face="Times New Roman">read()(UNIX</FONT>的标准库函数<FONT
face="Times New Roman">)</FONT>函数时,使用起来要非常小心,通常需要调用检测输入的函数,只有确认标准输入句柄有输入时,才调用读入信息的函数。然而就检测和读取输入信息的操作而言,程序严重依赖于操作系统,有兴趣的读者可注意<FONT
face="Times New Roman"><pipe.cpp></FONT>中的“<FONT
face="Times New Roman">#ifdef _WIN32</FONT>”语句,比较一下<FONT
face="Times New Roman">Windows</FONT>代码和<FONT
face="Times New Roman">UNIX</FONT>代码的区别。
<DT> 如果输入输出的对象不是标准输入输出句柄而是程序,那么必须用管道来连接子进程的标准输入输出句柄和主进程的控制句柄。用<FONT
face="Times New Roman">CreatePipe()(Windows</FONT>的标准库函数<FONT
face="Times New Roman">)</FONT>或<FONT
face="Times New Roman">pipe()(UNIX</FONT>的标准库函数<FONT
face="Times New Roman">)</FONT>建立管道时,务必要明确输入输出的方向,一个管道有两个句柄,数据总从后一个句柄输入<FONT
face="Times New Roman">(</FONT>称为“写入端”<FONT
face="Times New Roman">)</FONT>,从前一个句柄输出<FONT
face="Times New Roman">(</FONT>称为“读出端”<FONT
face="Times New Roman">)</FONT>,因此可以用两种方式来使用管道:
<DT> <FONT face="Times New Roman">(1) </FONT>写入端定向为子进程的标准输入句柄,读出端用来向子进程发送指令;
<DT> <FONT face="Times New Roman">(2)
</FONT>写入端用来接收子程序的反馈信息,读出端定向为子进程的标准输出句柄。
<DT> 因此,如果象棋程序的界面要控制引擎,必须建立<FONT face="Times New Roman">2</FONT>个管道,产生<FONT
face="Times New Roman">4</FONT>个句柄,其中<FONT
face="Times New Roman">2</FONT>个定向给引擎,<FONT
face="Times New Roman">2</FONT>个用来发送和接收数据,操作非常烦琐。好在<FONT
face="Times New Roman"><pipe.cpp></FONT>可自动完成这一切操作,具体应用可参阅<FONT
face="Times New Roman">UCCI2QH(UCCI</FONT>引擎的浅红象棋适配器<FONT
face="Times New Roman">)</FONT>和<FONT
face="Times New Roman">UCCILEAG(UCCI</FONT>引擎联赛模拟器<FONT
face="Times New Roman">)</FONT>的源程序。
<DT>
<DT><FONT face=Arial size=4><STRONG>10.7 </STRONG></FONT><FONT face=楷体_GB2312
size=4><STRONG>位搜索</STRONG></FONT><FONT face=Arial
size=4><STRONG>(bitscan.h/bitscan.cpp)</STRONG></FONT>
<DT>
<DT> 位搜索<FONT face="Times New Roman">(BitScan)</FONT>主要用于位棋盘的操作,<FONT
face="Times New Roman">Intel</FONT>处理器提供了两个指令,即搜索最低位<FONT
face="Times New Roman">(BSF</FONT>,<FONT
face="Times New Roman">BitScan-Forward)</FONT>和搜索最高位<FONT
face="Times New Roman">(BSR</FONT>,<FONT
face="Times New Roman">BitScan-Reverse)</FONT>的操作,位棋盘的国际象棋程序<FONT
face="Times New Roman">Crafty</FONT>用了<FONT
face="Times New Roman">FirstOne()</FONT>和<FONT
face="Times New Roman">LastOne()</FONT>两个函数,就是专门调用这两个指令的。然而很多试验表明,这两个指令是非常耗时的,而“查表代替计算”会比直接用汇编指令快得多。
<DT> <FONT face="Times New Roman"><bitscan.cpp></FONT>为查表计算分配了两个<FONT
face="Times New Roman">64K</FONT>的表,直接获得<FONT
face="Times New Roman">16</FONT>位数的位搜索结果,<FONT
face="Times New Roman">32</FONT>位数则分解成两个<FONT
face="Times New Roman">16</FONT>位数再分别查表,同时该模块还包含位计数<FONT
face="Times New Roman">(BitCount)</FONT>的操作,同样用了<FONT
face="Times New Roman">64K</FONT>的表。用<FONT
face="Times New Roman"><bitscan.h></FONT>提供的<FONT
face="Times New Roman">BitScanForward()</FONT>和<FONT
face="Times New Roman">BitScanReverse()</FONT>函数做位搜索操作,耗时比直接调用汇编指令少一半,但切记使用查表函数前务必用<FONT
face="Times New Roman">BitScanInit()</FONT>函数初始化。
<DT>
<DT><FONT face=Arial size=4><STRONG>10.8 96</STRONG></FONT><FONT
face=楷体_GB2312 size=4><STRONG>位位棋盘</STRONG></FONT><FONT face=Arial
size=4><STRONG>(bitboard.h)</STRONG></FONT>
<DT>
<DT> 尽管<FONT face="Times New Roman">ElephantEye</FONT>没有使用位棋盘,但位棋盘<FONT
face="Times New Roman">(BitBoard)</FONT>仍然是一个富有活力的数据结构,为此<FONT
face="Times New Roman">ElephantEye</FONT>的源程序包里保留了位棋盘结构的描述,即<FONT
face="Times New Roman"><bitboard.h></FONT>。位棋盘的赋值、比较、位操作<FONT
face="Times New Roman">(</FONT>与或非等<FONT
face="Times New Roman">)</FONT>、位移、位搜索都由该文件来定义<FONT
face="Times New Roman">(</FONT>定义为内联函数的运算符<FONT
face="Times New Roman">)</FONT>,另外还有为“折叠位棋盘”<FONT
face="Times New Roman">(</FONT>专门处理蹩马腿和塞象眼的算法<FONT
face="Times New Roman">)</FONT>而设计的操作,即<FONT
face="Times New Roman">CheckSum()</FONT>和<FONT
face="Times New Roman">Duplicate()</FONT>函数。 </DT></DL>
<DIR>
<LI>上一篇 <A
href="http://www.elephantbase.net/computer/eleeye_evaluate.htm">中国象棋程序设计探索<FONT
face="Times New Roman">(</FONT>九<FONT face="Times New Roman">)</FONT>:局面评价函数</A>
<LI>下一篇
<LI>返 回 <A href="http://www.elephantbase.net/computer.htm">象棋百科全书——电脑象棋</A>
</LI></DIR>
<DIV align=center>
<CENTER>
<TABLE border=0>
<TBODY>
<TR>
<TD>
<P align=center><A href="http://www.elephantbase.net/" target=_blank><IMG
height=31 src="解剖大象的眼睛——中国象棋程序设计探索(十):实用程序片段_files/elephantbase.gif"
width=88 border=0></A></P></TD></TR>
<TR>
<TD><A href="http://www.elephantbase.net/" target=_blank><FONT face=Arial
size=2><STRONG>www.elephantbase.net</STRONG></FONT></A></TD></TR></TBODY></TABLE></CENTER></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -