




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
基于Python的中国象棋软件开发设计1绪论 【内容摘要】中国象棋程序的实现主要分为两大部分,分别是人工智能与辅助功能。其中人工智能部分体现在计算机下棋的计算思路,包括搜索算法搜索着法,评估函数对各种着法进行价值评估,最终选择最佳的一步;而辅助功能主要是通过算法,为人机对战添加多种功能,增添用户下棋的乐趣。本文首先研究了计算机编程在中国象棋方面的现状与前景。在研究计算机博弈论的极大值极小值搜索的基础上,通过Alpha-beta剪枝算法,利用python语言与pycharm开发工具实现具有普通人棋力的中国象棋程序。【关键词】python;中国象棋;Alpha-beta剪枝算法1绪论1.1研究背景及意义伴随着时代的发展与科技的进步,人们的娱乐项目也逐渐丰富,在二十一世纪的生活里,玩游戏已经成为了人们在茶余饭后更加乐意选择的一种放松方式。计算机发明以后,游戏便又多了一个新的载体。随着计算机的发展,电脑游戏也在逐步进化成熟。在技术发展迅速的今天,对于有能力进行程序编辑的人来说,开发多功能游戏已经是一件很容易的事情了。其中棋牌类游戏因其操作简单、方便、快捷等多种优势在众多游戏中脱颖而出,除了上手快、游戏时间短暂、随时随地都可以玩的优点之外,棋牌类的游戏最大的特点就是不以追求盈利为主,更加专注于开发人们的智力,使人们在游戏的过程中获得新鲜感的同时得到智力上的开发,深受广大人民群众的喜爱和追捧。中国象棋起源于中国,以二人之间相互对抗竞争为游戏规则,在我国拥有着悠久的历史,是最能够代表中华民族优秀文化的标志之一。中国象棋规则易懂,却具有极强的趣味性与思考性。能够起到很好的锻炼人们的逻辑思维能力的作用。中国象棋在计算机博弈中有着很高的复杂度,也很少有人参与研究,因此在网络上参考的资料相对而言是比较少的。计算机技术的发展让人不由得去想:计算机计算是否有能力战胜人类大脑?象棋大师败于与计算机的对战是否证明了计算机已经超越了人类?这些问题都牵扯到了人工智能的概念。而人工智能就是以研究如何使计算机通过计算去完成传统认知中只有靠人类大脑才能完成的工作。基于科技发展的大背景之下,人工智能技术的研究成了游戏开发过程中一个热门方向。[1][2]1.2课题发展概况从最初功能单一的电子棋盘到如今的丰富多彩的电脑端游戏,象棋软件的发展也是十分迅速的。早期的象棋软件计算时间长,计算效果差,人们往往在下棋的过程中就败于缺乏耐性等待电脑计算。慢慢地,一些相对智能的中国象棋软件也渐渐出现在网络上,最突出的代表有:《棋瘾》等,虽然改善了计算时长方面的缺点,但同样存在着共同性的缺陷,那就是在进行对弈时智力与人脑还是存在明显的差异。自2016年阿尔法围棋与职业棋手李世石进行人机之间的较量之后并且以微弱的优势战胜计算机之后,越来越多的人们开始注意到人工智能的概念。它打破了传统观念中棋局对战必须双人参与的观点,首次正式提出了以计算机计算代替人类大脑计算的大胆想法。2017年,谷歌公司旗下子公司在国际学术期刊《Nature》上发布了关于人工智能自训练的两篇学术文章'MasteringthegameofGowithouthumanknowledge'以及'MasteringChessbySelf-PlaywithaGeneralReinforcementLearning',为后人实现中国象棋软件开发提供了清晰明了的思路及原理。在韩继凯硕士的论文《远程遥控中国象棋对弈机器人系统研制》中,对中国象棋机器人的研究意义做出了详细的介绍。[3]直到2020年,人们还是没有停止对中国象棋软件的研究,孔德帅硕士的论文《中国象棋人机博弈系统的研究与实现》又对人机博弈的理论提供了更加科学的理论依据及实践经验。[4]从这一系列发展来看,中国象棋软件的研究也逐步出现了上升的趋势。1.3主要研究内容作为当今三大极端技术之一,人工智能赋予了计算机一个“思考”的过程,使其智能化,做到能够代替人类完成某些工作。将人工智能与游戏相结合,以提高游戏过程中的趣味性成为了近些年来人们不断探索研究的重点。在本次软件设计与开发的过程中,主要运用到Python中的库,并综合运用了人工智能的相关搜索算法来实现着法的生成,完善整个游戏软件的实用性与趣味性。本此设计将着重将人工智能与中国象棋游戏结合起来,通过剪枝算法实现人机对弈的基本操作,因此,如何设计算法,优化代码成为了本次设计的重难点所在。本文完成一下的工作:第一部分绪论介绍了课题研究的背景及其意义、课题的发展概况与研究内容;第二部分系统技术分析,主要介绍了本次设计开发的技术支持,包括开发环境、开发语言以及开发工具;第三部分软件功能描述,从大体上介绍了中国象棋软件在当今社会的需求,提出本次设计开发的所要实现的功能;第四部分软件设计与实现,主要介绍了软件设计的整体思路以及其中的技术分析,详细描述了本次软件设计开发的过程;第五部分软件测试,主要对本次设计运行的结果进行了分析;第六部分总结,总结了本次设计所取得的成绩、指出存在的不足,提出对未来的展望。2系统技术分析本软件是为一个小型的基于Python语言编写的中国象棋软件,是实现人机对战的单机游戏,所耗费的资源非常的小。系统的界面友好,完全是可视化,基于Windows窗口方便了各种类型用户使用。本软件的开发工具是PyCharm2020.1版本,使用的语言为Python3.7版本。主要导入了Pygame、Numpy等库,共同完成了算法的设计。利用自带的功能库Pygame来进行页面布局,完成了整个软件操作界面的设计。只要启动程序的运行,即可打开界面开启游戏。2.1Pycharm概述Pycharm是python语言开发最普遍、常见的开发工具,具有跨平台的特型,主流的三大平台是Windows、MacOSX和Linux。其自带调试、工程管理、智能提示等等工具,能够帮助程序员在编程的过程中提高开发效率。除此之外,Pycharm还为用户提供了一些更加高级的功能,例如支持Django框架下的专业Web开发、支持GoogleAppEngine、IronPython等,种种功能在软件开发中发挥了重要的作用,使得Pycharm成为了Python语言开发最有力的工具。本次软件开发选择的版本为2020.1版本,能够调用现成的库来设计开发,能够实现软件的开发。2.2Python概述Python是近几年来逐渐流行的具有极强扩展性的一门编程语言。具有强大的功能价值,能够实现将各种不同的编程语言制作的模块综合联结应用。与Pycharm一样,Python也是能够跨平台利用的,能够在Windows,MacOS或者是linux上实现运行。在本次设计中使用的编程语言即为Python,版本为3.7,其具有的功能库能够满足我对于本次软件开发的要求。3软件需求与功能描述3.1需求描述由于现代技术的日益精进,人们在生活上的要求越来越高,开始将大部分注意力放在了享受生活上。基于现代人的心理需要,大量的娱乐游戏软件开始涌现,以供人们消遣闲暇的时间。基于Python的中国象棋软件将服务于所有年龄段的用户,以广大象棋爱好者为受众群体,满足象棋爱好者们下棋的需要,感受人工智能的魅力,这就是开发这么一款象棋软件的初衷。3.2功能描述基于Python的中国象棋软件主要是服务于电脑端的用户,增加业余时间的趣味性。本软件具备有人机对战、开启、关闭背景音、悔棋、重新开局、退出游戏等功能。人机对战,打开软件,用户为先手红棋子,电脑为后手黑棋子,用户先点击所要移动的棋子,再点击想要移动到的位置,就完成了的我方用户棋子移动。电脑通过Alpha-beta剪枝算法的计算,再以历史启发算法的优化,通过评估函数评估出每步棋胜利的概率,最后会将棋子自动移动到胜率最高的位置,完成电脑方的下棋。两个功能相互结合,即完成了人机对战的功能。开启、关闭背景音乐。打开软件,点击“音效控制”的按键,音乐的自动初始化和加载,实现自动播放背景音乐的作用,此时再次通过点击“音效控制”的按键,阻止音乐播放事件的发生。同理,如果再想打开音乐可以再次点击“音效控制”按钮,音乐又会重新加载播放。悔棋。打开软件,在对战的过程中可以随时点击“悔棋”按键,即可返回上一步的棋局,又可重新选择棋子完成棋局。重新开局。在对战的过程中可以随时点击“重新开局”按键,即可完成重新开局的操作。退出游戏。打开软件,点击退出游戏的按键区域,即可完成软件的退出。4软件设计与实现4.1软件设计原理本软件实现的目标是能进行人机对战的一款中国象棋软件,主要包括了人工智能的算法的实现以及辅助功能的实现,由Python语言进行开发,主要运用到Pygame等库,方便游戏的开发。主程序文件Chinachese.py统筹实现所有功能,运行主程序即可以对象棋游戏进行操作。软件主要包括了以下四个模块:页面布局的设置棋局与棋子的表示博弈程序的实现各项辅助功能整个软件的运行也是四个模块运行的共同结果,其中博弈程序的实现是整个软件的重难点。利用Python语言的卓越的通用性、高效性、灵活性与安全性实现软件各项功能的正常运行。这样开发的软件不仅在操作界面上能达到整洁美观的要求,而且也可以在Windows系统平台上稳定运行。设计的思路按照普通棋局对战思路来进行设计,如图4-1所示:图4-SEQ图表\*ARABIC\s11软件实现流程图4.2页面布局设计点击运行程序即可运行软件进入到象棋操作界面,操作界面是主程序Chinesschess.py文件中比较基础的部分,创建了一个900px*650px的游戏窗口,并通过Pygame库在窗口上进行其他样式的设置。图4-SEQ图表\*ARABIC\s12软件操作界面图简洁明了是UI设计上最大的要求。首先棋盘棋子界面,在主页面的左侧。用户可以以点击棋子的方式实现棋子的移动,便于操作。主页面的右上侧是提示区域,主要作用是显示当前用户的文档信息。右下角是工具栏,设置了四个按键:重新开局、悔棋、开启(关闭)音乐、退出游戏。当鼠标移动到该按键的区域时,字体颜色会由黑色变成红色,展现一个悬停的效果。用户可以通过点击按键的方式触发相应的函数实现各种各样的功能。完成的整个界面如图图4-SEQ图表\*ARABIC\s12软件操作界面图4.3棋局与棋子表示4.3.1棋局的表示整个棋局表示采用的是传统、简单的“棋盘列表”,即生成一个9*10的二维数据列表记录储存每个棋子的位置信息,数据列表里的元素相对应的就是棋盘上的位置点是否存在棋子、存在哪种类型的棋子。初始棋局的表示需要将原始棋子的位置点信息添加到该数据列表里,完成数据的初始化。通过棋局的表示方便博弈程序中对当前棋局状况的识别与辨认。4.3.2棋子的表示如果将每一个棋子看成是数据点,将棋盘看作是一个平面坐标系,具备储存数据点的功能,就可以将每个棋子的位置信息固定在横坐标X的范围在0到10之间,纵坐标Y的范围在0到11之间。有了坐标范围的限制,就可以通过坐标点的加减来控制着法,即以想要移动到的位置的坐标点的值减去棋子本身坐标点的值,若是符合要求则移动,若不符合就返回错误值。若是移动棋子,则修改其中的坐标值即可。至于在中国象棋里独有的“吃子”规则,也是通过坐标点的计算来限制。被吃掉的棋子用超越范围的数来表示。在这其中可以用一个字节为32的一维数组piecesList来表示每一个棋子的位置,其中每个字节的高4位表示棋子的横坐标,低4位表示纵坐标。有了局面与棋子的表示,就完成了整个程序的基础部分,相当于建立好了地基,之后的电脑搜索与功能实现都将建立在此基础之上。4.4博弈程序的实现4.4.1着法生成着法即是棋子下棋的走法。着法生成的基本思路是:读取当前现有的棋盘,将棋盘上每一个棋子的位置数据都搜索查看一遍,根据棋子的类型返回所有的可行着法,最后通过价值评估判断出对自己最有利的棋子着法储存到着法队列中,并将该着法队列返回到棋局数据列表中。着法的生成是为了方便进行搜索,因为过多层数的搜索会导致搜索时间过长的情况,所以为了避免搜所效果不理想的情况,在本次设计中设定搜索的层数为4层。这样不仅保证了搜索时的效率,同时还保证了搜索的质量,表现在电脑的下棋水平会相对较高。4.4.2博弈树概念机器博弈在电脑游戏中十分普遍,在中国象棋的实践中也需要用到博弈的概念。通常以博弈树的结构来解决机器博弈的一系列问题。图4-SEQ图表\*ARABIC\s13图4-SEQ图表\*ARABIC\s13博弈树结构图在这棵博弈树的结构里,每一层代表其中一方走子,结点代表不同的走子方式产生的不同局面,从每一个结点衍生出来的又是另外与之相对抗的结点。反反复复,直到到达叶子结点,即出现没有其他走法、棋局结束的局面,博弈树才停止。在该博弈树的结构里,一共出现了三种类型的结点:奇数层结点(包括根节点),表示红方走棋;偶数层结点,表示黑方走棋;叶子结点,表示棋局结束。计算机下棋的思路,就是将博弈树全部查看过一遍,试走每一种可能性,并在众多的可能性之中相互比较并选出唯一一种对自己最有利的走法,以此来帮助自己获得胜利。那么判断可能性的成功值成了博弈树关键所在,若给每一个结点都打上相应的分值,通过比较分值的大小来间接反映局面的优劣,那么就能够实现判断判断最优走法。还是假定甲乙两方下棋,甲方胜利的局面标记为一个极大值α(一个极大的正数),对手方乙方胜利的局面标记为一个极小值β(极大值的负数),和棋的局面标记为零或是接近于零的值。在博弈的过程中,甲方会尽可能地使局面分值处于较大的值,从而执行奇数层上分值最大的结点,而乙方则会采取措施使局面分值尽可能的小,从而执行偶数层上分值最小的结点。这就是“最小-最大”思想。博弈树在中国象棋的应用里是存在缺陷的,即在下棋的过程中,平均着法大概有40种左右,那么搜索4层的博弈树将需要检查大约250万条路线,不仅工程量会成指数增长,而且还特别费时。[5]4.4.2Alpha-beta剪枝算法Alpha-beta剪枝,能够做到在不影响搜索精度的条件下减少搜索的工作量,它的核心思想就是在进行搜索的过程中利用上当前局面的信息来进行剪枝的方法。它的实现基于一种想法:如果存在某一种选择会比眼前的选择更加适合,那么就可以证明眼前的选择并不是最佳,便可以进行剪枝处理,在后面搜索的过程中将不需要对眼前的选择进行考虑。Alpha-beta剪枝算法在进行搜索时,将始终记录节点的α值和β值。通过比较不同节点之间的α、β值来进行剪枝。α的初始值为负无穷,代表的是MAX方的最优值,β初始值为正无穷,代表的是MIN方的最优值。在MAX方搜索时,只改变α值,将其数值改变成max(自身,下一层α,下一层β);同样的,在MIN方搜索时,只改变β值,将其数值改变成min(自身,下一层α,下一层β)。α与β的传递顺序为先遍历左子树,返回至父结点之后再遍历右子树。剪枝的实质就是当某个结点的分数值存在α≥β时,将该支路进行裁剪。剪枝算法模型如图4-4所示:图4-SEQ图表\*ARABIC\s14Alpha-Beta剪枝算法模型图在图示中,A为根节点,属于MAX方,其α=-∞,β=+∞,其数值将依次传递至以下结点,成为各节点的初始值。对于结点E而言,属于MIN方,改变其β值为最小值,这里取10,改变之后E结点的数值就为α=-∞,β=10。在按照顺序遍历右子树,再次改变β值为5。对于C点而言,属于MAX方,只改变其α值为最大值。由于-∞<5,因此,C节点的数值为α=5,β=+∞。当搜索到B节点时,再将该数值向另一分支往下传递,重新依次按照方法对D、G和H节点进行遍历。最后发现在搜索到“D-G”这条分支时,D节点的数值改变为α=7,β=7,出现了α≥β的情况,因此将该分支进行剪枝处理。在最理想的情况下,通过Alpha-Beta剪枝算法处理的博弈树是初始的极大极小值算法的平方根级。因此,该算法成为博弈程序中改进的基础算法,而且生成博弈树中的节点排列顺序对剪枝效果也有很大的影响。在本软件中,Alpha-Beta代码的实现主要是在my_game.py文件中定义,具体代码如下:defalpha_beta(self,depth,alpha,beta):#alpha-beta剪枝,alpha是大可能下界,beta是最小可能上界
who=(self.max_depth-depth)%2#那个玩家
ifself.is_game_over(who):#判断是否游戏结束,如果结束了就不用搜了
returncc.min_val
ifdepth==1:#搜到指定深度了,也不用搜了
returnself.evaluate(who)
move_list=self.board.generate_move(who)#返回所有能走的方法
#利用历史表0
foriinrange(len(move_list)):
move_list[i].score=self.history_table.get_history_score(who,move_list[i])#启用历史启发法
move_list.sort()#为了让更容易剪枝利用历史表得分进行排序
best_step=move_list[0]
score_list=[]
forstepinmove_list:#遍历着法列表
temp=self.move_to(step)#执行着法
score=-self.alpha_beta(depth-1,-beta,-alpha)#递归调用,因为是一层选最大一层选最小,所以利用取负号来实现
score_list.append(score)#返回分数值
self.undo_move(step,temp)#撤销着法
ifscore>alpha:#进行搜索
alpha=score
ifdepth==self.max_depth:
self.best_move=step#返回最优着法
best_step=step
ifalpha>=beta:#进行裁剪
best_step=step
break
ifbest_step.from_x!=-1:#更新历史表
self.history_table.add_history_score(who,best_step,depth)
returnalpha4.4.3历史启发算法根据Alpha-beta剪枝算法的思想来看,树的结构就在很大程度上对它的效率有影响。如果只有在分析了所有的可能性之后才实现剪枝,那么剪枝也就失去了原先的价值。基于此提出一种方案,那就是如果能够给计算机提供一个搜索辅助,将提早进行剪枝,那工作量就会减少,也在一定程度上提高了搜索的效率。基于此想法,在进行Alpha-beta剪枝算法搜索的过程中,引入一个排序的思想,当发现一个好的走法的时候,就给该走法累加一个增量以记录其“历史得分”,这样一个被多次搜索并认为是最佳的走法的“历史得分”就会较高。得分的高低将影响搜索结点的排序,在搜索的过程中,得分高的结点,也就是最优的走法将会优先进行剪枝搜索。这样Alpha-Beta搜索就可以实现尽可能早地进行“裁剪”,从而保证了搜索的效率。具体代码的实现主要是在history_heuristic.py文件中。4.4.4价值评估函数在进行Alpha-beta剪枝搜索的同时要进行的就是评价函数对当前局面的评估。评价函数不仅仅要考虑到剪枝搜索的α值和β值,还要综合考虑棋子的固定子力值、棋子的位置价值、以及棋子灵活度评估值和棋子威胁、保护评估值等。只有在能够综合考虑各种情况、因素的合理的评价函数的评估下才能够对当前局面做出最正确的判断。棋子的固定棋力。每个棋子都具有其相应的价值能量大小,这就是棋子的固定棋力。在棋局中,如果哪一方的棋子的固定棋力比较大,那么这一方在当前棋局中就处于一个相对优势的局面。一般而言,将(帅)的棋力最大,而卒(兵)的棋力最小,其中排序依次为:将(帅)、车、马、炮、士(仕)、象(相)、卒(兵)。在本软件中棋子固定棋力的数据如表4-1所示。表4-1棋子固定棋力数据表棋子将士象马车炮卒棋子固定棋力1000025025030050030080棋子的位置价值。在中国象棋中,同样棋子在不一样的位置点上存在着不一样的价值,不同的棋子在同一位置点上也存在着不一样的价值。例如,在初始状态或者未进入九宫之前,卒的棋力都比较小,对棋局的威胁力相对小。而当卒进入到九宫之后,由于走法没有了限制,对对方的威胁就较大,故可以称其为位置力较大。不同棋子的位置价值需要通过设计者自己设置,以9*10的数组列表记录每一个棋子不同位置的价值。棋子的灵活程度值。每个棋子都有其自身的走法规则限制,例如马走日,象走田等规则,这就影响了棋子的灵活程度。灵活度较高的棋子可以在棋局中自由移动,因此其灵活程度值就比较高。相反的,那些有条件限制的棋子灵活程度值就比较低。一般来说,在中国象棋的棋盘里,兵(卒)灵活程度值最高,灵活程度值最差的是将和炮。[6]在本软件中设置棋子灵活程度值的数据如表4-2所示。表4-2棋子灵活程度数据表棋子将士象马车炮卒灵活程度值011126615棋子状态评估值。在棋局中,棋子可能处于两种状态,一种是处于被对方棋子威胁的状态,另一种是被自己的棋子保护的状态。无论是哪种状态都影响棋子的安全系数,影响对当前棋局的判断。因此,在编写评价函数时也要将棋子的状态值考虑进去。当棋子处于被其他棋子保护、相对安全的状态下时则提高其评估值,而当处于威胁状态时,减低其评估值。在实际代码的应用中,以num_guarded来记录棋子受到保护的值,以num_attacked来记录棋子受到威胁的值。在价值评估的函数里,主要涉及到的数据量有relation_list=self.init_relation_list()#记录、储存关系信息base_val=[0,0]#基础价值,固定棋力
pos_val=[0,0]#位置价值
mobile_val=[0,0]#棋子灵活程度价值
relation_val=[0,0]#棋子状态评估价值最后计算机计算出来的价值量就是各个价值之和,最后合计为最大价值量my_max_val与最小价值量my_min_val。价值函数返回值就是最大价值量与最小价值量之差。ifwho==0:#判断当前用户为要求最大值的玩家
returnmy_max_val-my_min_val
else:
returnmy_min_val-my_max_val综合剪枝搜索算法,价值评估函数之后产生的最优结果最后会返回到当前棋局中实现棋子的移动。整个博弈程序的实现流程如图4-5所示图4-SEQ图表\*ARABIC\s15博弈程序实现流程图图4-SEQ图表\*ARABIC\s15博弈程序实现流程图5.1悔棋悔棋是棋类软件中最基本的功能。为了完成悔棋的功能,主要完成以下任务:提取所要还原的棋子信息;改变棋子的坐标值,恢复上一步数据值;将数据在记录走法的数据数组列表里删除。首先就是需要记录好每一步的走棋信息,根据走棋的信息来完成撤销着法的操作,在本次软件设计中,走棋的信息用数组move_pieces_history[]来记录,在该数组中,用户棋子操作与计算机棋子操作为一个元素,每一个元素里又存在数组专门记录了棋子类型、未移动位置时的X值以及未移动位置时的Y值。详细的记录是为了确保数据信息的完整,在执行悔棋操作时不容易出错。提取走棋信息数组的最后一个元素,将其未改变之前的坐标值反赋值到棋子的坐标值数据里,实现当前棋子的坐标值与未移动之前的坐标值相一致。最后一步就是将存储在走棋信息数组里的信息删除。defrepentance(self):
iflen(self.move_pieces_history)==0:#判断是否有棋子发生了移动
return
else:
temp_moved_pieces_infos=self.move_pieces_history[-1]#获取列表最后一个元素
foriteminself.piecesList:#将元素返回前一个元素的位置,主要是x,y的值的还原
ifitem.x==temp_moved_pieces_infos[1][0].xanditem.y==temp_moved_pieces_infos[1][0].y:#还原用户棋子
item.x=temp_moved_pieces_infos[1][1]
item.y=temp_moved_pieces_infos[1][2]
ifitem.x==temp_moved_pieces_infos[0][0].xanditem.y==temp_moved_pieces_infos[0][0].y:#还原计算机棋子
item.x=temp_moved_pieces_infos[0][1]
item.y=temp_moved_pieces_infos[0][2]
self.move_pieces_history.pop(-1)#移除历史列表中最后的一个元素,即最后一步操作步骤5.2重新开局重新开局的功能的实现需要提前定义一个变量,在本次软件设计中,将该变量定义命名为:isrestart_flag,判断0或是1。若是0,则表示继续当前棋局,若是1,则对当前绘制的游戏窗口进行重新执行的操作,以此来完成重新开局的操作。5.3音效控制音效控制的实现方式与重新开局方式一致,同样为定义变量,通过变量的转换来实现背景音乐开关的功能。在本次软件设计中,将控制音效的变量名称定义为:is_mute_flag,为了区别于重新开局的变量,将控制音效的判断设置为Ture与Flase。若是Ture,则音乐暂停,若为Flase,则音乐播放。6软件测试软件测试的作用主要是为了查看验证预定功能是否得到实现。如果代码无错误,并且功能都得到了实现,那么则说明软件设计与开发是符合要求的。根据预期的要求,软件测试将分为人机对弈、重新开局、悔棋操作、开启(关闭)背景音乐以及退出游戏五个部分来进行测试,测试结果如下。6.1人机对弈打开中国象棋文件Chinahess,运行主程序Chinachess.py,出现游戏的操作界面:棋盘界面、提示框部分界面以及功能键界面。提示框显示当前用户为红色,即需要用户先点击想要移动的红色棋子,再点击想要棋子移动到的交叉点上。点击红色“兵”棋,再次点击正上方的棋盘交叉点,提示框显示当前用户为黑色,即棋子已经实现了移动,等待黑棋子走下一步。当黑棋走了下一步,提示框将自动跳转提示用户下棋。假如点击之后提示框始终提示当前用户为红棋子,那么则说明点击想要去的坐标点不符合象棋游戏规则,需要重新点击符合规则的交叉点。若某一方的棋子想要到达的交叉点上存在着对方的棋子,在符合游戏规则的前提下,对方的棋子将会被撤掉,换上我方的棋子,如此则完成吃棋的操作。当某一方的将(帅)被对方棋子吃掉后,操作界面显示“电脑(用户)胜利!“字样”,如图5-1所示:图5-SEQ图表\*ARABIC\s11获胜界面6.2重新开局当游戏进行到一半时,点击“重新开局”按键,所有的棋子回到原位,可以重新开始新的棋局。重新开局功能测试完成。6.3悔棋游戏进行到一半时,点击“悔棋”按键,则黑棋与红棋的同时返回上一步之前的位置。例如:在游戏开始后,点击任意一个棋子移动,然后点击“悔棋”按键,棋子退回到原先的状态。悔棋功能测试完成。6.4开启(关闭)音乐打开软件,弹出游戏界面。点击“音效控制”按键,背景音自动播放。再次点击“音效控制”按键,音乐重新关闭。开启(关闭)音乐功能测试完成。6.5退出游戏打开软件,弹出游戏操作界面,点击“退出游戏”按键,游戏界面关闭,程序强制退出。退出游戏功能测试完成。经过测试可以验证预定的功能均已实现,满足了预期的要求,达到了开发设想,完成了设计与开发的任务。在系统的编码上能够将各个功能实现模块化,编写风格规范化,提高了整个软件系统的可读性以及延展性。7总结本文针对计算机博弈与中国象棋游戏相结合进行了深入的研究,在理解了象棋规则、计算机博弈论的基础上,实现了具有普通人棋力的中国象棋软件。在这个过程中,我将大学四年来所学到的知识运用上,感受到了知识的巨大用途。能够将知识运用到实践中,我觉得四年的时间没有白白浪费。然而,我的水平还不是很高,在程序设计方面也存在着一些不足。例如对人工智能的算法不够熟悉,在理解搜索原理时花费了大量的实践与精力,导致整个设计的进程速度慢。再比如,软件程序虽然实现了悔棋、重新开局等功能,却在使用上具有局限性,偶尔会出现代码冲突的问题。虽然这次设计开发算不上是完美的,却也花费了我许多的精力去深入研究学习。学习是没有边际的,我会在以后的时间里继续深入学习,努力将软件开发实现得更加智能,灵敏。
参考文献[1]刘丹奕.浅谈人工智能在游戏开发中的应用[J].黑龙江科技信息,2014,(36):128,69.[2]曹坤泽.人工智能及其在游戏领域中的应用[J].科技传播,2020,12(08):143-144.[3]韩继凯.远程遥控中国象棋对弈机器人系统研制[R].南京:南昌大学,2019:3-5.[4]孔德帅.中国象棋人机博弈系统的研究与实现[R].山东:青岛大学,2020:1-3,27-29.[5]黎利辉.基于Alpha-Beta剪枝法的中国象棋博弈系统研究[J].福建电脑.2014,30(03):29-50.[6]汤云雄.中国象棋布局基本原则的重要性研究[J].现代盐化工,2020,47(03):50-102.
英文摘要ThedesignanddevelopmentofChinesechesssoftwarebasedonPythonAbstract:TheimplementationofChinesechessprogramismainlydividedintotwoparts,namely,artificialintelligenceandauxiliaryfunctions.Thepartofartificialintelligenceisembodiedinthecalculationthinkingofcomputerplayingchess,includingsearchingalgorithmsearchingformoves,evaluationfunctionevaluatingthevalueofvariousmoves,andfinallychoosingthebestmove.Andtheauxiliaryfunctionismainlythroughthealgorithm,fortheman-machinewartoaddavarietyoffunctions,addthefunoftheuserplayingchess.Firstly,thispaperstudiesthecurrentsituationandprospectofcomputerprogramminginChinesechess.Onthebasisofstudyingthesearchofmaximumandminimumvaluesincomputergametheory,theChinesechessprogramwithordinarypeople'schessabilityisrealizedbyusingPythonlanguageandPyCharmdevelopmenttoolthroughalpha-betapruningalgorithm.Keywords:Python;Chinesechess;Alpha-betapruningalgorithm
附录chinachess.pyimportpygame
importtime
importconstants
frombuttonimportButton
importpieces
importcomputer
importmy_gameasmg
classxiaoguo(object):
def__init__(self,text,color,x=None,y=None,**kwargs):
#font_addr=pygame.font.get_default_font()
#font=pygame.font.Font(font_addr,36)
font=pygame.font.SysFont('kaiti',36)
self.surface=font.render(text,True,color)
self.WIDTH=self.surface.get_width()
self.HEIGHT=self.surface.get_height()
if'centered_x'inkwargsandkwargs['centered_x']:
self.x=constants.SCREEN_WIDTH//1.3-self.WIDTH//2
else:
self.x=x
if'centered_y'inkwargsandkwargs['cenntered_y']:
self.y=constants.SCREEN_HEIGHT//2-self.HEIGHT//2
else:
self.y=y
defdisplay(self):
MainGame.window.blit(self.surface,(self.x,self.y))
defcheck_click(self,position):
x_match=position[0]>self.xandposition[0]<self.x+self.WIDTH
y_match=position[1]>self.yandposition[1]<self.y+self.HEIGHT
ifx_matchandy_match:
returnTrue
else:
returnFalse
classMainGame():
window=None
Start_X=constants.Start_X
Start_Y=constants.Start_Y
Line_Span=constants.Line_Span
Max_X=Start_X+8*Line_Span
Max_Y=Start_Y+9*Line_Span
from_x=0
from_y=0
to_x=0
to_y=0
clickx=-1
clicky=-1
mgInit=mg.my_game()
player1Color=constants.player1Color#用户
player2Color=constants.player2Color#机器人
Putdownflag=player1Color
piecesSelected=None
button_go=None
piecesList=[]
isrestart_flag=1
is_end_flag=1
#代码里所有flag=1的地方都打印dataerror的,所以是用来标记异常的。flag初始为0,表示为正常状态。只要flag值没被改成1,就说明输入正常,一直循环输入;如果输入错误,即flag被改为1,那么就停止输入,程序结束。
is_mute_flag=False#是否静音True静音False不静音
move_pieces_history=[]
defstart_game(self):
MainGame.window=pygame.display.set_mode([constants.SCREEN_WIDTH,constants.SCREEN_HEIGHT])
pygame.display.set_caption("中国象棋")
MainGame.button_go=Button(MainGame.window,"重新开局",constants.SCREEN_WIDTH-260,300)#创建开始按钮
MainGame.button_repentance=Button(MainGame.window,"悔棋",constants.SCREEN_WIDTH-260,350)#创建声音按钮
MainGame.button_exit=Button(MainGame.window,"退出游戏",constants.SCREEN_WIDTH-260,450)
play_button=xiaoguo('悔棋',(0,0,0),None,310,centered_x=True)
huiqi_button=xiaoguo('重新开局',(0,0,0),None,360,centered_x=True)
exit_button=xiaoguo('退出游戏',(0,0,0),None,410,centered_x=True)
music_button=xiaoguo('背景音乐',(0,0,0),None,460,centered_x=True)
pygame.mixer.init()
pygame.mixer.music.load("music/bg_music2.mp3")#加载背景音乐
self.piecesInit()
whileTrue:
time.sleep(0.1)
MainGame.window.blit(constants.BG_IMAGE,(0,0))#加载背景图
#MainGame.window.fill((233,204,138))
self.drawChessboard()
ifplay_button.check_click(pygame.mouse.get_pos()):
play_button=xiaoguo('悔棋',(255,0,0),None,310,centered_x=True)
else:
play_button=xiaoguo('悔棋',(0,0,0),None,310,centered_x=True)
ifhuiqi_button.check_click(pygame.mouse.get_pos()):
huiqi_button=xiaoguo('重新开局',(255,0,0),None,360,centered_x=True)
else:
huiqi_button=xiaoguo('重新开局',(0,0,0),None,360,centered_x=True)
ifexit_button.check_click(pygame.mouse.get_pos()):
exit_button=xiaoguo('退出游戏',(255,0,0),None,410,centered_x=True)
else:
exit_button=xiaoguo('退出游戏',(0,0,0),None,410,centered_x=True)
ifmusic_button.check_click(pygame.mouse.get_pos()):
music_button=xiaoguo('音效控制',(255,0,0),None,460,centered_x=True)
else:
music_button=xiaoguo('音效控制',(0,0,0),None,460,centered_x=True)
play_button.display()
huiqi_button.display()
exit_button.display()
music_button.display()
self.piecesDisplay()
self.VictoryOrDefeat()
ifself.is_end_flag==1:#0:当前局游戏已结束1:未结束
self.Computerplay()
#print("cccc")
self.isrestart_flag=self.getEvent()#0:重新开始1:不重新开始
#print("dddd")
ifself.isrestart_flag==0:
break
pygame.display.update()#显示更新
pygame.display.flip()#显示翻转
ifself.isrestart_flag==0:
return
#MainGame().start_game()
defdrawChessboard(self):#绘画棋盘界面
#pygame.draw.circle(MainGame.window,[255,0,0],[830,180],20,0)
outer_frame_color=(60,20,0)
pygame.draw.rect(MainGame.window,outer_frame_color,[45,45,491,550],5)
s_font=pygame.font.Font('C:\Windows\Fonts\ARIALUNI.ttf',40)
u_font=pygame.font.Font('C:\Windows\Fonts\ARIALUNI.ttf',30)
my_font=pygame.font.Font('C:\Windows\Fonts\ARIALUNI.ttf',50)
title_font=pygame.font.Font('C:\Windows\Fonts\ARIALUNI.ttf',55)
text4=my_font.render("楚河",True,(0,0,0))
text5=my_font.render("漢界",True,(0,0,0))
text6=title_font.render("中国象棋",True,(0,0,0))
text7=s_font.render("当前用户:",True,(0,0,0))
text8=u_font.render("玩家",True,(255,0,0))
MainGame.window.blit(text4,(120,285))
MainGame.window.blit(text5,(360,285))
MainGame.window.blit(text6,(600,50))
MainGame.window.blit(text7,(580,150))
MainGame.window.blit(text8,(780,160))
pygame.draw.line(MainGame.window,(0,0,0),(580,140),(860,140))
pygame.draw.line(MainGame.window,(0,0,0),(580,145),(860,145))
mid_end_y=MainGame.Start_Y+4*MainGame.Line_Span
min_start_y=MainGame.Start_Y+5*MainGame.Line_Span
foriinrange(0,9):#竖线设置
x=MainGame.Start_X+i*MainGame.Line_Span
ifi==0ori==8:
y=MainGame.Start_Y+i*MainGame.Line_Span
pygame.draw.line(MainGame.window,constants.BLACK,[x,MainGame.Start_Y],[x,MainGame.Max_Y],1)
else:
pygame.draw.line(MainGame.window,constants.BLACK,[x,MainGame.Start_Y],[x,mid_end_y],1)
pygame.draw.line(MainGame.window,constants.BLACK,[x,min_start_y],[x,MainGame.Max_Y],1)
foriinrange(0,10):#横线设置
x=MainGame.Start_X+i*MainGame.Line_Span
y=MainGame.Start_Y+i*MainGame.Line_Span
pygame.draw.line(MainGame.window,constants.BLACK,[MainGame.Start_X,y],[MainGame.Max_X,y],1)
speed_dial_start_x=MainGame.Start_X+3*MainGame.Line_Span
speed_dial_end_x=MainGame.Start_X+5*MainGame.Line_Span
speed_dial_y1=MainGame.Start_Y+0*MainGame.Line_Span
speed_dial_y2=MainGame.Start_Y+2*MainGame.Line_Span
speed_dial_y3=MainGame.Start_Y+7*MainGame.Line_Span
speed_dial_y4=MainGame.Start_Y+9*MainGame.Line_Span
pygame.draw.line(MainGame.window,constants.BLACK,[speed_dial_start_x,speed_dial_y1],
[speed_dial_end_x,speed_dial_y2],1)
pygame.draw.line(MainGame.window,constants.BLACK,[speed_dial_start_x,speed_dial_y2],
[speed_dial_end_x,speed_dial_y1],1)
pygame.draw.line(MainGame.window,constants.BLACK,[speed_dial_start_x,speed_dial_y3],
[speed_dial_end_x,speed_dial_y4],1)
pygame.draw.line(MainGame.window,constants.BLACK,[speed_dial_start_x,speed_dial_y4],
[speed_dial_end_x,speed_dial_y3],1)
defpiecesInit(self):#后台将棋子放在相应的位置上,不可见
self.piecesList=[]
self.piecesList.append(pieces.Rooks(self.player2Color,0,0))#坐标对应棋子所在棋盘的坐标
self.piecesList.append(pieces.Rooks(self.player2Color,8,0))
self.piecesList.append(pieces.Elephants(self.player2Color,2,0))
self.piecesList.append(pieces.Elephants(self.player2Color,6,0))
self.piecesList.append(pieces.King(self.player2Color,4,0))
self.piecesList.append(pieces.Knighs(self.player2Color,1,0))
self.piecesList.append(pieces.Knighs(self.player2Color,7,0))
self.piecesList.append(pieces.Cannons(self.player2Color,1,2))
self.piecesList.append(pieces.Cannons(self.player2Color,7,2))
self.piecesList.append(pieces.Mandarins(self.player2Color,3,0))
self.piecesList.append(pieces.Mandarins(self.player2Color,5,0))
self.piecesList.append(pieces.Pawns(self.player2Color,0,3))
self.piecesList.append(pieces.Pawns(self.player2Color,2,3))
self.piecesList.append(pieces.Pawns(self.player2Color,4,3))
self.piecesList.append(pieces.Pawns(self.player2Color,6,3))
self.piecesList.append(pieces.Pawns(self.player2Color,8,3))
self.piecesList.append(pieces.Rooks(self.player1Color,0,9))
self.piecesList.append(pieces.Rooks(self.player1Color,8,9))
self.piecesList.append(pieces.Elephants(self.player1Color,2,9))
self.piecesList.append(pieces.Elephants(self.player1Color,6,9))
self.piecesList.append(pieces.King(self.player1Color,4,9))
self.piecesList.append(pieces.Knighs(self.player1Color,1,9))
self.piecesList.append(pieces.Knighs(self.player1Color,7,9))
self.piecesList.append(pieces.Cannons(self.player1Color,1,7))
self.piecesList.append(pieces.Cannons(self.player1Color,7,7))
self.piecesList.append(pieces.Mandarins(self.player1Color,3,9))
self.piecesList.append(pieces.Mandarins(self.player1Color,5,9))
self.piecesList.append(pieces.Pawns(self.player1Color,0,6))
self.piecesList.append(pieces.Pawns(self.player1Color,2,6))
self.piecesList.append(pieces.Pawns(self.player1Color,4,6))
self.piecesList.append(pieces.Pawns(self.player1Color,6,6))
self.piecesList.append(pieces.Pawns(self.player1Color,8,6))
defpiecesDisplay(self):#将棋子显示在主页面上
foriteminself.piecesList:#循环列表
item.displaypieces(MainGame.window)
#MainGame.window.blit(item.image,item.rect)
defgetEvent(self):
#获取所有的事件
eventList=pygame.event.get()
foreventineventList:
ifevent.type==pygame.QUIT:
self.endGame()
elifevent.type==pygame.MOUSEBUTTONDOWN:
pos=pygame.mouse.get_pos()
mouse_x=pos[0]
mouse_y=pos[1]
#print("aaaaa")
if(
mouse_x>MainGame.Start_X-MainGame.Line_Span/2andmouse_x<MainGame.Max_X+MainGame.Line_Span/2)and(
mouse_y>MainGame.Start_Y-MainGame.Line_Span/2andmouse_y<MainGame.Max_Y+MainGame.Line_Span/2):
ifself.Putdownflag!=MainGame.player1Color:
return
click_x=round((mouse_x-MainGame.Start_X)/MainGame.Line_Span)
click_y=round((mouse_y-MainGame.Start_Y)/MainGame.Line_Span)
click_mod_x=(mouse_x-MainGame.Start_X)%MainGame.Line_Span
click_mod_y=(mouse_y-MainGame.Start_Y)%MainGame.Line_Span
print("")
ifabs(click_mod_x-MainGame.Line_Span/2)>=5andabs(
click_mod_y-MainGame.Line_Span/2)>=5:
#print("有效点:x="+str(click_x)+"y="+str(click_y))
#有效点击点
self.from_x=MainGame.clickx
self.from_y=MainGame.clicky
self.to_x=click_x
self.to_y=click_y
#print(self.from_x)
#print(self.from_y)
MainGame.clickx=click_x
MainGame.clicky=click_y
self.PutdownPieces(MainGame.player1Color,click_x,click_y)#用户棋子移动
else:
if625<mouse_x<765and460<mouse_y<495:#音效控制
print("xxxxxxxx")
#pygame.mixer_music.stop()
ifMainGame.is_mute_flag==False:
print("nnnnnnnnnn")
pygame.mixer.music.play()
else:
print("666666666")
pygame.mixer.music.stop()
MainGame.is_mute_flag=notMainGame.is_mute_flag
if615<mouse_x<755and410<mouse_y<445:#退出游戏
print("zzzzzz")
self.endGame()
#pygame.quit()
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 辽阳古建施工方案审批
- 2024年三季度报湖南地区A股销售净利率排名前十大上市公司
- 快船新球馆施工方案
- (教研室)福建省宁德市2024-2025学年高二上学期期末考试语文试题
- 扬尘施工方案
- 预制滤板施工方案
- 2025年柳工营销面试题及答案
- 6年级上册20课青山不老课堂笔记
- 教育教学评价表
- 低空经济产业专项引导基金
- 《制造业信息化》课件
- 湘教版地理八年级下册 期末综合测试卷(二)(含答案)
- 2024年度股权激励代持协议
- 北师大版(2024新版)七年级上册数学全册教案
- 2024年上海市安全员B证(项目负责人)考试试题题库
- 食品安全、消防安全、交通安全
- 建筑施工企业新员工三级安全教育培训
- 变频器实训报告
- 无人机团体培训课件
- 汽车检测技术课件 任务二 检测汽车动力性能
- 地测防治水技能竞赛理论考试题库(含答案)
评论
0/150
提交评论