下载

1下载券

加入VIP
  • 专属下载特权
  • 现金文档折扣购买
  • VIP免费专区
  • 千万文档免费下载

上传资料

关闭

关闭

关闭

封号提示

内容

首页 vc++五子棋论文正文

vc++五子棋论文正文.doc

vc++五子棋论文正文

苏惮
2011-06-14 0人阅读 举报 0 0 暂无简介

简介:本文档为《vc++五子棋论文正文doc》,可适用于IT/计算机领域

毕业设计说明书 引言 五子棋介绍五子棋是起源于中国古代的传统黑白棋种之一。现代五子棋日文称之为“連珠”英译为“Renju”英文称之为“Gobang”或“FIR”(FiveinaRow的缩写)亦有“连五子”、“五子连”、“串珠”、“五目”、“五目碰”、“五格”等多种称谓。五子棋不仅能增强思维能力提高智力而且富含哲理有助于修身养性。五子棋既有现代休闲的明显特征“短、平、快”又有古典哲学的高深学问“阴阳易理”它既有简单易学的特性为人民群众所喜闻乐见又有深奥的技巧和高水平的国际性比赛它的棋文化源渊流长具有东方的神秘和西方的直观既有“场”的概念亦有“点”的连接。它是中西文化的交流点是古今哲理的结晶。 开发背景当前网络上流传的五子棋游戏功能并不尽善尽美其中最主要的问题就是人机对战和网络对战不能够一起实现所以我决定开发一个既能够人机对战又能够进行网络对战的五子棋系统。 开发环境及运行环境 开发环境​ Intel®Pentium®GHzM内存G硬盘​ Microsoft®Windows™Professional​ Microsoft®VisualC​ Microsoft®DeveloperNetworkforVisualStudioNET​ VisualAssistX 运行环境​ Intel®Pentium®及以上处理器M以上内存G以上硬盘​ Microsoft®Windows™XNT操作系统​ *或以上的屏幕分辨率 软件架构软件的总体架构如图:图软件架构考虑到整个的下棋过程(无论对方是电脑抑或其他网络玩家)可以分为:己方落子、等待对方落子、对方落子、设置己方棋盘数据这一系列过程因此一人游戏类、二人游戏类和棋盘类之间的关系参考了AbstractFactory(抽象工厂)模式以实现对两个不同模块进行一般化的控制。 棋盘类整个架构的核心部分类名为CTable。封装了棋盘的各种可能用到的功能如保存棋盘数据、初始化、判断胜负等。用户操作主界面主界面与CTable进行交互来完成对游戏的操作。 游戏模式类用来管理人机对弈网络对弈两种游戏模式类名为CGame。CGame是一个抽象类经由它派生出一人游戏类COneGame和网络游戏类CTwoGame如图:图CGame类派生关系这样CTable类就可以通过一个CGame类的指针在游戏初始化的时候根据具体游戏模式的要求实例化COneGame或CTwoGame类的对象然后利用多态性使用CGame类提供的公有接口就可以完成不同游戏模式下的不同功能了。 棋盘类CTable 主要成员变量说明 网络连接标志mbConnected用来表示当前网络连接的情况在网络对弈游戏模式下客户端连接服务器的时候用来判断是否连接成功事实上它也是区分当前游戏模式的唯一标志。 棋盘等待标志mbWait与mbOldWait由于在玩家落子后需要等待对方落子mbWait标志就用来标识棋盘的等待状态。当mbWait为TRUE时是不允许玩家落子的。在网络对弈模式下玩家之间需要互相发送诸如悔棋、和棋这一类的请求消息在发送请求后等待对方回应时也是不允许落子的所以需要将mbWait标志置为TRUE。在收到对方回应后需要恢复原有的棋盘等待状态所以需要另外一个变量在发送请求之前保存棋盘的等待状态做恢复之用也就是mbOldWait。等待标志的设置由成员函数SetWait和RestoreWait完成。 网络套接字msock和mconn在网络对弈游戏模式下需要用到这两个套接字对象。其中msock对象用于做服务器时的监听之用mconn用于网络连接的传输。 棋盘数据mdata这是一个*的二位数组用来保存当前棋盘的落子数据。其中对于每个成员来说表示落黑子表示落白子表示无子。 游戏模式指针mpGame这个CGame类的对象指针是CTable类的核心内容。它所指向的对象实体决定了CTable在执行一件事情时候的不同行为具体的内容请参见“游戏模式”一节。 主要成员函数说明 套接字的回调处理Accept、Connect、Receive本程序的套接字派生自MFC的CAsyncSocket类CTable的这三个成员函数就分别提供了对套接字回调事件OnAccept、OnConnect、OnReceive的实际处理其中尤以Receive成员函数重要它之中包含了对所有网络消息(参见“消息机制”一节)的分发处理。 清空棋盘Clear在每一局游戏开始的时候都需要调用这个函数将棋盘清空也就是棋盘的初始化工作。在这个函数中主要发生了这么几件事情:​ 将mdata中每一个落子位都置为无子状态()。​ 按照传入的参数设置棋盘等待标志mbWait以供先、后手的不同情况之用。​ 使用delete将mpGame指针所指向的原有游戏模式对象从堆上删除。 绘制棋子Draw这无疑是很重要的一个函数它根据参数给定的坐标和颜色绘制棋子。绘制的详细过程如下:​ 将给定的棋盘坐标换算为绘图的像素坐标。​ 根据坐标绘制棋子位图。​ 如果先前曾下过棋子则利用RNOTXORPEN将上一个绘制棋子上的最后落子指示矩形擦除。​ 在刚绘制完成的棋子四周绘制最后落子指示矩形。 左键消息OnLButtonUp作为棋盘唯一响应的左键消息也需要做不少的工作:​ 如果棋盘等待标志mbWait为TRUE则直接发出警告声音并返回即禁止落子。​ 如果点击时的鼠标坐标在合法坐标(,)~(,)之外亦禁止落子。​ 如果走的步数大于步方才允许悔棋。​ 进行胜利判断如胜利则修改UI状态并增加胜利数的统计。​ 如未胜利则向对方发送已经落子的消息。​ 落子完毕将mbWait标志置为TRUE开始等待对方回应。 绘制棋盘OnPaint每当WMPAINT消息触发时都需要对棋盘进行重绘。OnPaint作为响应绘制消息的消息处理函数使用了双缓冲技术减少了多次绘图可能导致的图像闪烁问题。这个函数主要完成了以下工作:​ 装载棋盘位图并进行绘制。​ 根据棋盘数据绘制棋子。​ 绘制最后落子指示矩形。 对方落子完毕Over在对方落子之后仍然需要做一些判断工作这些工作与OnLButtonUp中的类似在此不再赘述。 设置游戏模式SetGameMode这个函数通过传入的游戏模式参数对mpGame指针进行了初始化代码如下:voidCTable::SetGameMode(intnGameMode){if(==nGameMode)mpGame=newCOneGame(this)elsempGame=newCTwoGame(this)mpGame>Init()}这之后就可以利用OO的继承和多态特点来使mpGame指针使用相同的调用来完成不同的工作了事实上COneGame::Init和CTwoGame::Init都是不同的。 胜负的判断Win这是游戏中一个极其重要的算法用来判断当前棋盘的形势是哪一方获胜。其详细内容请参见“主要算法”一节。 游戏模式类CGame这个类负责对游戏模式进行管理以及在不同的游戏模式下对不同的用户行为进行不同的响应。由于并不需要CGame本身进行响应所以将其设计为了一个纯虚类它的定义如下:classCGame{protected:CTable*mpTablepublic:落子步骤list<STEP>mStepListpublic:构造函数CGame(CTable*pTable):mpTable(pTable){}析构函数virtual~CGame()初始化工作不同的游戏方式初始化也不一样virtualvoidInit()=处理胜利后的情况CTwoGame需要改写此函数完成善后工作virtualvoidWin(constSTEPstepSend)发送己方落子virtualvoidSendStep(constSTEPstepSend)=接收对方消息virtualvoidReceiveMsg(MSGSTRUCT*pMsg)=发送悔棋请求virtualvoidBack()=} 主要成员变量说明 棋盘指针mpTable由于在游戏中需要对棋盘以及棋盘的父窗口主对话框进行操作及UI状态设置故为CGame类设置了这个成员。当对主对话框进行操作时可以使用mpTable>GetParent()得到它的窗口指针。 落子步骤mStepList一个好的棋类程序必须要考虑到的功能就是它的悔棋功能所以需要为游戏类设置一个落子步骤的列表。由于人机对弈和网络对弈中都需要这个功能故将这个成员直接设置到基类CGame中。另外考虑到使用的简便性这个成员使用了C标准模板库(StandardTemplateLibrarySTL)中的std::list而不是MFC的CList。 主要成员函数说明 悔棋操作Back在不同的游戏模式下悔棋的行为是不一样的。​ 人机对弈模式下计算机是完全允许玩家悔棋的但是出于对程序负荷的考虑(此原因请参见“几点补充说明”一节)只允许玩家悔当前的两步棋(计算机一步玩家一步)。​ 双人网络对弈模式下悔棋的过程为:首先由玩家向对方发送悔棋请求(悔棋消息)然后由对方决定是否允许玩家悔棋在玩家得到对方的响应消息(允许或者拒绝)之后才进行悔棋与否的操作。 初始化操作Init对于不同的游戏模式而言也就有不同的初始化方式。对于人机对弈模式而言初始化操作包括以下几个步骤:​ 设置网络连接状态mbConnected为FALSE。​ 设置主界面计算机玩家的姓名。​ 初始化所有的获胜组合。​ 如果是计算机先走则占据天元(棋盘正中央)的位置。网络对弈的初始化工作暂为空以供以后扩展之用。 接收来自对方的消息ReceiveMsg这个成员函数由CTable棋盘类的Receive成员函数调用用于接收来自对方的消息。对于人机对弈游戏模式来说所能接收到的就仅仅是本地模拟的落子消息MSGPUTSTEP对于网络对弈游戏模式来说这个成员函数则负责从套接字读取对方发过来的数据然后将这些数据解释为自定义的消息结构并回到CTable::Receive来进行处理。 发送落子消息SendStep在玩家落子结束后要向对方发送自己落子的消息。对于不同的游戏模式发送的目标也不同:​ 对于人机对弈游戏模式将直接把落子的信息(坐标、颜色)发送给COneGame类相应的计算函数。​ 对于网络对弈游戏模式将把落子消息发送给套接字并由套接字转发给对方。 胜利后的处理Win这个成员函数主要针对CTwoGame网络对弈模式。在玩家赢得棋局后这个函数仍然会调用SendStep将玩家所下的制胜落子步骤发送给对方玩家然后对方的游戏端经由CTable::Win来判定自己失败。 消息机制Windows系统拥有自己的消息机制在不同事件发生的时候系统也可以提供不同的响应方式。五子棋程序也模仿Windows系统实现了自己的消息机制主要为网络对弈服务以响应多种多样的网络消息。 消息机制的架构当继承自CAsyncSocket的套接字类CFiveSocket收到消息时会触发CFiveSocket::OnReceive事件在这个事件中调用CTable::ReceiveCTable::Receive开始按照自定义的消息格式接收套接字发送的数据并对不同的消息类型进行分发处理。图自定义的消息机制如图所示当CTable获得了来自网络的消息之后就可以使用一个switch结构来进行消息的分发了。 各种消息说明网络间传递的消息都遵循以下一个结构体的形式:摘自MessageshtypedefstructtagMsgStruct{消息IDUINTuMsg落子信息intxintyintcolor消息内容TCHARszMsg}MSGSTRUCT随着uMsg表示消息IDx、y表示落子的坐标color表示落子的颜色szMsg随着uMsg的不同而有不同的含义。 落子消息MSGPUTSTEP表明对方落下了一个棋子其中x、y和color成员有效szMsg成员无效。在人机对弈游戏模式下亦会模拟发送此消息以达到程序模块一般化的效果。 悔棋消息MSGBACK表明对方请求悔棋除uMsg成员外其余成员皆无效。接到这个消息后会弹出MessageBox询问是否接受对方的请求(如图所示)并根据玩家的选择回返MSGAGREEBACK或MSGREFUSEBACK消息。另外在发送这个消息之后主界面上的某些元素将不再响应用户的操作。图请求悔棋 同意悔棋消息MSGAGREEBACK表明对方接受了玩家的悔棋请求除uMsg成员外其余成员皆无效。接到这个消息后将进行正常的悔棋操作。 拒绝悔棋消息MSGREFUSEBACK表明对方拒绝了玩家的悔棋请求(如图所示)除uMsg成员外其余成员皆无效。接到这个消息后整个界面将恢复发送悔棋请求前的状态。图拒绝悔棋 和棋消息MSGDRAW表明对方请求和棋除uMsg成员外其余成员皆无效。接到这个消息后会弹出MessageBox询问是否接受对方的请求(如图所示)并根据玩家的选择回返MSGAGREEDRAW或MSGREFUSEDRAW消息。另外在发送这个消息之后主界面上的某些元素将不再响应用户的操作。图请求和棋 同意和棋消息MSGAGREEDRAW表明对方接受了玩家的和棋请求(如图所示)除uMsg成员外其余成员皆无效。接到这个消息后双方和棋。图同意和棋 拒绝和棋消息MSGREFUSEDRAW表明对方拒绝了玩家的和棋请求(如图所示)除uMsg成员外其余成员皆无效。接到这个消息后整个界面将恢复发送和棋请求前的状态。图拒绝和棋 认输消息MSGGIVEUP表明对方已经投子认输(如图所示)除uMsg成员外其余成员皆无效。接到这个消息后整个界面将转换为胜利后的状态。图认输 聊天消息MSGCHAT表明对方发送了一条聊天信息szMsg表示对方的信息其余成员无效。接到这个信息后会将对方聊天的内容显示在主对话框的聊天记录窗口内。 对方信息消息MSGINFORMATION用来获取对方玩家的姓名szMsg表示对方的姓名其余成员无效。在开始游戏的时候由客户端向服务端发送这条消息服务端接到后设置对方的姓名并将自己的姓名同样用这条消息回发给客户端。 再次开局消息MSGPLAYAGAIN表明对方希望开始一局新的棋局除uMsg成员外其余成员皆无效。接到这个消息后会弹出MessageBox询问是否接受对方的请求(如图所示)并根据玩家的选择回返MSGAGREEAGAIN消息或直接断开网络。图再次开局 同意再次开局消息MSGAGREEAGAIN表明对方同意了再次开局的请求除uMsg成员外其余成员皆无效。接到这个消息后将开启一局新游戏。 主要算法五子棋游戏中有相当的篇幅是算法的部分。无论是人机对弈还是网络对弈都需要合理算法的支持本节中将详细介绍五子棋中使用的算法。 判断胜负五子棋的胜负在于判断棋盘上是否有一个点从这个点开始的右、下、右下、左下四个方向是否有连续的五个同色棋子出现如图:图判断胜负方向这个算法也就是CTable的Win成员函数。从设计的思想上需要它接受一个棋子颜色的参数然后返回一个布尔值这个值来指示是否胜利代码如下:BOOLCTable::Win(intcolor)const{intx,y判断横向for(y=y<y){for(x=x<x){if(color==mdataxycolor==mdataxycolor==mdataxycolor==mdataxycolor==mdataxy){returnTRUE}}}判断纵向for(y=y<y){for(x=x<x){if(color==mdataxycolor==mdataxycolor==mdataxycolor==mdataxycolor==mdataxy){returnTRUE}}}判断“”方向for(y=y<y){for(x=x<x){if(color==mdataxycolor==mdataxycolor==mdataxycolor==mdataxycolor==mdataxy){returnTRUE}}}判断“”方向for(y=y<y){for(x=x<x){if(color==mdataxycolor==mdataxycolor==mdataxycolor==mdataxycolor==mdataxy){returnTRUE}}}不满足胜利条件returnFALSE}需要说明的一点是由于这个算法所遵循的搜索顺序是从左到右、自上而下因此在每次循环的时候都有一些坐标无需纳入考虑范围。例如对于横向判断而言由于右边界所限因而所有横坐标大于等于的点都构不成达到五子连的条件所以横坐标的循环上界也就定为这样也就提高了搜索的速度。 人机对弈算法人机对弈算法完全按照CGame基类定义的接口标准封装在了COneGame派生类之中。下面将对这个算法进行详细地介绍。 获胜组合获胜组合是一个三维数组它记录了所有取胜的情况。也就是说参考于CTable::Win中的情况对于每一个落子坐标获胜的组合一共有****=种。而对于每个坐标的获胜组合应该设置一个大小的三维数组。在拥有了这些获胜组合之后就可以参照每个坐标的种组合给自己的局面和玩家的局面进行打分也就是根据当前盘面中某一方所拥有的获胜组合多少进行权值的估算给出最有利于自己的一步落子坐标。由于是双方对弈所以游戏的双方都需要一份获胜组合也就是:boolmComputer电脑获胜组合boolmPlayer玩家获胜组合在每次游戏初始化(COneGame::Init)的时候需要将每个坐标下可能的获胜组合都置为true。此外还需要设置计算机和玩家在各个获胜组合中所填入的棋子数:intmWin在初始化的时候将每个棋子数置为。 落子后处理每当一方落子后都需要作如下处理:​ 如果己方此坐标的获胜组合仍为true且仍有可能在此获胜组合处添加棋子则将此获胜组合添加棋子数加​ 如果对方此坐标的获胜组合仍为true则将对方此坐标的获胜组合置为false并将对方此获胜组合添加棋子数置为(不可能靠此组合获胜)。以玩家落子为例代码为:for(i=i<i){修改状态变化if(mPlayerstepPutxstepPutyimWini!=)mWiniif(mComputerstepPutxstepPutyi){mComputerstepPutxstepPutyi=falsemWini=}} 查找棋盘空位在计算机落子之前需要查找棋盘的空位所以需要一个SearchBlank成员函数完成此项工作此函数需要进行不重复的查找也就是说对已查找过的空位进行标记并返回找到空位的坐标其代码如下:boolCOneGame::SearchBlank(inti,intj,intnowTable){intx,yfor(x=x<x){for(y=y<y){if(nowTablexy==nowTablexy!=){i=xj=yreturntrue}}}returnfalse} 落子打分找到空位后需要对这个点的落子进行打分这个分数也就是这个坐标重要性的体现代码如下:intCOneGame::GiveScore(constSTEPstepPut){inti,nScore=for(i=i<i){if(mpTable>GetColor()==stepPutcolor){玩家下if(mPlayerstepPutxstepPutyi){switch(mWini){case:nScore=breakcase:nScore=breakcase:nScore=breakcase:nScore=breakdefault:break}}}else{计算机下if(mComputerstepPutxstepPutyi){switch(mWini){case:nScore=breakcase:nScore=breakcase:nScore=breakcase:nScore=breakdefault:break}}}}returnnScore}如代码所示考虑到攻守两方面的需要所以将玩家落子给的分数置为负值。 防守策略落子的考虑不单单要从进攻考虑还要从防守考虑。这一细节的实现其实就是让计算机从玩家棋盘布局分析战况然后找出对玩家最有利的落子位置。整个过程如下:for(m=m<m){暂时更改玩家信息if(mPlayerijm){tempn=mmPlayerijm=falsetempn=mWinmmWinm=n}}ptempTableij=pi=ipj=jwhile(SearchBlank(i,j,ptempTable)){ptempTableij=标记已被查找stepcolor=mpTable>GetColor()stepx=istepy=jptemp=GiveScore(step)if(pscore>ptemp)此时为玩家下子运用极小极大法时应选取最小值pscore=ptemp}for(m=m<nm){恢复玩家信息mPlayerpipjtempm=truemWintempm=tempm} 选取最佳落子在循环结束的时候就可以根据攻、守两方面的打分综合地考虑落子位置了。代码如下:if(ctemppscore>cscore){cscore=ctemppscorebestx=pibesty=pj}在这之后重新改变一下棋盘的状态()即可。 几点补充说明​ 考虑到程序的响应速度人机对弈算法只对玩家的棋子进行了一步的推测。​ 由于计算机在落子时选取的是得分最高的一步落子所以如果玩家在开局的时候不改变落子步骤那么将会获得从头至尾相同的棋局。​ 考虑到下棋同时还要聊天所以并未对落子时间加入任何限制同样如果玩家离开游戏也不会判负。​ 对于人机对弈的悔棋处理由于这个算法的开销相当大每一步落子都会存在不同的棋盘布局所以实现从头到尾的悔棋不是很现实(将会存在过多的空间保存棋盘布局)因而在人机对弈模式下只允许玩家悔最近的两步落子。 心得体会通过编写这个程序我体会最为深刻的一点是系统架构和设计模式的重要性。即使是对于一个并不大的程序代码的组织都是非常重要的因为这关系到日后的维护以及扩展。这个游戏之中有关网络Socket编程或者博弈树算法的知识都可以直接从无所不包的Internet上获取甚至可以直接获得一个完整的五子棋人机对弈算法的源代码级模块。但是对于系统的架构却完全是自己的事情几千上万行的代码需要通过合适的方法组织起来使程序员编写代码更加有条理更加符合软件工程的标准这才是最重要的。在刚开始编写这个程序的时候我幼稚地认为其中最重要的是博弈树算法。但是头一个月编写程序的时候却发现程序越写越不容易维护可见是我走错了方向。后来我向公司真正的软件设计人员及系统架构师讨教他们告诉我:我们的先人早已为我们准备好了各种精良可用的现成算法我们所要做的就是直接“拿来主义”罢了但是对于代码的组织(也就是软件的架构)才是真正软件工业的核心部分因为软件事实上是直接和经济挂钩的因此我们必须在编写代码之前选择一种最为合适的方法来组织这些代码否则我们将会失去更多的时间和金钱。于是我将以前写的代码全部删除认真地思考了三天的时间。我也在这三天内真正从一个学生程序员走入了软件开发的大门我开始发现其实软件开发并不是纯数学正相反数学只占了很小的一部分。它其实是一种哲学一种有着数学美感的哲学。参考文献​ MSDNforVisualStudio​ 设计模式可复用面向对象软件的基础ErichGammaRichardHelmRalphJohnsonJohnVlissides著李英军马晓星蔡敏刘建中等译机械工业出版社​ 深入浅出MFC(第版)侯俊杰著华中科技大学出版社​ ABeginner'sGuidetoPointersAndrewPeacehttp:wwwcodeprojectcomcpppointersasp​ 水煮多态titilimahttp:homenuceducn~titilimareadarticlephpid=​ Microsoft®VisualCNET技术内幕(第版)GeorgeShepherdDavidKruglinski著潘爱民译清华大学出版社​ VisualC网络通信协议分析与应用实现汪晓平钟军等编著人民邮电出版社​ C编程思想BruceEckel著刘宗田邢大红孙慧杰等译机械工业出版社​ 天学通CJesseLiberty著康博创作室译人民邮电出版社​ C标准程序库NicolaiMJosuttis著侯捷孟岩译华中科技大学出版社​ Windows程序设计CharlesPetzold著北京博彦科技发展有限公司译北京大学出版社​ VisualCNET网络编程易君编著中国铁道出版社​ 博弈树搜索http:wlkcrengongzhinengrengongzhinengkejianAIAichapterhtm​ 五子棋的核心算法蝈蝈俊nethttp:blogjoycodecomghjarticlesaspx​ 道法自然王咏武王咏刚著电子工业出版社致谢感谢我的父母没有您们的包容和支持就不会有我的今天。感谢我的导师康珺老师您开明地为我进京实习提供了那么多便利条件。感谢北京灵图软件技术有限公司为我无偿提供了开发环境。感谢kedy谢谢你为我提供的代理服务器让我在学校的时候能够及时上网获取资料。在此祝福你能在金山开创美好的未来。感谢中北大学信息中心的唐道光学长为我解释了很多网络连接的知识。感谢武汉大学的姜舸同学谢谢你在工作之余和我一起进行CAsyncSocket部分的测试。感谢的所有兄弟尤其是黑皮和RedBad谢谢你们在我离校期间为我所作的一切。感谢不一样的鱼、hottey、赵晋辉、杜琳和赵序庚同学谢谢你们在测试期提供的帮助和修改意见。感谢APTX字幕组谢谢你们提供的《名侦探柯南》。尤其是情报员源源谢谢你一直以来为我提供的一切便利条件。感谢RockstarGames公司你们的GrandTheftAuto:ViceCity伴我度过了下班后的无聊时光。

用户评价(0)

关闭

新课改视野下建构高中语文教学实验成果报告(32KB)

抱歉,积分不足下载失败,请稍后再试!

提示

试读已结束,如需要继续阅读或者下载,敬请购买!

文档小程序码

使用微信“扫一扫”扫码寻找文档

1

打开微信

2

扫描小程序码

3

发布寻找信息

4

等待寻找结果

我知道了
评分:

/28

vc++五子棋论文正文

VIP

在线
客服

免费
邮箱

爱问共享资料服务号

扫描关注领取更多福利