认证主体:李**(实名认证)
IP属地:安徽
下载本文档
1、毕业设 计中国象棋游戏的设计与实现摘要中国象棋发展至今已有数千年的历史了,它是中华民族智慧的结晶。在我国,中国象棋的普与程度是其它棋类无法比拟的,大至国际、国比赛,小至社区街道。如今,仅中国就有2亿人会下中国象棋,且中国象棋的发展趋势日益国际化。本文首先研究了中国象棋在计算机中的表示问题,讨论如何产生着法等一系列相关容,其次研究了博弈树的搜索技术与在此基础上发展起来的相关剪枝算法。系统使用MFC文档视图体系结构和Visual C+开发工具,实现了一个具有一定棋力的中国象棋人机对弈程序。此博弈程序实现了人机博弈,悔棋,电脑难度设置,着法名称生成等功能。关键词:中国象棋人工智能博弈树Alpha-B
2、eta搜索25 / 27目 录1 前言11.1中国象棋游戏设计背景和研究意义11.2国外象棋软件发展概况11.3中国象棋游戏设计研究方法11.4本文的主要工作22棋局表示和着法生成22.1棋盘和棋子的表示22.2着法生成43走棋和博弈程序的实现53.1博弈程序的实现53.1.1搜索算法53.1.2着法排序83.1.3局面评估93.2悔棋和还原功能的实现113.3着法名称显示功能的实现123.4胜败判定144界面设计和系统实现154.1界面设计154.2系统实现175总结21参考文献23ABSTRACT24致 25仲恺农业工程学院毕业论文(设计)成绩评定表261 前言1.1 中国象棋游戏设计背景
3、和研究意义中国象棋游戏流传至今已经有数千年的历史了,是一种古老的文化,它集文化、科学、艺术、竞技于一体,有利于开发人的智慧,锻炼人的思维,培养人的毅力,增强人的竞争意识。自从计算机发明,向各个领域发展,到成为我们现在每天工作和生活必不可少的一部分的这个过程中,电子游戏也逐步渗入我们每个人的娱乐活动中。在计算机已经普与的今天,对于可以用计算机进行程序编辑的人来说,开发属于自己的游戏,已经不再是梦想,中国象棋历史悠久不仅源远流长,而且基础广泛,作为一项智力运动更成为我们游戏开发的首选对象。中国象棋是一项智力游戏,以往都是人和人下棋,现在有了计算机我们可以和计算机竞技,人可以与计算机进行对弈。控制计
4、算机的是人类,而人工智能是综合性很强的一门边缘学科,它的中心任务是研究如何使计算机去做那些过去只能靠人的智力才能做的工作。因此,对游戏开发过程中的人工智能技术的研究自然也就成了业界的一个热门研究方向。 1.2 国外象棋软件发展概况最早的象棋软件是一副可以外出携带的电子棋盘,后来升级到电视游戏机。开始出现的一些容量很小的象棋软件如:DOS界面将族、WIN31程序的中国象棋等等,与其说人类下不过电脑,倒不如说是没有耐性等待电脑程序慢吞吞的搜索算法,有时甚至怀疑软件是否在搜索中死掉了。后来,网络上先后出现了真正的WINDOWS窗口界面的象棋专业高级软件棋隐、象棋世家、象棋参谋、象棋奇兵等。总而言之,
5、各类象棋软件既有自身的优点,也存在共通性的缺陷,如:中局审势不够智能化,走不出弃子取势的人性化佳构,残局时智力明显低于人脑,难以走出残局例胜的必然着法等。放眼未来,象棋软件已经走完了一波持续上涨的行情,有可能出现逐步降温的滑坡趋势。1.3 中国象棋游戏设计研究方法本系统主要用 Visual C+ 进行开发,里面的MFC类库,使游戏开发更加方便,并利用人工智能相关搜索算法实现人工智能的着法生成,从而完善整个游戏的功能。该象棋人机博弈系统实现的功能主要包括:1、选手选择(人或电脑);2、人机对弈(人与电脑竞技);3、电脑棋力难度选择(电脑下棋能力难度选择,共有4级:按电脑配置选择难度);4、悔棋、
6、还原;5、着法名称显示(象棋走棋规名称)。1.4 本文的主要工作第一部分主要介绍了中国象棋游戏开发的背景与意义、国外象棋软件的发展概况和象棋游戏的设计研究方法;第二部分介绍了棋局表示方法和着法生成;第三部分介绍了走棋和博弈程序的实现;第四部分介绍了界面设计和系统的实现。2 棋局表示和着法生成2.1 棋盘和棋子的表示对于中国象棋棋盘局面的表示可采用传统而简单的“棋盘数组”。即用一个9*10的数组来存储棋盘上的信息,数组的每个元素存储棋盘上是否有棋子。这种表示方法简单易行。按此方法棋盘的初始情形如下所示:BYTE CChessBoard910 = R, 0, 0, P, 0, 0, p, 0, 0
7、, r,H, 0, C, 0, 0, 0, 0, c, 0, h,E, 0, 0, P, 0, 0, p, 0, 0, e,A, 0, 0, 0, 0, 0, 0, 0, 0, a,K, 0, 0, P, 0, 0, p, 0, 0, k,A, 0, 0, 0, 0, 0, 0, 0, 0, a,E, 0, 0, P, 0, 0, p, 0, 0, e,H, 0, C, 0, 0, 0, 0, c, 0, h,R, 0, 0, P, 0, 0, p, 0, 0, r;给所有棋子定义一个值:#define R_BEGIN R_KING#define R_END R_PAWN#define B_B
8、EGIN B_KING#define B_END B_PAWN#define NOCHESS 0 /没有棋子黑方:#define B_KING 1 /黑帅#define B_CAR2 /黑车#define B_HORSE3 /黑马#define B_CANON 4 /黑炮#define B_BISHOP 5 /黑士#define B_ELEPHANT 6 /黑象#define B_PAWN 7 /黑卒红方:#define R_KING 8 /红将#define R_CAR 9 /红车#define R_HORSE 10/红马#define R_CANON 11/红炮#define R_BISH
9、OP 12/红士#define R_ELEPHANT 13/红相#define R_PAWN 14/红兵判断颜色:#define IsBlack(x) (x>=B_BEGIN && x<=B_END)/判断某个棋子是不是黑色#define IsRed(x) (x>=R_BEGIN && x<=R_END)/判断某个棋子是不是红色对于着法的表示,直接借用棋盘数组的下标来记录着法的起点和目标点。至于是什么棋子在走,以与是否吃子、吃的是什么子,在着法结构中并不记录。这些信息由外部读取棋盘上起点、终点的数据获得。着法结构定义如下,其中还包含了对着
10、法的历史得分的记录项,以供后面要讲到的“历史启发”所用。typedef structshort nChessID; /表明是什么棋子CHESSMANPOS From;/起始位置CHESSMANPOS To; /走到什么位置int Score; /走法的分数CHESSMOVE; 有了对棋盘局面和着法的表示之后,程序才能够完成以下操作: 生成所有合法着法; 执行着法、撤销着法; 针对某一局面进行评估。 因而,棋局表示好比是整个程序(计算机下棋引擎部分)的地基,之后所有的操作都将建立在其基础上。2.2 着法生成在着法生成器中,采用的基本思想就是遍历整个棋盘(一个接一个地查看棋盘上的每个位置点),当发
11、现有当前下棋方的棋子时先判断它是何种类型的棋子,然后根据其棋子类型而相应地找出其所有合法着法并存入着法队列。这里谈到的“合法着法”包括以下几点:1、各棋子按其行子规则行子。诸如马跳“日”字、象走“田”字、士在九宫斜行等等(这里需要特别注意的是卒(兵)的行子规则会随其所在位置的不同而发生变化过河后可以左右平移)。2、行子不能越出棋盘的界限。当然所有棋子都不能走到棋盘的外面,同时某些特定的棋子还有自己的行棋界限,如将、士不能出九宫,象不能过河。3、行子的半路上不能有其它子阻拦(除了炮需要隔一个子才能打子之外)以与行子的目的点不能有本方的棋子(当然不能自己吃自己了)。4、将帅不能碰面(本程序中只在生
12、成计算机的着法时认为将帅碰面是非法的,而对用户所走的导致将帅碰面的着法并不认为其非法,而只是产生败局罢了)。产生了着法后要将其存入着法队列以供搜索之用,由于搜索会搜索多层(即考虑双方你来我往好几步,这样才有利于对局面进行评估以尽可能避免“目光短浅”),所以在把着法存入着法队列的时候还要同时存储该着法所属的搜索层数。因此可以将着法队列定义为二维数组m_MoveList870,其中第一个数组下标为层数,第二个数组下标为每一层的全部着法数。关于搜索层数,设定为4,实际使用的是1到3(在界面中将其限定为13)。搜索层数的增加会显著提高电脑的下棋水平(当然计算机的棋力在很大程度上也依赖于局面评估)。在配
13、置为1.5G,512M存的计算机上最多只能搜索3层,再多将导致搜索时间达到令人无法容忍的地步(这里还需要特别说明的是,搜索的速度也和着法生成的效率以与局面评估的复杂度有关,因为每分析一个结点都要执行这两种操作)。对于每一层的着法数,也就是当前下棋方针对当前局面的所有可选的合法着法,据有关数据统计在象棋实战中一般最多情况下也就五六十种。定义第二个数组下标为70,应当可以保证十分的安全。3 走棋和博弈程序的实现3.1 博弈程序的实现3.1.1 搜索算法搜索算法对于整个下棋引擎来说都是至关重要的。它如同程序的心脏,驱动着整个程序。搜索算法的好坏直接影响着程序执行的效率(从某种角度上,它影响着计算机的
14、下棋水平。因为,计算机必须在有限的时间完成思考,搜索速度快意味着在一样的时间程序可以“看”得更远,“想”的更多)。关于棋类对弈程序中的搜索算法,已有成熟的Alpha-Beta搜索算法以与其它一些辅助增强算法(还有众多基于Alpha-Beta算法的派生、变种算法)。我们在程序中直接借鉴了Alpha-Beta搜索算法并辅以历史启发。本节先介绍Alpha-Beta搜索算法:在中国象棋里,双方棋手获得一样的棋盘信息。他们轮流走棋,目的就是吃掉对方的将或帅,或者避免自己的将或帅被吃。表示红方走棋表示黑方走棋图1博弈树又此,可以用一棵“博弈树”(图1)来表示下棋的过程树中每一个结点代表棋盘上的一个局面,对
15、每一个局面(结点)根据不同的走法又产生不同的局面(生出新的结点),如此不断进行下去直到再无可选择的走法,即到达叶子结点(棋局结束)。中国象棋的博弈树的模型大概如下图所示,可以把其中连接结点的线段看作是着法,不同的着法自然产生不同的局面。该树包含三种类型的结点:1、奇数层的中间结点(以与根结点),表示轮到红方走棋;2、偶数层的中间结点,表示轮到黑方走棋;3、叶子结点,表示棋局结束。现在让计算机来下中国象棋,它应当选择一步对它最有利的着法(最终导致它取胜的着法)。获得最佳着法的方法就是“试走”每一种可能的着法,比较它们所产生的不同后果,然后从中选出能够产生对自己最有利的局面的着法。结合上面所讲的博
16、弈树,若给每个结点都打一个分值来评价其对应的局面(这一任务由后面所讲的局面评估来完成),那么可以通过比较该分值的大小来判断局面的优劣。假定甲乙两方下棋,甲胜的局面是一个极大值(一个很大的正数),那么乙胜的局面就是一个极小值(极大值的负值),和棋的局面则是零值(或是接近零的值)。如此,当轮到甲走棋时他会尽可能地让局面上的分值大,相反轮到乙走棋时他会选尽可能地让局面上的分值小。反映到博弈树上,即如果假设奇数层表示轮到甲方走棋,偶数层表示轮到乙方走棋。那么由于甲方希望棋盘上的分值尽可能大,则在偶数层上会挑选分值最大的结点偶数层的结点是甲走完一步棋之后的棋盘局面,反映了甲方对棋局形势的要求。同样道理,
17、由于乙方希望棋盘上的分值尽可能小,那么在奇数层上会选择分值最小的结点。这是“最小-最大”(Minimax)的基本思想。这样搜索函数在估值函数的协助下可以通过在奇数层选择分值最大(最小)的结点,在偶数层选择分值最小(最大)的结点的方式来搜索以当前局面为根结点、限定搜索层数以的整棵树来获得一个最佳的着法。然而不幸的是,博弈树相当庞大(它会成指数增长),因而搜索(限定层数以的)整棵树是一件相当费时的工作其时间复杂度为O(bn)。其中b是分枝因子,即针对各种局面的合法着法的数目的平均值,n是搜索的深度。对于中国象棋而言,在中盘时平均着法数目大约是40种左右,那么搜索4层需要检查250万条路线,搜索5层
18、需要检查1亿条路线,搜索6层需要检查40亿条路线!Alpha-Beta搜索能在不影响搜索精度的前提下大幅减少工作量。因为,如果考虑到下棋是一个你来我往的交替进行并且相互“较劲”的过程。由于每一方都会尽可能将局面导向对自己有利而对对方不利的方向(假定下棋双方对棋局有着同样的认知,即你认为对你很糟糕的局面,在你的对手看来则是对他很有利的局面),那么某些局面由于能够产生出很糟糕的局面因而根本没有再继续考虑的价值。所以当你看到某个局面有可能产生很糟糕的局面时(确切地说这里的“很糟糕”是与之前分析的情况相比较而言的),你应当立刻停止对其剩余子结点的分析不要对它再抱任何幻想了,如果你选择了它,那么你必将得
19、到那个很糟糕的局面,甚至可能更糟。这样一来便可以在很大程度上减少搜索的工作量,提高搜索效率,这称为“树的裁剪”。下面用图来进一步说明“树的裁剪”。为了简便起见,将博弈树进行了简化每个结点只有三个分支,实际情况中,刚才讲过在盘中应有大约40个分支。假定棋盘上的局面发展到了结点A(图2),现在轮到你走棋了,你是“最大的一方”即你希望棋局的分值尽可能的高。用搜索两层来看一看“树的裁剪”对提高搜索效率的帮助。图中表示该结点要取子结点中的最大值;表示该结点要取子结点中的最小值。ACDB-8-210-8?2图2树的裁剪首先,考察结点A的子结点B。结点B所属的这一层是轮到你的对手“最小者”来走棋了,目的是使
20、得棋局的分值尽可能的小。依次考察结点B的各个子结点,查看它们的分值(因为事先约定好了搜索两层,现在已达到搜索深度的要求了,所以就停下来调用局面评估函数来给它打分)。结点B的第一个子结点(从左到右算起)返回-8,第二个子结点返回了-2,第三个子结点返回了2。由于结点B这层是你的对手来做选择,假设他一定会做出明智的选择(你不能寄希望于你的对手会走出一步“昏招”),那么他会选择返回值为-2的那个结点。-2最终也就成了从结点B传递回的值,即倘若你(现在位于结点A)选择了产生结点B的走法,使得局面发展到了结点B。那么下一步,你的对手的选择就会使得棋局发展成为分值为-2的那个结点所表示的局面。再来分析结点
21、A的第二个子结点C,结点C与结点B同属一层,它依然是轮到你的对手作选择。依次查看结点C的各个子结点的分值,其第一个子结点返回了2。采用 “裁剪”方法。不必再继续考察结点C的剩余子结点了,因为结点C已经够糟糕的了,不管结点C的剩余子结点有怎样的分值,它最多只能传回-8(有可能其剩余子结点中还有分值更小的结点,因而结点C还有可能传回更小的值)。而与前面已经分析过的结点B所传回-2相比较,作为“最大一方”的你显然更不愿意看到2的局面。所以,你当然不会选择相应的着法使得局面发展成为结点C。因为那样的话,下一步你的对手就会带给你一个分值不高于2的局面。由此,在不影响搜索质量的前提下避免了搜索“无价值的”
22、结点C的剩余子结点的大量工作,从而节省了宝贵时间,为在同样机器配置下搜索更多的层数提供了可能。“最小-最大”的思想再加上“对树的裁剪”,这就是Alpha-Beta搜索算法的核心。最基本的Alpha-Beta算法的代码如下:int AlphaBeta(int depth, int alpha, int beta)if (depth = 0)/如果是叶子节点(到达搜索深度要求)return Evaluate();/则由局面评估函数返回估值GenerateLegalMoves();/产生所有合法着法while (MovesLeft()/遍历所有着法MakeNextMove();/执行着法int va
23、l = -AlphaBeta(depth - 1, -beta, -alpha); /递归调用UnmakeMove();/撤销着法if (val >= beta)/裁剪return beta;if (val > alpha)/保留最大值alpha = val;return alpha;3.1.2 着法排序Alpha-Beta搜索算法是在“最小-最大”的基础上引入“树的裁剪”的思想以期提高效率,它的效率将在很大程度上取决于树的结构如果搜索了没多久就发现可以进行“裁剪”了,那么需要分析的工作量将大大减少,效率自然也就大大提高;而如果直至分析了所有的可能性之后才能做出“裁剪”操作,那此时
25、增量以记录其“历史得分”,一个多次被搜索并认为是好的走法的“历史得分”就会较高。对于即将搜索的结点,按照“历史得分”的高低对它们进行排序,保证较好的走法(“历史得分”高的走法)排在前面,这样Alpha-Beta搜索就可以尽可能早地进行“裁剪”,从而保证了搜索的效率。对于着法的排序可以使用各种排序算法,在程序中采用了归并排序。归并排序的空间复杂度为O(n),时间复杂度为O(nlog2n),具有较高的效率。3.1.3 局面评估前文已经讲过了棋局表示、着法生成、搜索算法(包括搜索辅助“历史启发”), 在象棋程序中如果说搜索算法是心脏,那么局面评估就是大脑。搜索算法负责驱动整个程序,而局面评估则负责对
26、搜索的容进行判断和评价。因而搜索与局面评估是整个下棋引擎的核心。首先,先介绍一下在局面评估中需要考虑的因素。就不同的棋类可能要考虑的因素略有差异。在中国象棋中所要考虑的最基本的几个因素包括如下四点:1、子力总和子力是指某一棋子本身所具有的价值。通俗地讲就是一个棋子它值个什么价。例如,车值10的话,那可能马值6,卒值2等等。所以在评估局面时,首先要考虑双方的子力总和的对比。比如红方拥有士象全加车马炮,而黑方只有残士象加双马,则红方明显占优。2、棋子位置棋子位置,或称控制区域,是指某一方的棋子在棋盘上所占据(控制)的位置。例如,沉底炮、过河卒、以与车占士角等都是较好的棋子位置状态,而窝心马、将离开
27、底线等则属较差的棋子位置状态。3、棋子的机动性棋子的机动性指棋子的灵活度(可移动性)。例如,起始位置的车机动性较差,所以下棋讲究早出车。同样四面被憋马腿的死马机动性也较差(对于一步也不能走的棋子,可以认为其机动性为零)。4、棋子的相互关系这一点的分析较为复杂,因为一个棋子与其它子之间往往存在多重关系。如:一个马可能在对方的炮的攻击之下同时它又攻击着对方的车。在程序中,估值函数最后返回的是每一方的总分的差值,而各方的总分就是上面所提到的四个因素的打分的总和。对于子力打分和控制区域打分,只要遍历棋盘,当遇到棋子时简单地去查事先定义好的“子力价值表”和“控制区域价值表”,取出相对应的值进行累加即可。
28、对于机动性打分,需要求出各个子总共有多少种走法,然后根据各个子所不同的机动性价值每多一种走法就加一次相应的分数。 对棋子间相互关系的打分,要用到以下几个数据:int m_BaseValue15; /存放棋子基本价值int m_FlexValue15; /存放棋子灵活性分值short m_AttackPos109; /存放每一位置被威胁的信息BYTE m_GuardPos109; /存放每一位置被保护的信息BYTE m_FlexibilityPos109;/存放每一位置上棋子的灵活性分值int m_chessValue109; /存放每一位置上棋子的总价值其中计算机会进行所有棋子值的判断,Att
29、ackPos和GuardPos分别记录该棋子受到的威胁和被保护的值。当遍历一遍棋盘之后,子力打分、控制区域打分和机动性打分都可以完成,而关系表也可以填完。之后,再根据关系表来具体考察棋子的相互关系,进行关系打分。分析关系时,首先,对王的攻击保护应分离出来单独考虑,因为对王的保护没有任何意义,一旦王被吃掉整个游戏就结束了。其次,对一个普通子,当它既受到攻击又受到保护的时候要注意如下几个问题:1、攻击者子力小于被攻击者子力,攻击方将愿意换子。比如,一个车正遭受一个炮的攻击,那么任何对车的保护都将失去意义对方肯定乐意用一个炮来换一个车。2、多攻击/单保护的情况,并且攻击者最小子力小于被攻击者子力与保
30、护者子力之和,则攻击方可能以一子换两子。3、三攻击/两保护的情况,并且攻击者子力较小的二者之和小于被攻击者子力与保护者子力之和,则攻击方可能以两子换三子。4、攻击方与保护方数量一样,并且攻击者子力小于被攻击者子力与保护者子力之和再减去保护者中最大子力,则攻击方可能以n子换n子。当然,上述四条只是覆盖了最常见的几种情况,覆盖并不全面。而且,在程序中并没有直接地重新考虑双方兑子之后的控制区域与机动性变化情况(之所以说没有“直接地重新考虑”,是因为搜索继续展开结点后仍会考虑这些因素,只是目前不知这样效果是否受影响考察这两种方法在效果上的差异需要一定数量的试验数据的支持)。所以,如果今后要对引擎进行改
31、进,提高程序的下棋水平的话,还应当在此进行研究。3.2 悔棋和还原功能的实现悔棋和还原是棋类软件中较为基本的功能。要实现悔棋和还原功能,首先要明确哪些信息应当被保存以供悔棋和还原所使用。在程序中保存了如下信息:棋局表示中所定义的棋盘数组;各棋子的贴图位置;这里需要特别说明的是通常象棋程序处于程序效率的考虑并不保存所有棋子的信息,而只是保存之前一步的走棋信息。此后当悔棋的时候,需要撤销着法;还原的时候,需要执行着法。然而,在编写自己的程序时一来考虑到程序的可读性和不易出错性,二来考虑到对当今的计算机的配置来说这点开销基本上不会对程序的效率产生什么影响。因此保存了全部棋子的信息。根据所要保存的数据
32、定义了如下基本结构类型:typedef structCHESSMOVE cmChessMove;short nChessID;/被吃掉的棋子UNDOMOVE;在对弈过程中,每一回合都将棋局信息(这里指前面所说的需要保存的信息)保存至走法队列,以供悔棋所用。还原功能是与悔棋功能相对应的,只有当产生了悔棋功能之后,还原功能才会被激活。一个回合的结束意味着前一次操作没有悔棋功能的产生,因此还原队列也应被清空。在悔棋中主要完成了以下任务:1、下棋回合数减一;2、将当前局面信息保存至走法队列,以供还原所用;3、从走法队列中取出上一回合的棋局信息,恢复到当前局面,然后将其从队列中剔除掉;4、将显示着法名称
33、的列表框中的本回合的着法名称保存到一个着法名称队列,以供还原所用。然后从列表框中删除它。而在还原中所做的刚好和悔棋相反:1、下棋回合数加一;2、将当前局面信息保存至队列,以供悔棋所用;3、从队列中取出最近一次悔棋前的棋局信息,恢复到当前局面,然后将其从队列中剔除;4、从走法队列中取出最近一次存入的着法名称(两项,因为每回合会产生两步着法),将其重新显示到列表框中。然后将其从中剔除。以上便是悔棋和还原功能所完成的具体操作,其代码分别写入悔棋和还原按钮(Button)的事件处理函数中。3.3 着法名称显示功能的实现每当下棋者(用户或是计算机)走一步棋,在棋盘旁边的一个列表框控件(List Box)
34、中按照中国象棋关于着法描述的规要求显示出该着法的名称。如:炮八进四、马二进三此类。为了获得该着法名称,我们编写了一个函数,其功能就是将被移动的棋子类型以与走法的起点坐标、终点坐标这些信息转换成中国象棋所规的着法名称。实现此功能代码如下:void CGradientProgressCtrl:OnPaint() CPaintDC dc(this); / device context for painting/ TODO: Add your message handler code hereif(m_nCurrentPosition<=m_nLower | m_nCurrentPosition
38、=nPos;return (CProgressCtrl:SetPos(nPos);int CGradientProgressCtrl:StepIt()m_nCurrentPosition+=m_nStep;return CProgressCtrl:StepIt();以下介绍如何对列表框控件(List Box)进行操作,以显示或删除着法名称。首先,在ChessDlg下定义以下函数:this->GetMoveStr(nFromX,nFromY,nToX,nToY,nSourceID);/用来获得刚下的一步棋的走法;void CChessDlg:AddChessRecord(int nFrom
40、unt()-1);减一之后正好是最后一项的行号。3.4 胜败判定胜负判定只要一方将另一方的将或帅吃掉就是胜者。主要代码如下:int CSearchEngine:IsGameOver(BYTE position9, int nDepth)int i,j;BOOL RedLive=FALSE,BlackLive=FALSE;/检查红方九宫是否有帅for(i=7;i<10;i+)for(j=3;j<6;j+)if(positionij=B_KING)BlackLive=TRUE;if(positionij=R_KING)RedLive=TRUE;/检查黑方九宫是否有将for(i=0;i&
41、lt;3;i+)for(j=3;j<6;j+)if(positionij=B_KING)BlackLive=TRUE;if(positionij=R_KING)RedLive=TRUE;i=(m_nMaxDepth-nDepth+1)%2;/取当前奇偶标志,奇数层为电脑方,偶数层为用户方。/红方不在if(!RedLive)if(i)return 19990+nDepth; /奇数层返回极大值elsereturn -19990-nDepth;/偶数层返回极小值/黑方不在if(!BlackLive)if(i)return -19990-nDepth;/奇数层返回极小值elsereturn 1
43、是否结束标志等的初始化;对棋盘、棋子的贴图位置(即棋盘、棋子在程序中实际显示位置)的初始化;对程序辅助部分所用到的一些变量的初始化。包括对悔棋、还原队列的清空,棋盘、棋子样式的默认形式,下棋模式的默认选择,以与着法名称列表的初始化等。2、绘图部分void CCChessUIDlg:OnPaint() OnPaint()函数负责的是程序界面的绘图。因此,在这里将要完成棋盘、棋子的显示走棋起始位置和目标位置的提示框的显示。由于棋盘、棋子等都是以位图的形式给出的。所以在OnPaint()函数里做的工作主要都是在贴位图。需要注意的是由于位图文件不能像GIF文件那样有透明的背景并且棋子是圆形的而位图文件
44、只能是矩形的,所以如果直接贴图的话会在棋盘上留下一块白色的边框棋子的背景。因此,要想让棋子文件的背景“隐藏”需要通过一些“与”和“异或”操作来屏蔽掉棋子的背景。3、走棋部分(用户动作响应部分)为WM_LBUTTONDOWN消息添加消息响应事件,可得到如下函数:void CCChessUIDlg:OnLButtonDown(UINT nFlags, CPoint point)当用户在窗口客户区按下鼠标左键时,程序就会调用OnLButtonDown(UINT nFlags, CPoint point)函数来进行响应。其中第二个参数CPoint point是在本程序中所要用到的,它给出了当鼠标左键被
45、按下时,鼠标指针的位置坐标。可以通过这一信息来得知用户的走法。在OnLButtonDown函数里处理如下两种操作:1、如果用户点击鼠标的位置落在己方的棋子上,表示用户选中了该棋子,下一步将移动该子进行走棋(也可能用户下一步将会选择己方另外的棋子,总之这一操作会记录下用户所选的将要走的棋子)。2、如果之前用户已经选过了棋子,那么这一次的点击(如果不是另选本方的其它棋子的话)表达了用户的一次走棋过程。在收到用户传达的走棋信息后,可先判断该着法是否合法(是否符合中国象棋的游戏规则),如果合法,则执行之。紧接着调用引擎的搜索函数计算出计算机对用户着法的应着,然后执行该应着。如此,在OnLButtonD
46、own函数里,实现了人与机器的对弈(当然每走一步棋,也还需要绘图函数来显示棋盘局面的更新)。以上三部分并非界面程序的全部,而仅仅是与程序密切相关的部分。此外还有其它部分对程序同样必不可少,但这些部分主要由MFC自动生成,无需人为改动,故在此不多做介绍。4.2 系统实现现在已具备了实现一款中国象棋对弈程序引擎部分的所有要素,将上述模块分别写作.h头文件。如下:ChessDlg.h象棋相关定义。包括棋盘局面和着法的表示。BaseClasses.h着法生成器。就当前局面生成某一方所有合法着法。MoveList.h搜索部分。使用搜索求出最佳着法。Thinkdef.h历史启发。Alpha-Beta搜索之
47、补充,以提高搜索效率。Thinker.h着法排序。对着法按其历史得分进行降序排序,以提高搜索效率。ThinkOptionDlg.h局面评估。为某一特定局面进行评分。当实现了引擎部分的各要素时,可先建立一个Win32控制台项目,之后只要再添加一个.cpp文件负责接受用户的输入、调用搜索函数、显示搜索结果,便可简单的测试引擎了(采用输入着法的起点坐标和终点坐标的方式来传送用户走棋的信息。同样,程序显示计算机走棋的起点坐标和终点坐标来做出回应)。此后,等到界面部分初步完成,引擎的上述各模块无需作任何改动,仍以.h头文件的形式加入界面工程,只要由界面中的某个.cpp文件调用搜索函数即可。这种连接方式实
48、现起来非常简单。首先,执行该软件,系统并不需要很高的配置,CPU在1.5G以上,存在512M以上就可以很流畅地执行。下面简单介绍一下象棋相关规则:对局时,由执红棋的一方先走,双方轮流各走一着,直至分出胜、负、和,对局即终了。轮到走棋的一方,将某个棋子从一个交叉点走到另一个交叉点,或者吃掉对方的棋子而占领其交叉点,都算走一着。双方各走一着,称为一个回合。如果有一方的主帅被对方吃了,就算那一方输。各种棋子的走法:帅(将):帅和将是棋中的首脑,是双方竭力争夺的目标。它只能在“九宫”之活动,可上可下,可左可右,每次走动只能按竖线或横线走动一格。帅与将不能在同一直线上直接对面,否则走方判负。仕(士):仕
49、(士)是帅(将)的贴身保镖,它也只能在九宫走动。它的行棋路径只能是九宫的斜线。相(象):相(象)的主要作用是防守,保护自己的帅(将)。它的走法是每次循对角线走两格,俗称“象走田”。相(象)的活动围限于“河界”以的本方阵地,不能过河,且如果它走的“田”字中央有一个棋子,就不能走,俗称“塞象眼”。 车:车在象棋中威力最大,无论横线、竖线均可行走,只要无子阻拦,步数不受限制。因此,一车可以控制十七个点,故有“一车十子寒”之称。炮:炮在不吃子的时候,走动与车完全一样。马:马走动的方法是一直一斜,即先横着或直着走一格,然后再斜着走一个对角线,俗称“马走日”。马一次可走的选择点可以达到四周的八个点,故有“
50、八面威风”之说。如果在要去的方向有别的棋子挡住,马就无法走过去,俗称“蹩马腿”。兵(卒):兵(卒)在未过河前,只能向前一步步走,过河以后,除不能后退外,允许左右移动,但也只能一次一步。在懂的以上规则之后并可进行游戏,执行该软件后,并可进入游戏界面。棋盘界面(图3)所示:图3 棋盘界面从界面上方的菜单栏中可以进行相关设置参数设置界面(图4)如下:图4 参数设置界面等你将参数设置完毕之后,既可进入游戏。走法记录界面(图5)如下:图5 走法记录界面其他辅助功能界面(图6)如下:图6 其他辅助功能界面你可以通过上面四个辅助功能对棋局进行研究,从而提高你的下棋水平。例如,您是红方,第一步走的是兵七进一或
51、兵三进一,电脑则会炮2进4或炮8进4(图7):图7 程序运行界面以上是系统实现的所有界面与功能测试。5 总结2009年2月,我开始了我的毕业论文工作,时至今日,论文基本完成。从最初的茫然,到慢慢的进入状态,再到对思路逐渐的清晰,整个写作过程难以用语言来表达。历经了几个月的奋战,紧而又充实的毕业设计终于落下了帷幕。回想这段日子的经历和感受,我感慨万千,在这次毕业设计的过程中,我拥有了无数难忘的回忆和收获。脚踏实地,认真严谨,实事的学习态度,不怕困难、坚持不懈、吃苦耐劳的精神是我在这次设计中最大的收益。我想这是一次意志的磨练,是对我实际能力的一次提升,也会对我未来的学习和工作有很大的帮助。在这次毕
52、业设计中也使我们的同学关系更进一步了,同学之间互相帮助,有什么不懂的大家在一起商量,听听不同的看法对我们更好的理解知识,所以在这里非常感帮助我的同学。在此更要感我的导师和专业老师,是你们的细心指导和关怀,使我能够顺利的完成毕业论文。在我的学业和论文的研究工作中无不倾注着老师们辛勤的汗水和心血。老师的严谨治学态度、渊博的知识、无私的奉献精神使我深受启迪。从尊敬的导师身上,我不仅学到了扎实、宽广的专业知识,也学到了做人的道理。在此我要向我的导师致以最衷心的感和深深的敬意。本论文对计算机博弈技术进行了研究,在深入研究了机器下中国象棋方法理论基础上,实现了一个具有一定棋力的人机对弈中国象棋程序。然而,由于时间关系,程序也存在着几点不足:第一:没对计算机下棋引擎部分作更深一步的挖掘和研究。对于诸如位棋盘(BitBoard)、迭代加深(Iterative Deepening)、机器学习(Machine Learning)等当今棋类对弈程序中所采用的先进技术和思想,在程序中并未涉与。这在一定程度上影响了程序中下棋引擎的工作效率。第二:由于对人工智能算法的不熟悉,在Alpha-Beta搜索算法上花了大量的时间和精力来了解,导致程序进度的缓慢。尽管,这些问题最终都得以解决,但却影响了程序开发的进程。第
0/150
联系客服
本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。人人文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知人人文库网,我们立即给予删除!