第1页共30页1引言1.1五子棋介绍五子棋是起源于中国古代的传统黑白棋种之一。现代五子棋日文称之为“連珠”,英译为“Renju”,英文称之为“Gobang”或“FIR”(FiveinaRow的缩写),亦有“连五子”、“五子连”、“串珠”、“五目”、“五目碰”、“五格”等多种称谓。五子棋不仅能增强思维能力,提高智力,而且富含哲理,有助于修身养性。五子棋既有现代休闲的明显特征“短、平、快”,又有古典哲学的高深学问“阴阳易理”;它既有简单易学的特性,为人民群众所喜闻乐见,又有深奥的技巧和高水平的国际性比赛;它的棋文化源渊流长,具有东方的神秘和西方的直观;既有“场”的概念,亦有“点”的连接。它是中西文化的交流点,是古今哲理的结晶。1.2开发背景当前网络上流传的五子棋游戏功能并不尽善尽美,其中最主要的问题就是人机对战和网络对战不能够一起实现,所以我决定开发[1]一个既能够人机对战,又能够进行网络对战的五子棋系统。1.3开发环境及运行环境1.3.1开发环境Intel®Pentium®42.0GHz,512M内存,80G硬盘Microsoft®Windows™2000ProfessionalMicrosoft®VisualC++6.0Microsoft®DeveloperNetworkforVisualStudio.NET2003VisualAssistX10.1.1301.01.3.2运行环境Intel®Pentium®2及以上处理器,32M以上内存,4G以上硬盘Microsoft®Windows™9X/NT操作系统800*600或以上的屏幕分辨率第2页共30页2软件架构软件的总体架构如图2.1:图2.1软件架构考虑到整个的下棋过程(无论对方是电脑抑或其他网络玩家)可以分为:己方落子、等待对方落子、对方落子、设置己方棋盘数据这一系列过程,因此一人游戏类、二人游戏类和棋盘类之间的关系参考了AbstractFactory(抽象工厂)模式,以实现对两个不同模块进行一般化的控制。[2]2.1棋盘类整个架构的核心部分,类名为CTable。封装了棋盘的各种可能用到的功能[3],如保存棋盘数据、初始化、判断胜负等。用户操作主界面,主界面与CTable进行交互来完成对游戏的操作。2.2游戏模式类用来管理人机对弈/网络对弈两种游戏模式,类名为CGame。CGame是一个抽一人游戏类二人游戏类棋盘类主界面用户游戏类指针第3页共30页象类,经由它派生出一人游戏类COneGame和网络游戏类CTwoGame,如图2.2:图2.2CGame类派生关系这样,CTable类就可以通过一个CGame类的指针[4],在游戏初始化的时候根据具体游戏模式的要求实例化COneGame或CTwoGame类的对象;然后利用多态性[5],使用CGame类提供的公有接口就可以完成不同游戏模式下的不同功能了。抽象类CGameCOneGameCTwoGame第4页共30页3棋盘类——CTable3.1主要成员变量说明3.1.1网络连接标志——m_bConnected用来表示当前网络连接的情况,在网络对弈游戏模式下客户端连接服务器的时候用来判断是否连接成功;事实上,它也是区分当前游戏模式的唯一标志。3.1.2棋盘等待标志——m_bWait与m_bOldWait由于在玩家落子后需要等待对方落子,m_bWait标志就用来标识棋盘的等待状态。当m_bWait为TRUE时,是不允许玩家落子的。在网络对弈模式下,玩家之间需要互相发送诸如悔棋、和棋这一类的请求消息,在发送请求后等待对方回应时,也是不允许落子的,所以需要将m_bWait标志置为TRUE。在收到对方回应后,需要恢复原有的棋盘等待状态,所以需要另外一个变量在发送请求之前保存棋盘的等待状态做恢复之用,也就是m_bOldWait。等待标志的设置,由成员函数SetWait和RestoreWait完成。3.1.3网络套接字——m_sock和m_conn在网络对弈游戏模式下,需要用到这两个套接字对象。其中m_sock对象用于做服务器时的监听之用,m_conn用于网络连接的传输。3.1.4棋盘数据——m_data这是一个15*15的二位数组,用来保存当前棋盘的落子数据。其中对于每个成员来说,0表示落黑子,1表示落白子,-1表示无子。3.1.5游戏模式指针——m_pGame这个CGame类的对象指针是CTable类的核心内容。它所指向的对象实体决第5页共30页定了CTable在执行一件事情时候的不同行为,具体的内容请参见“游戏模式”一节。3.2主要成员函数说明3.2.1套接字的回调处理——Accept、Connect、Receive本程序的套接字派生自MFC的CAsyncSocket类[6],CTable的这三个成员函数就分别提供了对套接字[7]回调事件OnAccept、OnConnect、OnReceive的实际处理,其中尤以Receive成员函数重要,它之中包含了对所有网络消息(参见“消息机制”一节)的分发处理。3.2.2清空棋盘——Clear在每一局游戏开始的时候都需要调用这个函数将棋盘清空,也就是棋盘的初始化工作。在这个函数中,主要发生了这么几件事情:将m_data中每一个落子位都置为无子状态(-1)。按照传入的参数设置棋盘等待标志m_bWait,以供先、后手的不同情况之用。使用delete将m_pGame指针所指向的原有游戏模式对象从堆上删除。3.2.3绘制棋子——Draw这无疑是很重要的一个函数,它根据参数给定的坐标和颜色绘制棋子。绘制的详细过程如下:将给定的棋盘坐标换算为绘图的像素坐标。根据坐标绘制棋子位图。如果先前曾下过棋子,则利用R2_NOTXORPEN将上一个绘制棋子上的最后落子指示矩形擦除。在刚绘制完成的棋子四周绘制最后落子指示矩形。第6页共30页3.2.4左键消息——OnLButtonUp作为棋盘唯一响应的左键消息,也需要做不少的工作:如果棋盘等待标志m_bWait为TRUE,则直接发出警告声音并返回,即禁止落子。如果点击时的鼠标坐标在合法坐标(0,0)~(14,14)之外,亦禁止落子。如果走的步数大于1步,方才允许悔棋。进行胜利判断,如胜利则修改UI状态并增加胜利数的统计。如未胜利,则向对方发送已经落子的消息。落子完毕,将m_bWait标志置为TRUE,开始等待对方回应。3.2.5绘制棋盘——OnPaint每当WM_PAINT消息触发时,都需要对棋盘进行重绘。OnPaint作为响应绘制消息的消息处理函数使用了双缓冲技术,减少了多次绘图可能导致的图像闪烁问题。这个函数主要完成了以下工作:装载棋盘位图并进行绘制。根据棋盘数据绘制棋子。绘制最后落子指示矩形。3.2.6对方落子完毕——Over在对方落子之后,仍然需要做一些判断工作,这些工作与OnLButtonUp中的类似,在此不再赘述。3.2.7设置游戏模式——SetGameMode这个函数通过传入的游戏模式参数对m_pGame指针进行了初始化,代码如下:voidCTable::SetGameMode(intnGameMode){if(1==nGameMode)第7页共30页m_pGame=newCOneGame(this);elsem_pGame=newCTwoGame(this);m_pGame-Init();}这之后,就可以利用OO的继承和多态特点[8]来使m_pGame指针使用相同的调用来完成不同的工作了,事实上,COneGame::Init和CTwoGame::Init都是不同的。3.2.8胜负的判断——Win这是游戏中一个极其重要的算法,用来判断当前棋盘的形势是哪一方获胜。其详细内容请参见“主要算法”一节。第8页共30页4游戏模式类——CGame这个类负责对游戏模式进行管理,以及在不同的游戏模式下对不同的用户行为进行不同的响应。由于并不需要CGame本身进行响应,所以将其设计为了一个纯虚类[9],它的定义如下:classCGame{protected:CTable*m_pTable;public://落子步骤listSTEPm_StepList;public://构造函数CGame(CTable*pTable):m_pTable(pTable){}//析构函数virtual~CGame();//初始化工作,不同的游戏方式初始化也不一样virtualvoidInit()=0;//处理胜利后的情况,CTwoGame需要改写此函数完成善后工作virtualvoidWin(constSTEP&stepSend);//发送己方落子virtualvoidSendStep(constSTEP&stepSend)=0;//接收对方消息第9页共30页virtualvoidReceiveMsg(MSGSTRUCT*pMsg)=0;//发送悔棋请求virtualvoidBack()=0;};4.1主要成员变量说明4.1.1棋盘指针——m_pTable由于在游戏中需要对棋盘以及棋盘的父窗口——主对话框进行操作及UI状态设置,故为CGame类设置了这个成员。当对主对话框进行操作时,可以使用m_pTable-GetParent()得到它的窗口指针。4.1.2落子步骤——m_StepList一个好的棋类程序必须要考虑到的功能就是它的悔棋功能,所以需要为游戏类设置一个落子步骤的列表。由于人机对弈和网络对弈中都需要这个功能,故将这个成员直接设置到基类CGame中。另外,考虑到使用的简便性,这个成员使用了C++标准模板库[10](StandardTemplateLibrary,STL)中的std::list,而不是MFC的CList。4.2主要成员函数说明4.2.1悔棋操作——Back在不同的游戏模式下,悔棋的行为是不一样的。人机对弈模式下,计算机是完全允许玩家悔棋的,但是出于对程序负荷的考虑(此原因请参见“几点补充说明”一节),只允许玩家悔当前的两步棋(计算机一步,玩家一步)。双人网络对弈模式下,悔棋的过程为:首先由玩家向对方发送悔棋请求(悔棋消息),然后由对方决定是否允许玩家悔棋,在玩家得到对方的响应消息(允许或者拒绝)之后,才进行悔棋与否的操作。第10页共30页4.2.2初始化操作——Init对于不同的游戏模式而言,也就有不同的初始化方式。对于人机对弈模式而言,初始化操作包括以下几个步骤:设置网络连接状态m_bConnected为FALSE。设置主界面计算机玩家的姓名。初始化所有的获胜组合。如果是计算机先走,则占据天元(棋盘正中央)的位置。网络对弈的初始化工作暂为空,以供以后扩展之用。4.2.3接收来自对方的消息——ReceiveMsg这个成员函数由CTable棋盘类的Receive成员函数调用,用于接收来自对方的消息。对于人机对弈游戏模式来说,所能接收到的就仅仅是本地模拟的落子消息MSG_PUTSTEP;对于网络对弈游戏模式来说,这个成员函数则负责从套接字读取对方发过来的数据,然后将这些数据解释为自定义的消息结构,并回到CTable::Receive来进行处理。4.2.4发送落子消息——SendStep在玩家落子结束后,要向对方发送自己落子的消息。对于不同的游戏模式,发送的目标也不同:对于人机对弈游戏模式,将直接把落子的信息(坐标、颜色)发送给COneGame类相应的计算函数。对于网络对弈游戏模式,将把落子消息发送给套接字,并由套接字转发给对方。4.2.5胜利后的处理——Win第11页共30页这个成员函数主要针对CTwoGame网络对弈模式。在玩家赢得棋局后,这个函数仍然会调用SendStep将玩家所下的制胜落子步骤发送给对方玩家,然后对方的游戏端经由CTable::Win来判定自己失败。第12页共30页5消息机制Windows系统拥有自己的消息机制,在不同事件发生的时候,系统也可以提供不同的响应方式[11]。五子棋程序也模仿Windows系统实现了自己的消息机制,主要为网络对弈服务,以响应多种多样的网络消息。5.