📄 国际象棋程序设计(六):局面评估函数.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0057)http://www.elephantbase.net/computer/basic_evaluation.htm -->
<HTML><HEAD><TITLE>国际象棋程序设计(六):局面评估函数</TITLE>
<META http-equiv=Content-Type content="text/html; charset=gb_2312-80">
<META content="MSHTML 6.00.3790.2759" name=GENERATOR></HEAD>
<BODY link=#0000ff background=国际象棋程序设计(六):局面评估函数_files/background.gif>
<DL>
<DIV align=center>
<CENTER>
<DT><FONT face=隶书 size=6>国际象棋程序设计(六):局面评估函数</FONT> </CENTER></DT></DIV>
<DIV align=center>
<CENTER>
<DT> </CENTER></DT></DIV>
<DIV align=center>
<CENTER>
<DT><FONT face="Times New Roman">Fran</FONT>ç<FONT face="Times New Roman">ois
Dominic Laram</FONT>é<FONT face="Times New Roman">e/</FONT>文
</CENTER></DT></DIV>
<DT>
<DT> 已经六个月了,我知道你们有人觉得我不会闭嘴,但是你们错了,这是我的国际象棋程序设计连载的最后一篇。还有,我的<FONT
face="Times New Roman">Java</FONT>象棋程序<FONT
face="Times New Roman">(</FONT>看上去很烂<FONT
face="Times New Roman">)</FONT>已经做好了,和这篇文章一起上传给了<FONT
face="Times New Roman">GameDev</FONT>网站,这个程序还是可以验证这些连载内容的。
<DT> 这个月的话题——局面评估函数——确实很特别,搜索技术大同小异,着法产生可以只根据规则来处理,而局面的评估则需要很深入彻底的分析。可以想象,如果我们不知道某个局面会导致哪方获胜,那么评价这个局面的相对强弱将是不可能的。因此,很多要讨论概念对于其他游戏来说就不是这么回事了,有的则根本不能用。对于你自己的游戏,考虑用什么样的评估方法,这是你作为程序员应该知道的。<FONT
color=#0000ff>【译注:对于中国象棋要特别注意,很多概念不能从国际象棋照般,我写过《中国象棋和国际象棋比较研究》一文,详细阐述过这个问题。】</FONT>
<DT> 抓紧时间,让我们来看一些局面评价的尺度,并且需要了解它们有什么作用。
<DT>
<DT><FONT face=楷体_GB2312 size=5><B>子力平衡</B></FONT>
<DT>
<DT> 简单地说,子力平衡<FONT face="Times New Roman">(Material
Balance)</FONT>就是指双方各有哪些棋子。根据象棋文献,后的价值是<FONT
face="Times New Roman">900</FONT>分,车<FONT
face="Times New Roman">500</FONT>,象<FONT
face="Times New Roman">325</FONT>,马<FONT
face="Times New Roman">300</FONT>,兵<FONT
face="Times New Roman">100</FONT>,王是无价的。计算子力平衡是非常简单的,每方的子力价值就是:
<DIV align=center>
<CENTER></DIV>
<DT> </CENTER>
<DIV></DIV>
<DIV align=center>
<CENTER></DIV>
<DT><FONT face="Times New Roman">MB = Sum (Np x Vp)</FONT> </CENTER>
<DIV></DIV>
<DT>
<DT> 这里<FONT face="Times New Roman">Np</FONT>是棋盘上这种类型的子的数目,<FONT
face="Times New Roman">Vp</FONT>是子的价值。如果你在棋盘上的子力价值比对手多,那么你的形势好。<FONT
color=#0000ff>【说句提外话,外国人把“吃”说成“抓获”</FONT><FONT face="Times New Roman"
color=#0000ff>(Capture)</FONT><FONT
color=#0000ff>,意思是棋子并非消失了,而是暂时退出战场了,所以说子力价值时一定要强调“棋盘上”。】</FONT>
<DT> 看上去非常简单是不是?但是这和象棋的局面评价还差很大距离呢。<FONT face="Times New Roman">CHESS
4.5</FONT>的作者估计了很多位置上的因素,例如机动性和安全性差不多接近<FONT
face="Times New Roman">1.5</FONT>个兵。实际上,用不着考虑别的,这就足够可以下出好棋了。<FONT
color=#0000ff>【注意,在把“兵值”这个概念运用到中国象棋的时候,最好也把车设成</FONT><FONT
face="Times New Roman" color=#0000ff>500</FONT><FONT
color=#0000ff>,这时机动性和安全性的因素就可以参考国际象棋,也不超过</FONT><FONT face="Times New Roman"
color=#0000ff>150</FONT><FONT color=#0000ff>分。具体的子力价值可参考《</FONT><A
href="http://www.elephantbase.net/other/compare2.htm" target=_blank><FONT
color=#0000ff>中国象棋和国际象棋比较研究</FONT><FONT face="Times New Roman"
color=#0000ff>(</FONT><FONT color=#0000ff>二</FONT><FONT face="Times New Roman"
color=#0000ff>)</FONT><FONT color=#0000ff>——子力价值</FONT></A><FONT
color=#0000ff>》一文。】</FONT>
<DT> 的确,有些情况下为了通过子力交换让局面得到进展,你必须牺牲某些棋子<FONT
face="Times New Roman">(</FONT>甚至是后<FONT
face="Times New Roman">)</FONT>。然而最好是通过搜索来发现,例如弃后可以导致<FONT
face="Times New Roman">3</FONT>步杀,你的搜索函数不需要额外的代码就会找到杀棋<FONT
face="Times New Roman">(</FONT>前提是它看得足够深远<FONT
face="Times New Roman">)</FONT>。如果你硬是要在评价函数里写特别的代码,来确定是否应该弃子,这种事情将是噩梦。
<DT> 很少有程序会用像我开始所说的那个评价函数。由于计算过于简单,人们会在上面增加点东西,都是这么做的。举一个众所周知的例子,当你子力上处于领先时,交换相等的子力是有利的。交换一个兵是不错的选择,因为它为你的车开放棋盘,但是你必须在棋盘上保存一些兵直到残局,以构筑防御屏障或者升变成后。最后,如果开局库里走出弃子的开局,你不用为程序担心,因此你要把“藐视因子”<FONT
face="Times New Roman">(Contempt Factor)</FONT>加到子力平衡的评价中。例如当子力落后<FONT
face="Times New Roman">150</FONT>分甚至更多时,你仍然让程序觉得是领先的。
<DT> 要注意,子力平衡在象棋和西洋棋里具有很高的地位,但是在黑白棋里却是欺骗性的。的确,棋局最后你必须控制更多的格子才能赢,但是你最好在中局阶段控制子的个数。在其他游戏像五子棋<FONT
color=#0000ff>【</FONT><FONT face="Times New Roman"
color=#0000ff>Go-Moku</FONT><FONT
color=#0000ff>确实应该是五子棋,我想不出还有什么不吃子的黑白棋类了】</FONT>及其变种<FONT
face="Times New Roman"><I>N</I></FONT>子棋<FONT
face="Times New Roman">(Connect-<I>N</I>)</FONT><FONT
color=#0000ff>【具体怎么下我也不知道】</FONT>,子力平衡是不会变化的,因为始终没有被吃的子。
<DT>
<DT><FONT face=楷体_GB2312 size=5><B>机动性和对棋盘的控制</B></FONT>
<DT>
<DT> 将死的特征之一是没有合理的着法。直觉上,好像选择余地越大约好,比如选手在<FONT
face="Times New Roman">30</FONT>种着法内找出一步好棋,这种可能总要比限定在<FONT
face="Times New Roman">3</FONT>步内高。
<DT> 在象棋中,机动性是很好评估的 计算同一局面下每方的合理着法,你已经能做到了<FONT
color=#0000ff>【还要复习一下《</FONT><A
href="http://www.elephantbase.net/computer/basic_movegen.htm"
target=_blank><FONT color=#0000ff>着法的产生</FONT></A><FONT
color=#0000ff>》吗?】</FONT>。然而这个数字仅仅占一小部分。为什么呢?就因为很多着法是漫无目的的。例如你每次让车向后退一格,着法是合理的,但不产生作用。另外,不惜代价试图限制对手的机动性,会让程序进行一系列漫无目的的将军,同时摧毁自己的防线。由于解除将军通常只有<FONT
face="Times New Roman">3</FONT>到<FONT
face="Times New Roman">4</FONT>种合理着法,所以基于机动性的程序会走出劣着去将军对方,过会儿就会发现什么事也没干成,并且自己的兵力也成一盘散沙了。<FONT
color=#0000ff>【我认为这种结果的根源在于没有把将军着法考虑进“静态搜索”中,如果考虑进去了,那么将军的时候不做局面评价,根本不存在对手机动性很低的假象。】</FONT>
<DT> 但是,有些明智的机动性评估方法,会起点作用。我的程序就“坏象”给予罚分,即象的行动路线被一系列同色格的兵阻挡的情况,当马太靠近棋盘边缘时也同样处理。另一个例子是车,在开放或半开放线<FONT
face="Times New Roman">(</FONT>即没有兵或只有一个兵的纵线<FONT
face="Times New Roman">)</FONT>上价值更高。
<DT> 和机动性有密切联系的是棋盘的控制能力。在象棋中,如果一方对某个格子产生攻击的棋子数量超过对方,那么这一方就控制了这个格子。走到受控制的格子通常是安全的,走到被对方控制的格子则是危险的。<FONT
face="Times New Roman">(</FONT>有一些例外,把后走到被敌方兵攻击的格子里,不管你有多少子可以吃他的兵,这无论如何不是好主意。还有,你故意把子送到对方嘴里,但是对方有更重要的格子需要保护。<FONT
face="Times New Roman">)</FONT>在象棋中,控制中心是开局的基本目标。但是,控制能力在某种程度上是很难计算的,它需要在任何时候都更新数据库,来记录棋盘上所有被攻击的格子。很多程序都这么做,但我的没有。
<DT> 机动性对于象棋程序来说并不是非常重要的,但在黑白棋里却非常重要<FONT
face="Times New Roman">(</FONT>在残局中有很少子可走的一方会陷入很深的困境<FONT
face="Times New Roman">)</FONT>。而对围棋而言,对棋盘的控制则是胜利的标致。
<DT>
<DT><FONT face=楷体_GB2312 size=5><B>局势发展</B></FONT>
<DT>
<DT> 有个教条,下象棋时轻子<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>,形成巨大的破坏力。
<DT> 我的程序用了一些因子来衡量局势的发展。首先,任何王和后前没有动过的兵都要扣分,阻挡车的马和象也要扣分,这样可以让后在其他子力出动后才开始动,如果对手还有后,那么王易位到安全位置时则给予很大的加分<FONT
face="Times New Roman">(</FONT>有易位权但是没有易位的也给予少量加分<FONT
face="Times New Roman">)</FONT>。
<DT> 你可以看到,局势发展的因素在开局阶段很重要,但是马上将失去意义。在大约<FONT
face="Times New Roman">10</FONT>回合以后,要衡量的因素基本上都发生过了<FONT
color=#0000ff>【即能加分的都加了,要扣分的都扣了】</FONT>。
<DT> 注意,在西洋棋之类的游戏中,倾向于局势发展可能很不好。事实上,先走的一方要空出后面一行的空位,这就已经吃亏了,而在这些地方避免局势发展,通常是不错的选择。
<DT>
<DT><FONT face=楷体_GB2312 size=5><B>兵形</B></FONT>
<DT>
<DT> 象棋大师门常说,兵是象棋的灵魂。因此新手很难体会的是,强手在对局时会因为一个兵的损失而早早认输。
<DT> 象棋书籍中提到很多兵的类型,有些是有利的,有些是有害的。我的程序考虑了以下几点。
<DT> <FONT face="Times New Roman">1.
</FONT>叠兵或三叠兵,一方两个或多个兵在同一列上是很坏的,因为它们的移动相互阻碍了;
<DT> <FONT face="Times New Roman">2. </FONT>对兵,双方两个兵“头碰头”互相阻挡去路,会造成很大的障碍;
<DT> <FONT face="Times New Roman">3. </FONT>通路兵,当兵进展到不会有对方兵攻击或阻碍时<FONT
color=#0000ff>【即同一列和相邻列里都不能有对方的兵】</FONT>,就会变得非常强大,因为它们更容易到达底线实现升变;
<DT> <FONT face="Times New Roman">4. </FONT>孤兵,两边都没有同伴兵保护的兵,最容易受到攻击,最需要寻求保护;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -