对于子力打分和控制区域打分,只要遍历棋盘,当遇到棋子时简单地去查事先定义好的“子力价值表”和“控制区域价值表”,取出相对应的值进行累加即可(这些值的具体设定参考了前人的程序并作了适当的调整,今后仍应根据电脑下棋所反映出的实际问题对这些值作适当修改)。
对于机动性打分,需要求出各个子总共有多少种走法,然后根据各个子所不同的机动性价值每多一种走法就加一次相应的分数。
对棋子间相互关系的打分,我先定义了一个关系表的结构类型
typedef struct _relationtable{
BYTE nCChessID ;
int nUAttackCount ;
int nUGuardCount ;
BYTE UnderAttack[5];
BYTE UnderGurad[5];
} RelationTable;
RelationTable RelationOfMan[9][10]; // 关系表
其中nCChessID给出棋子的类型,nUAttackCount和nUGuardCount分别记录正攻击该子的棋子数量和正保护该子的棋子数量,UnderAttack[5]和UnderGuard[5]则存放攻击该子和保护该子的具体棋子(的类型)。因为考虑到实战中几乎不可能出现同时有超过五个棋子攻击/保护一个子的情况,故数组下标设定为5。
当遍历一遍棋盘之后,子力打分、控制区域打分和机动性打分都可以完成,而关系表也可以填完。之后,再根据关系表来具体考察棋子的相互关系,进行关系打分。
分析关系时,首先,对王的攻击保护应分离出来单独考虑,因为对王的保护没有任何意义,一旦王被吃掉整个游戏就结束了。
其次,对一个普通子,当它既受到攻击又受到保护的时候要注意如下几个问题:
1、攻击者子力小于被攻击者子力,攻击方将愿意换子。比如,一个车正遭受一个炮的攻击,那么任何对车的保护都将失去意义——对方肯定乐意用一个炮来换一个车。
2、多攻击\单保护的情况,并且攻击者最小子力小于被攻击者子力与保护者子力之和,则攻击方可能以一子换两子。
3、三攻击\两保护的情况,并且攻击者子力较小的二者之和小于被攻击者子力与保护者子力之和,则攻击方可能以两子换三子。
4、攻击方与保护方数量相同,并且攻击者子力小于被攻击者子力与保护者子力之和再减去保护者中最大子力,则攻击方可能以n子换n子。
当然,上述四条只是覆盖了最常见的几种情况,覆盖并不全面。而且,在我们的程序中并没有直接地重新考虑双方兑子之后的控制区域及机动性变化情况(之所以说没有“直接地重新考虑”,是因为搜索继续展开结点后仍会考虑这些因素,只是目前我们尚不知这样效果是否受影响——考察这两种方法在效果上的差异需要一定数量的试验数据的支持)。所以,如果今后要对引擎进行改进,提高程序的下棋水平的话,还应当在此多做文章……
7、程序组装
至此,我们已具备了实现一款中国象棋对弈程序引擎部分的所有要素,我将上述模块分别写作.h头文件。如下:
CChessDef.h
——象棋相关定义。包括棋盘局面和着法的表示。
CChessMove.h
——着法生成器。就当前局面生成某一方所有合法着法。
CChessSearch.h
——搜索部分。使用Alpha-Beta搜索求出最佳着法。
HistoryHeuristic.h
——历史启发。Alpha-Beta搜索之补充,以提高搜索效率。
SortMove.h
——着法排序。对着法按其历史得分进行降序排序,以提高搜索效率。
CChessEvaluate.h
——局面评估。为某一特定局面进行评分。
当实现了引擎部分的各要素时,程序的界面部分还尚未开工。因此我们暂时先建了一个Win32控制台项目(这是我们所最熟悉的,也是我们在课堂上一直用的),之后只要再添加一个.cpp文件负责接受用户的输入、调用搜索函数、显示搜索结果,便可简单的测试引擎了(我们采用输入着法的起点坐标和终点坐标的方式来传送用户走棋的信息。同样,程序显示计算机走棋的起点坐标和终点坐标来做出回应)。
此后,等到界面部分初步完成以后,引擎的上述各模块无需作任何改动,仍以.h头文件的形式加入界面工程,只要由界面中的某个.cpp文件调用搜索函数即可。这种连接方式实现起来非常简单,基本上不需要其它额外作业。
三、界面及程序辅助部分
1、界面基本框架
关于界面,我们建了一个基于对话框的MFC应用程序。之后主要工作都在对话框类的两个文件CChessUIDlg.h和CChessUIDlg.cpp下展开。
我们所写的代码主要分布于以下三大部分:
一、初始化部分
BOOL CCChessUIDlg::OnInitDialog()
{
}
OnInitDialog()负责的是对话框的初始化。我们把有关中国象棋的棋局初始化情况也放在了这里面。初始化的内容包括:
对引擎部分所用到的变量的初始化。包括对棋盘上的棋子位置进行初始化(棋盘数组的初始化),对搜索深度、当前走棋方标志、棋局是否结束标志等的初始化;
对棋盘、棋子的贴图位置(即棋盘、棋子在程序中实际显示位置)的初始化;
对程序辅助部分所用到的一些变量的初始化。包括对悔棋、还原队列的清空,棋盘、棋子样式的默认选择,下棋模式的默认选择,计时器显示的初始化,以及着法名称列表的初始化等。
二、绘图部分
void CCChessUIDlg::OnPaint()
{
}
OnPaint()函数负责的是程序界面的绘图。因此,在这里我们要完成棋盘、棋子的显示(如果用户选择了盲棋模式,则不进行棋子的绘图,而是在屏幕中央给出提示信息表明当前为盲棋模式),走棋起始位置和目标位置的提示框的显示。
由于我们的棋盘、棋子等都是以位图的形式给出的。所以在OnPaint()函数里我们做的工作主要都是在贴位图。
需要注意的是由于位图文件不能像GIF文件那样有透明的背景并且棋子是圆形的而位图文件只能是矩形的,所以如果直接贴图的话会在棋盘上留下一块白色的边框——棋子的背景。因此,要想让棋子文件的背景“隐藏”需要通过一些“与”和“异或”操作来屏蔽掉棋子的背景。
三、走棋部分(用户动作响应部分)
为WM_LBUTTONDOWN消息添加消息响应事件,可得到如下函数:
void CCChessUIDlg::OnLButtonDown(UINT nFlags,
首页 上一页 1 2 3 4 5 6 7 下一页 尾页 4/7/7
免费vc中国象棋软件(四)由毕业论文网(www.huoyuandh.com)会员上传。