{
m_nCurrentPosition+=m_nStep; return CProgressCtrl::StepIt();
以下介绍如何对列表框控件(List Box)进行操作,以显示或删除着法名称。 首先,在ChessDlg下定义以下函数:
this->GetMoveStr(nFromX,nFromY,nToX,nToY,nSourceID); //用来获得刚下的一步棋的走法;
void CChessDlg::AddChessRecord(int nFromX,int nFromY,int nToX,int nToY,int nUserChessColor,int nSourceID) //将走法添加进下棋记录; 然后,显示在Listbox中。
当列表框中的项的数目超过列表框的显示范围时,列表框会自动添加垂直滚动条(前提是其VerticalScrollbar属性要为True——该属性默认即为True)。但是显示的内容依然是最早加进来的项。在控件属性里选择Vertical Scroll,使得列表框可垂直滚动以显示最新的着法名称。
想要从列表框中删除项时,可以使用
m_lstChessRecord.DeleteString(m_lstChessRecord.GetCount()-1);减一之后正好是最后一项的行号。 3.4 胜败判定
胜负判定只要一方将另一方的将或帅吃掉就是胜者。 主要代码如下:
int CSearchEngine::IsGameOver(BYTE position[][9], int nDepth) {
}
int i,j;
BOOL RedLive=FALSE,BlackLive=FALSE; //检查红方九宫是否有帅 for(i=7;i<10;i++)
for(j=3;j<6;j++) {
if(position[i][j]==B_KING)
BlackLive=TRUE;
14
}
if(position[i][j]==R_KING) RedLive=TRUE;
//检查黑方九宫是否有将 for(i=0;i<3;i++)
for(j=3;j<6;j++) {
if(position[i][j]==B_KING)
BlackLive=TRUE; RedLive=TRUE;
if(position[i][j]==R_KING)
}
i=(m_nMaxDepth-nDepth+1)%2;//取当前奇偶标志,奇数层为电脑方,偶数层为用户
方。 }
//红方不在 if(!RedLive)
if(i)
return 19990+nDepth; //奇数层返回极大值
else
return -19990-nDepth;//偶数层返回极小值
//黑方不在 if(!BlackLive)
if(i)
return -19990-nDepth;//奇数层返回极小值
else
return 19990+nDepth; //偶数层返回极大值
return 0;//将帅都在,返回0
4 界面设计和系统实现
4.1 界面设计
关于棋盘和棋子,建了一个基于对话框的MFC应用程序。主要工作都在对话框类的两个文件CChessDlg.h和CChessDlg.cpp下展开。
15
代码主要分布于以下三大部分: 1、初始化部分
BOOL CCChessUIDlg::OnInitDialog() { }
OnInitDialog()负责的是对话框的初始化。可以把有关中国象棋的棋局初始化情况也放在了这里面。初始化的内容包括:
对引擎部分所用到的变量的初始化。包括对棋盘上的棋子位置进行初始化(棋盘数组的初始化),对搜索深度、当前走棋方标志、棋局是否结束标志等的初始化;
对棋盘、棋子的贴图位置(即棋盘、棋子在程序中实际显示位置)的初始化; 对程序辅助部分所用到的一些变量的初始化。包括对悔棋、还原队列的清空,棋盘、棋子样式的默认形式,下棋模式的默认选择,以及着法名称列表的初始化等。
2、绘图部分
void CCChessUIDlg::OnPaint() { …… }
OnPaint()函数负责的是程序界面的绘图。因此,在这里将要完成棋盘、棋子的显示走棋起始位置和目标位置的提示框的显示。
由于棋盘、棋子等都是以位图的形式给出的。所以在OnPaint()函数里做的工作主要都是在贴位图。
需要注意的是由于位图文件不能像GIF文件那样有透明的背景并且棋子是圆形的而位图文件只能是矩形的,所以如果直接贴图的话会在棋盘上留下一块白色的边框——棋子的背景。因此,要想让棋子文件的背景“隐藏”需要通过一些“与”和“异或”操作来屏蔽掉棋子的背景。
3、走棋部分(用户动作响应部分)
为WM_LBUTTONDOWN消息添加消息响应事件,可得到如下函数:
void CCChessUIDlg::OnLButtonDown(UINT nFlags, CPoint point) { …… }
16
当用户在窗口客户区按下鼠标左键时,程序就会调用OnLButtonDown(UINT nFlags, CPoint point)函数来进行响应。其中第二个参数CPoint point是在本程序中所要用到的,它给出了当鼠标左键被按下时,鼠标指针的位置坐标。可以通过这一信息来得知用户的走法。
在OnLButtonDown函数里处理如下两种操作:
1、如果用户点击鼠标的位置落在己方的棋子上,表示用户选中了该棋子,下一步将移动该子进行走棋(也可能用户下一步将会选择己方另外的棋子,总之这一操作会记录下用户所选的将要走的棋子)。
2、如果之前用户已经选过了棋子,那么这一次的点击(如果不是另选本方的其它棋子的话)表达了用户的一次走棋过程。在收到用户传达的走棋信息后,可先判断该着法是否合法(是否符合中国象棋的游戏规则),如果合法,则执行之。紧接着调用引擎的搜索函数计算出计算机对用户着法的应着,然后执行该应着。
如此,在OnLButtonDown函数里,实现了人与机器的对弈(当然每走一步棋,也还需要绘图函数来显示棋盘局面的更新)。
以上三部分并非界面程序的全部,而仅仅是与程序密切相关的部分。此外还有其它部分对程序同样必不可少,但这些部分主要由MFC自动生成,无需人为改动,故在此不多做介绍。 4.2 系统实现
现在已具备了实现一款中国象棋对弈程序引擎部分的所有要素,将上述模块分别写作.h头文件。如下:
ChessDlg.h
——象棋相关定义。包括棋盘局面和着法的表示。 BaseClasses.h
——着法生成器。就当前局面生成某一方所有合法着法。 MoveList.h
——搜索部分。使用搜索求出最佳着法。 Thinkdef.h
——历史启发。Alpha-Beta搜索之补充,以提高搜索效率。 Thinker.h
——着法排序。对着法按其历史得分进行降序排序,以提高搜索效率。 ThinkOptionDlg.h
17
——局面评估。为某一特定局面进行评分。
当实现了引擎部分的各要素时,可先建立一个Win32控制台项目,之后只要再添加一个.cpp文件负责接受用户的输入、调用搜索函数、显示搜索结果,便可简单的测试引擎了(采用输入着法的起点坐标和终点坐标的方式来传送用户走棋的信息。同样,程序显示计算机走棋的起点坐标和终点坐标来做出回应)。
此后,等到界面部分初步完成,引擎的上述各模块无需作任何改动,仍以.h头文件的形式加入界面工程,只要由界面中的某个.cpp文件调用搜索函数即可。这种连接方式实现起来非常简单。
首先,执行该软件,系统并不需要很高的配置,CPU在1.5G以上,内存在512M以上就可以很流畅地执行。下面简单介绍一下象棋相关规则:
对局时,由执红棋的一方先走,双方轮流各走一着,直至分出胜、负、和,对局即终了。轮到走棋的一方,将某个棋子从一个交叉点走到另一个交叉点,或者吃掉对方的棋子而占领其交叉点,都算走一着。双方各走一着,称为一个回合。如果有一方的主帅被对方吃了,就算那一方输。
各种棋子的走法:
帅(将):帅和将是棋中的首脑,是双方竭力争夺的目标。它只能在“九宫”之内活动,可上可下,可左可右,每次走动只能按竖线或横线走动一格。帅与将不能在同一直线上直接对面,否则走方判负。
仕(士):仕(士)是帅(将)的贴身保镖,它也只能在九宫内走动。它的行棋路径只能是九宫内的斜线。
相(象):相(象)的主要作用是防守,保护自己的帅(将)。它的走法是每次循对角线走两格,俗称“象走田”。相(象)的活动范围限于“河界”以内的本方阵地,不能过河,且如果它走的“田”字中央有一个棋子,就不能走,俗称“塞象眼”。
车:车在象棋中威力最大,无论横线、竖线均可行走,只要无子阻拦,步数不受限制。因此,一车可以控制十七个点,故有“一车十子寒”之称。
炮:炮在不吃子的时候,走动与车完全相同。
马:马走动的方法是一直一斜,即先横着或直着走一格,然后再斜着走一个对角线,俗称“马走日”。马一次可走的选择点可以达到四周的八个点,故有“八面威风”之说。如果在要去的方向有别的棋子挡住,马就无法走过去,俗称“蹩马腿”。
兵(卒):兵(卒)在未过河前,只能向前一步步走,过河以后,除不能后退外,允
18
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库中国象棋游戏的设计与实现-毕业设计(4)在线全文阅读。
相关推荐: