网络五子棋的设计与实现论文
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
摘要
五子棋游戏以其优秀的人工智能深受广大玩家的喜爱,而对于初步探究网络编成的编程爱好者来说,编制五子棋程序因其规则简单而大受欢迎,然而它却要求程序员对五子棋规则有相当深入的了解。
程序员考虑得越周到,其五子棋程序就越智能。
五子棋游戏软件设计的主要内容是:根据五子棋的基本规则,要让对方客户端知道该在哪一点下子,就要根据盘面的形势,并把棋盘棋子的重新绘制绘制,也就是更新该点的位置,然后再通过监听网络传递的消息,直到新的位置放在棋盘的什么位置上,在进行修改,并通过计算,得出玩家是否获得胜利.,因此玩家就能反复的进行联机游戏。
本文论述了采用联机对战的方式体现出五子棋程序的分析与设计,并采用面向对象的开发工具VC++来具体实现。
关键词:五子棋,VC++,面向对象
Abstract
Wuziqi game with excellent artificial intelligence by the vast number of players who, for the initial research network organization programming enthusiasts, Wuziqi procedures for the preparation of the rules simple and popular, but it requires programmer to Wuziqi game has a deep understanding of the rules. Other thoughtful consideration they treat their Wuziqi game procedures more wisdom.
Wuziqi game software design is the main content: According Wuziqi basic rules to know each other's customers - in violation of the West, we must under Permian situation, and the board pawn re-mapping mapping, that is updating the point position, and then through the monitoring network news until the new location on the board what position, Following changes, and through the calculation, resulting in players is victory. , the on-line game players can repeatedly.
This article discusses the use of on-line way reflect those Wuziqi procedures analysis and design, object-oriented development tools and the adoption of specific VC++ to achieve.
Key Words : Wuziqi, VC++, object-oriented
目录
摘要 (1)
ABSTRACT (2)
第一章引言 (4)
1.1课题背景 (4)
1.1.1背景知识 (4)
1.1.2五子棋游戏的规则 (5)
1.1.3开发系统的几点建议 (5)
1.2相关技术介绍 (6)
1.2.1结构化生命周期法简介 (6)
1.2.2开发技术——快速原型法简介 (7)
1.2.3本系统开发方法的选择 (7)
第二章系统目标 (7)
第三章系统需求分析 (8)
3.1系统需求 (8)
3.2功能需求 (8)
3.3系统运行环境 (8)
3.4MFC简述 (8)
3.5服务器与客户端SOCKET设计 (9)
第四章系统设计 (9)
4.1概要设计 (9)
4.2流程图 (10)
4.3详细设计 (12)
4.3.1钩子的使用 (12)
4.4程序设计 (13)
4.4.1 程序窗口的设计 (13)
第五章结论 (20)
5.1关键技术 (20)
5.2总结 (20)
第六章设计总结 (21)
第七章谢辞 (22)
参考文献 (23)
附录 (24)
第一章引言
1.1课题背景
1.1.1背景知识
五子棋是起源于中国古代的传统黑白棋种之一。
现代五子棋日文称之为“连珠”,英译为“Renju”,英文称之为“Gobang”或“FIR”(Five in a Row的缩写),亦有“连五子”、“五子连”、“串珠”、“五目”、“五目碰”、“五格”等多种称谓。
五子棋不仅能增强思维能力,提高智力,而且富含哲理,有助于修身养性。
五子棋既有现代休闲的明显特征“短、平、快”,又有古典哲学的高深学问“阴阳易理”;它既有简单易学的特性,为人民群众所喜闻乐见,又有深奥的技巧和高水平的国际性比赛;它的棋文化源渊流长,具有东方的神秘和西方的直观;既有“场”的概念,亦有“点”的连接。
它是中西文化的交流点,是古今哲理的结晶。
五子棋起源于古代中国,发展于日本,风靡于欧洲。
对于它与围棋的关系有两种说法,一说早于围棋,早在“尧造围棋”之前,民间就已有五子棋游戏;一说源于围棋,是围棋发展的一个分支。
在中国的文化里,倍受人们的青睐。
古代的五子棋的棋具与围棋相同,纵横各十七道。
五子棋大约随围棋一起在我国南北朝时先后传入朝鲜、日本等地。
据日本史料文献介绍,中国古代的五子棋是经由高丽(朝鲜),于1688年至1704年的日本元禄时代传到日本的。
到日本明治32年(公元1899年),经过公开征名,“连珠”这一名称才被正式确定下来,取意于“日月如合壁,五星如连珠”。
从此,连珠活动经过了不断的改良,主要是规则的变化(即对执黑棋一方的限制),例如,1899年规定,禁止黑白双方走“双三”;1903年规定,只禁止黑方走“双三”;1912年规定,黑方被迫走“双三”亦算输;1916年规定,黑方不许走“长连”;1918年规定,黑方不许走“四、三、三”;1931年规定,黑方不许走“双四”,并规定将19×19的围棋盘改为15×15的连珠专用棋盘。
本世纪初五子棋传入欧洲并迅速风靡全欧。
通过一系列的变化,使五子棋这一简单的游戏复杂化、规范化,而最终成为今天的职业连珠五子棋,同时也成为一种国际比赛棋。
1.1.2五子棋游戏的规则
(一)棋盘,棋子
1.棋盘为十五路,正中一点为“天元”,周围四点为小星。
2.棋子分黑白两色,黑子113枚,白子112枚,共225枚。
(二)比赛规则
1.黑先白后,从天元开始落子。
然后执白棋的一方在黑棋周围的交叉点上落子,白第二着棋应布在自己河界的一侧。
此后,执黑方在以天元为中心的25个交叉点的范围内布盘面的第三着棋。
2.最先在横向,竖向,斜向形成连续的相同色五个棋子的一方为胜。
3.黑棋禁手判负,白棋无禁手。
黑棋禁手包括“三三”,“四四”,“长连”。
黑方只能“四三”胜。
所谓禁手,是指黑方一子落下同时形成两个或两个以上的活三,冲四及长连禁手。
长连禁手是指黑方形成六个或六个以上的连续棋子。
4.双方均不能形成五连为和棋。
5.对局中拔子,中途退场均判为负。
6.五连与禁手同时形成,先五为胜。
因黑方已形成五连,故禁手失效,黑方胜。
7.黑方禁手形成时,白方应立即指出禁手点,黑方即负。
若白方继续应子,则黑方禁手不成立。
8.高段位职业比赛的特殊规定:“三手可交换”:黑下完第2手,执白者可提出交换。
即执白方变为执黑方。
“五手两打法”:执黑下第五手时,必须下两手棋,执白者从这两手棋中任选一步。
本文所论述的联机五子棋系统就是依照这种方式进行的。
1.1.3开发系统的几点建议
(1)、开发系统不必贪大求全,力争简单实用。
应从大处着眼,小处着手,循序渐进,逐步完善。
(2)、对开发过程中的各种文档应当注意保存。
这是系统开发所要求的必要条件。
(3)、尽可能取得对程序设计重视,使用简化的程序代码保证整个系统开发的清晰。
1.2相关技术介绍
1.2.1结构化生命周期法简介
结构化生命周期法是一种传统的系统开发方法,其基本思想是把整个系统开发过程分成若干个阶段,每个阶段进行若干活动,每项活动应用一系列标准、规范、方法和技术,完成一个或多个任务,形成符合给定规范的产品。
采用结构化生命周期法来开发系统时,应遵循的主要原则:
(1)、用户参与的原则
(2)、“先逻辑后物理”的原则
(3)、“自顶向下”的原则
(4)、工作成果描述(主要指文档)标准化的原则
其具体开发步骤可分为以下四步:
a系统规划
b系统开发
c系统的运行及维护
d系统评价
其中系统开发又分为以下四个步骤:
(a)系统分析
.系统初步调查
.系统可行性研究
.现行系统的详细调查
.新系统逻辑方案的提出
(b)系统设计
.系统总体结构设计
系统总体功能设计
.系统总体物理结构设计
系统详细设计
.代码设计
.输入输出设计
(c)系统实施
.程序设计
系统测试
1.2.2开发技术——快速原型法简介
快速原型法是80年代发展起来的,旨在缩短开发周期,提高开发效率和用户对系统的满意程度。
其基本思想是在系统开发的初期,尽快构造出系统的原型,使用户能及早地运行这个系统原型,通过使用它、熟悉它,受到启发并取得经验,然后对系统的目标和功能提出更精确、具体的要求,研制人员据此逐渐修改和完善原型,使它满足用户的需求,最后完成系统的开发。
该方法大大提高了系统开发效率,弥补了结构化生命周期法来开发的时间长的缺陷。
通常采用原型法需要以下四个阶段:
(1)、明确用户的基本要求
(2)、研制系统的原型
(3)、使用、评价系统原型
(4)、修改和完善原型
1.2.3本系统开发方法的选择
基于以上开发方法的优劣和本系统的实际情况,本系统总体上采用结构化生命周期法进行系统规则、系统分析和系统设计,但在系统实施阶段采用原型法。
在开发程序的方法上,本系统将采用VISUALC++开发工具编制一个五子棋联机游戏的软件,用以实现客户端与服务端管理。
第二章系统目标
五子棋联机游戏系统主要致力于为提供联机双方进行联机游戏联络,以及提供准确可靠用户操作动作的信息。
具体目标如下:
●选择连接到服务器的客户端进行记录。
●记录客户机的键盘动作。
●分析是否已经取得胜利。
第三章系统需求分析
3.1系统需求
(1)满足记录客户机的游戏动作的基本要求。
(2)满足连接数据到客户端的基本要求。
(3)满足服务器实时获得客户端游戏状态的基本要求。
(4)在服务器端分析双方是否胜利。
3.2功能需求
基于系统需求分析,该系统需要实现以下基本功能:
(1)动作记录:当客户端程序启动的时候,程序自动加载键盘钩子,对客户端的网络的连接和操作进行记录,并提示给游戏双方。
(2)对连接到客户端数据的基本要求:能够将要发送的聊天记录发送至对方手上,能够完成数据的连接。
(3)实时显示:当从游戏一方将数据传入另一方系统中,将五子棋的表格进行重新的刷新,和更改。
(4)通过控制鼠标点击五子棋表格:进入控制模式,加载鼠标钩子,截取鼠标的按件动作,并把该动作发送到游戏另一方,并判断是否胜利。
3.3系统运行环境
系统运行环境:Windows 2000及其以上
3.4 MFC简述
MFC(Microsoft Foundation Class)指的是Microsoft基础类,是用来为Windows 开发C++GUI应用程序。
MFC是一种十分优秀的工具,使得面向对象的软件函数包装
技术演变成为一种可以进行代码复用、简化了程序的复杂性并使程序更加有效的软件开发环境..对于使用Windows API 进行应用程序开发的人员来说, MFC使程序员大大提高了程序开发效率.你不必创建GDU对象,不必编写许多代码行对这些对象进行初始化,并且小心地跟踪其生命周期的运行情况,你只需建立一个MFC类的实例,使用其默认值,然后让撤消程序来清除系统资源即可.
3.5 服务器与客户端SOCKET设计
本程序都采用tcpsock的DLL模型,该模型允许应用程序以Windows消息的形式接收网络事件通知。
这个模型是为了适应Windows的消息驱动环境而设置的,用于对性能要求不高的网络应用程序,最大可连接64个客户端。
使用该模型基本满足本程序要求。
协议设计:
0 move 鼠标移动
1 leftdown 鼠标左件按下
2 leftup 鼠标左件弹起
3 rightdown 鼠标右件按下
4 rightup 鼠标右件弹起
5 send 发送数据
6 stop 停止发送
7 quick 实时发送
第四章系统设计
4.1 概要设计
本次毕业设计的内容就是设计出联机五子棋系统,在此基础上实现系统模型各个子系统的基本功能。
此系统用建立一个tcpsock的DLL文件来进行联机的游戏的网络数据。
主要是运用了strListen类进行联机数据的传输
在系统功能需求分析的基础上,结合Visual C++程序编制的特点,得到下图所示
的系统功能模块图。
图4-1五子棋服务端模块
图4-2五子棋客户端主模块
4.2流程图
下面用我们用数据流图(DFD, Data Flow Diagram),也就是从数据传递和加工的角度,以图形的方式刻画数据流从输入到输出的移动变换过程。
如下图所示:
本图只是画出了系统得一部分的功能流程图,因为本程序是一个windows程序,由较多的功能,主要是基于消息驱动的,所以有一些功能不能有流程图表达出来,如,
消息的传递,当系统接到客户端传递来的信息后,就调用一个函数,将随机的产生出一些信息。
提示在提示框内。
让下棋一方了解到,现在该我下子了。
当然传递对方下棋的棋子位置等数据的接受处理也是基于消息的,当有传递数据到达的时候,系统会触发一个消息,程序调用函数读取数据并进行相应的处理。
如果是对方棋子位置的信息,则在屏幕上找到对应期盼坐标画出对方棋子,同时判断对方是否获胜。
4.3详细设计
4.3.1钩子的使用
本程序使用了以个钩子,他们分别是鼠标钩子。
客户段使用的是键盘钩子,拦截WH_KEYBOARD消息,服务器使用的鼠标钩子,当服务器要获得客户端操作的时候,鼠标钩子将用户的鼠标信息以消息的形式发送到服务器端,服务器再通过socket发送到客户端进行控制操作
因此我们必须首先了解钩子的使用函数:
HHOOK SetWindowsHookEx( int idHook, HOOK_PROC lpfn, HINSTANCE hMod,DWORD dwThreadID);
参数说明:
idHook :钩子的类型
lpfn :钩子处理函数地址
hMod :包含钩子函数的模块句柄
dwThreadID :钩子的线程
函数说明:函数将在系统中挂上一个由idHook指定类型的钩子,处理相应的特定消息。
BOOL UnhookWindowsHookEx( HHOOK hhk );
函数说明:函数将撤销由hhk指定的钩子。
LRESULT CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam,LPARAM lParam );
函数说明:函数将消息向下传递,下一个钩子处理将截获这一消息。
HHOOK SetWindowsHookEx( int idHook, HOOK_PROC lpfn, HINSTANCE hMod,DWORD dwThreadID);
参数说明:
idHook :钩子的类型
lpfn :钩子处理函数地址
hMod :包含钩子函数的模块句柄
dwThreadID :钩子的线程
函数说明:函数将在系统中挂上一个由idHook指定类型的钩子,监控并处理相应的特定消息。
BOOL UnhookWindowsHookEx( HHOOK hhk );
函数说明:函数将撤销由hhk指定的钩子。
LRESULT CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam,LPARAM lParam );
函数说明:函数将消息向下传递,下一个钩子处理将截获这一消息。
4.4 程序设计
4.4.1 程序窗口的设计
由于此应用程序采用的是基于对话框的开发,系统应用程序的各个不同功能是通过选择主对话框窗口中的不同按钮来完成的,每个功能模块由一个或多个对话框实现。
该应用程序的主对话框(即运行应用程序后出现的对话框)如图所示:
本文系统得棋盘是由本文设定的画笔进行绘画而成的。
布尔值对数据进行更新和计算,将棋盘和棋子很好的合并在一起。
这样整个五子棋的程序将很轻易的展现在人们的面前
建立好后,就可以输入代码:
void CMyChessDlg1::DrawNowBlack(int x, int y)
{
//画当前的黑子
CClientDC dc(this);
CDC mdc;
mdc.CreateCompatibleDC(&dc);
mdc.SelectObject(m_bblack);
dc.BitBlt(24+x*36-x-18,25+y*36-y-18,33,33,&mdc,0,0,MERGEPAINT);
mdc.SelectObject(m_blastblackchess);
dc.BitBlt(24+x*36-x-18,25+y*36-y-18,33,33,&mdc,0,0,SRCAND);
}
void CMyChessDlg1::DrawNowWhite(int x, int y)
{
//画当前的白子.
CClientDC dc(this);//CClientDC类负责在构造时调用Windows函数GetDC,在析构时调用ReleaseDC CDC mdc;
mdc.CreateCompatibleDC(&dc);//CreateCompatibleDC()函数创建一个与&dc指定的设备兼容的内存设备描述表
mdc.SelectObject(m_bblack);//SelectObject()将一个对象引入设备描述表
dc.BitBlt(24+x*36-x-18,25+y*36-y-18,33,33,&mdc,0,0,MERGEPAINT);//MERGEPAINT 用布尔OR操作符将反相的源位图与目标位图结合起来
mdc.SelectObject(m_blastwhitechess);
dc.BitBlt(24+x*36-x-18,25+y*36-y-18,33,33,&mdc,0,0,SRCAND);//SRCAND用布尔AND操作符将目标位图象素与源位图象素结合起来
}
void CMyChessDlg1::GetBoard(int tempboard[][15], int nowboard[][15])//获取当前棋盘状态
{
int i,j;
for(i=0;i<15;i++)
for(j=0;j<15;j++)
{
if(i==9)
i=9;
tempboard[i][j]=nowboard[i][j];
}
}
void CMyChessDlg1::InitializeBoard()//初始化
{
//初始化函数
int i,j,count=0,k;
m_pclastpos.x=-1;
m_pclastpos.y=-1;
m_pplastpos.x=-1;
m_pplastpos.y=-1;
start=true;
//判断哪方先开始
if(m_bwfirst)//计算机先
{
player=false;
computer=true;
}
else//人先
{
player=true;
computer=false;
}
pwin=cwin=false;//初始化计算机和玩家的获胜组合情况for(i=0;i<15;i++)
for(j=0;j<15;j++)
for(k=0;k<572;k++)
{
ptable[i][j][k]=false;
ctable[i][j][k]=false;
}
for(i=0;i<2;i++)
for(j=0;j<572;j++)
win[i][j]=0;
for(i=0;i<15;i++)
for(j=0;j<15;j++)
board[i][j]=2;
for(i=0;i<15;i++)
for(j=0;j<11;j++)
{
for(k=0;k<5;k++)
{
ptable[j+k][i][count]=true;
ctable[j+k][i][count]=true;
}
count++;
}
for(i=0;i<15;i++)
for(j=0;j<11;j++)
{
for(k=0;k<5;k++)
{
ptable[i][j+k][count]=true;
ctable[i][j+k][count]=true;
}
count++;
}
for(i=0;i<11;i++)
for(j=0;j<11;j++)
{
for(k=0;k<5;k++)
{
ptable[j+k][i+k][count]=true;
ctable[j+k][i+k][count]=true;
}
count++;
}
for(i=0;i<11;i++)
for(j=14;j>=4;j--)
{
for(k=0;k<5;k++)
{
ptable[j-k][i+k][count]=true;
ctable[j-k][i+k][count]=true;
}
count++;
}
}
void CMyChessDlg1::OnLButtonDown(UINT nFlags, CPoint point)
{
int x,y,tx,ty;
// TODO: Add your message handler code here and/or call default if(player&&point.x<=535&&point.y<=535)//判断是否在有效区域
{
tx=x=point.x-24;
ty=y=point.y-25;
while(tx>=36)
tx-=36;
while(ty>=36)
ty-=36;
tx+=x/36;
ty+=y/36;
if(tx>18)
x=x/36+1;
else
x=x/36;
if(ty>18)
y=y/36+1;
else
y=y/36;//将坐标换算成棋盘上的格子。
if(board[x][y]==2)
{
board[x][y]=0;//设为玩家的棋子
if(m_pplastpos.x!=-1&&m_pplastpos.y!=-1)
{
if(!m_bwfirst)
DrawWhiteChess(m_pplastpos.x,m_pplastpos.y);
else
DrawBlackChess(m_pplastpos.x,m_pplastpos.y);
}
if(!m_bwfirst)
DrawNowWhite(x,y);
else
DrawNowBlack(x,y);
m_pplastpos.x=x;//将当前棋子的信息装入,记录移动棋子的结构中
m_pplastpos.y=y;
for(int i=0;i<572;i++)
{//修改玩家下子后棋盘状态的变化
if(ptable[x][y][i]&&win[0][i]!=7)
win[0][i]++;
if(ctable[x][y][i])
{
ctable[x][y][i]=false;
win[1][i]=7;
}
}
player=false;
computer=true;
}
}
CDialog::OnLButtonDown(nFlags, point);
}
void CMyChessDlg1::OnPaint()
{
if (IsIconic())//IsIconic()函数指出此CWnd是否最小化
{
CPaintDC dc(this); // CPaintDC 为设备描述表类
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);//SendMessage()函数向此窗口发送指定的消息
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);//GetClientRect(&rect)函数把此CWnd客户区的客户坐标拷贝到rect所指向的结构中
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();//当Windows或应用程序申请绘制应用程序窗口的某一部分时此函数被调用}
CClientDC dc(this);//CClientDC类负责在构造时调用Windows函数GetDC,在析构时调用ReleaseDC.
CDC mdc;
mdc.CreateCompatibleDC(&dc);//CreateCompatibleDC()函数创建一个与pDC指定的设备兼容的内存设备描述表
mdc.SelectObject(m_bboard);//SelectObject()函数将一对象选入设备描述表
dc.BitBlt(0,0,600,537,&mdc,0,0,SRCCOPY);//BitBlt()函数将一个位图从源设备描述表拷贝到此当前设备描述表中
//SRCCOPY将源位图拷贝到目标位图上for(int i=0;i<15;i++)
for(int j=0;j<15;j++)
{
//玩家的棋子
if(board[i][j]==0)
{
if(m_pplastpos.x==i&&m_pplastpos.y==j)
{
if(!m_bwfirst)
DrawNowWhite(m_pplastpos.x,m_pplastpos.y);
else
DrawNowBlack(m_pplastpos.x,m_pplastpos.y);
continue;
}
if(!m_bwfirst)
DrawWhiteChess(i,j);
else
DrawBlackChess(i,j);
}
//计算机的棋子
if(board[i][j]==1)
{
if(m_pclastpos.x==i&&m_pclastpos.y==j)
{
if(!m_bwfirst)
DrawNowBlack(m_pclastpos.x,m_pclastpos.y);
else
DrawNowWhite(m_pclastpos.x,m_pclastpos.y);
continue;
}
if(!m_bwfirst)
DrawBlackChess(i,j);
else
DrawWhiteChess(i,j);
}
}
dc.Draw3dRect(0,0,537,537,RGB(255,255,255),RGB(0,0,0));//画15*15的棋盘
}
先查看客户端的状态,然后依照客户端的变化在更新五子棋的程序
第五章结论
5.1 关键技术
本系统开发过程中用到的关键技术主要有:
●钩子程序的使用
●对网络联机的知识
5.2总结
在设计过程中,出现过不同的问题,开始的时候解决起来有一些困难,经过两个月的不断学习和实践,基本上都已经解决,而且通过解决问题的过程,总结出一些需要注意的事项:
1、网络知识相对来说,并不是很容易理解,在网络的开发中,我们必须要
注意到消息的获得和判断,例如winsock的开发机制和传输数据的内容,
我们必须要注意。
2、在系统开发的时候,我们使用的是MFC进行数据的封装,其代码量使用
比Winsock要小,而编写windows应用程序,大多基于事件机制,对
windows系统的事件机制需要能够透彻的理解,我们才能进行完善的系
统设计和开发
第六章设计总结
由于以前对Visual C++ 6.0的接触并不是很多,对它的开发环境不是非常了解,所以在程序的开发过程中遇到了很多的困难,但经过同学和指导老师的帮助,一一化解了困难,并从中学到了很多编程方面的知识。
但是由于经验方面的原因,以及对库存方面的操作流程了解不足,该系统还有许多不尽如人意的地方和功能上的缺陷,这些都有待于进一步改善。
第七章谢辞
此毕业设计为时两个月,由于时间和能力的限制,难免出现许多不足之处,敬请各位老师批评指正。
但是这一段的实践和学习,大大提高了我解决实际问题的能力,确实使我收获很多,提高很大,想信对我以后的学习生活都会大有裨益。
在此,首先要感谢我的指导老师***老师不辞劳苦的知道,使我们得以顺利完成毕业设计;其次,系里的其他的一些老师和机房的老师在毕业设计的过程中给予我们的大力支持,我从这些老师那里获益很多,在此一并表示感谢。
最后,要感谢和我同组做毕业设计的同学,这份毕业设计的成果是大家共同努力的结果。
谢谢大家。
参考文献
[1] 伍俊良.《Visual C++ 课程设计与系统开发案例》.清华大学出版社
[2] 杨小平.《Visual C++ 项目案例导航》.科学出版社
[3] 邓宗明,张晓竞.《Visual C++ 编程实用技术与案例》.清华大学出版社
[4] 郑阿奇.《Visual C++ 实用教程》.电子工业出版社
[5] 王艳平,张越《WINDOWS网络与通信程序设计》。
人民邮电出版社
[6] 郑人杰,殷人昆,陶永雷.实用软件工程.清华大学出版社.1997.4 .
附录
1、棋盘程序
MyChessDlg.h
#if !defined(AFX_MYCHESSDLG_H__327DACFE_0A82_4A9B_A675_C9F2568F5C13__INCLUDED_) #define AFX_MYCHESSDLG_H__327DACFE_0A82_4A9B_A675_C9F2568F5C13__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif// _MSC_VER > 1000
// MyChessDlg.h : header file
//
///////////////////////////////////////////////////////////////////////////// // CMyChessDlg dialog
class CMyChessDlg1 : public CDialog
{
// Construction
public:
bool SearchBlank(int &i, int &j, int nowboard[][15]);
void IsWin();
void InitializeBoard();
int GiveScore(int type, int x, int y);
void GetBoard(int tempboard[][15], int nowboard[][15]);
void DrawWhiteChess(int x, int y);
void DrawNowWhite(int x,int y);
void DrawNowBlack(int x,int y);
void DrawBlackChess(int x, int y);
void ComTurn();
int board[15][15];
bool computer;
bool ctable[15][15][572];
bool cwin;
CBitmap m_bblack;
CBitmap m_bwhitechess;
CBitmap m_bblackchess;
CBitmap m_bboard;
CBitmap m_blastwhitechess;
CBitmap m_blastblackchess;
bool m_binit;//判断游戏是否是处于刚开始阶段
bool m_bwfirst;//谁先走,1为电脑先走,0为玩家先走
CPoint m_pplastpos;//玩家走的前一步棋
CPoint m_pclastpos;//计算机走的前一步棋
bool player;
bool ptable[15][15][572];
bool pwin;
bool start;
int win[2][572];
CMyChessDlg1(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CMyChessDlg)
enum { IDD = IDD_ESTDLG };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMyChessDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
void OnUpdateSetPerson(CCmdUI* pCmdUI);
void OnTimer(UINT nIDEvent);
void OnSysCommand(UINT nID, LPARAM lParam);
void OnSetPerson();
HCURSOR OnQueryDragIcon();
void OnPaint();
void OnLButtonDown(UINT nFlags, CPoint point);
// Generated message map functions
//{{AFX_MSG(CMyChessDlg)
afx_msg void OnGameStart();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
public:
afx_msg void OnBnClickedEffect();
afx_msg void OnBnClickedListen();
};
// App command to run the dialog
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_MYCHESSDLG_H__327DACFE_0A82_4A9B_A675_C9F2568F5C13__INCLUDED_)
MyChessDlg.cpp
// MyChessDlg.cpp : implementation file
//
#include "stdafx.h"
#include "fchess.h"
#include "MyChessDlg.h"
#include ".\mychessdlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CMyChessDlg dialog
CMyChessDlg1::CMyChessDlg1(CWnd* pParent /*=NULL*/)//gjl
: CDialog(CMyChessDlg1::IDD, pParent)
{
//{{AFX_DATA_INIT(CMyChessDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);//AfxGetApp获取一个指向CWinApp对象指针
}
//CMyChessDlg::CMyChessDlg(CWnd* pParent /*=NULL*/)/
// : CDialog(CMyChessDlg::IDD, pParent)
//{
//{{AFX_DATA_INIT(CMyChessDlg)
// // NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
// m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);//AfxGetApp获取一个指向CWinApp对象指针
//}
void CMyChessDlg1::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);//DoDataExchange()框架调用此函数以交换和有效化对话数据,pDX是指向一个CDataExchange对象的指针
//{{AFX_DATA_MAP(CMyChessDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CMyChessDlg1, CDialog)
//{{AFX_MSG_MAP(CMyChessDlg)
ON_COMMAND(ID_GAME_START, OnGameStart)
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_EFFECT, OnBnClickedEffect)
ON_BN_CLICKED(IDC_LISTEN, OnBnClickedListen)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMyChessDlg message handlers
void CMyChessDlg1::OnGameStart()
{
InitializeBoard();
Invalidate();//此函数使CWnd的整个客户区无效
SetTimer(0,200,NULL);//0:为一个非0的定时器标识符。
200:为以毫秒数指出限时值;NULL:为WM_TIMER 消息将被放到应用程序的队列中并由此CWnd对象来处理
}
void CMyChessDlg1::ComTurn()//寻找下棋的空白位置,并下棋子
{
//bestx,besty为当前最佳位置,i,j是人能下的各种位置;ci,cj是计算机能下的各种位置
int
bestx,besty,i,j,ci,cj,ptemp,ctemp,pscore=10,cscore=-10000,ctempboard[15][15],ptempboard[15][15];
int m,n,temp1[20],temp2[20];//暂存第一步搜索的信息
if(start)
{
if(board[7][7]==2)//如果棋盘为空
{
bestx=7;
besty=7;
}
else
{
bestx=8;
}
start=false;
}
else
{//寻找最佳位置
GetBoard(ctempboard,board);
while(SearchBlank(i,j,ctempboard))
{
n=0;
pscore=10;
GetBoard(ptempboard,board);
ctempboard[i][j]=3;//标记已被查找
ctemp=GiveScore(1,i,j);
for(m=0;m<572;m++)
{//暂时更改玩家信息
if(ptable[i][j][m])
{
temp1[n]=m;
ptable[i][j][m]=false;
temp2[n]=win[0][m];
win[0][m]=7;
n++;
}
}
ptempboard[i][j]=1;
ci=i;
cj=j;
while(SearchBlank(i,j,ptempboard))
{
ptempboard[i][j]=3;//标记已被查找
ptemp=GiveScore(0,i,j);
if(pscore>ptemp)//此时为玩家下子,运用极小极大法时应选取最小值
pscore=ptemp;
}
for(m=0;m<n;m++)
{//恢复玩家信息
ptable[ci][cj][temp1[m]]=true;
win[0][temp1[m]]=temp2[m];
}
if(ctemp+pscore>cscore)//此时为计算机下子,运用极小极大法时应选取最最大值
{
cscore=ctemp+pscore;
besty=cj;
}
}
}
board[bestx][besty]=1;
if(m_pclastpos.x!=-1&&m_pclastpos.y!=-1)
{//画前一棋子
if(!m_bwfirst)
DrawBlackChess(m_pclastpos.x,m_pclastpos.y);
else
DrawWhiteChess(m_pclastpos.x,m_pclastpos.y);
}
if(!m_bwfirst)
DrawNowBlack(bestx,besty);
else
DrawNowWhite(bestx,besty);
m_pclastpos.x=bestx;
m_pclastpos.y=besty;
for(i=0;i<572;i++)
{//修改计算机下子后,棋盘的变化状况
if(ctable[bestx][besty][i]&&win[1][i]!=7)
win[1][i]++;
if(ptable[bestx][besty][i])
{
ptable[bestx][besty][i]=false;
win[0][i]=7;
}
}
computer=false;
player=true;
}
void CMyChessDlg1::DrawBlackChess(int x, int y)
{
CClientDC dc(this);//CClientDC类负责在构造时调用Windows函数GetDC,在析构时调用ReleaseDC.
CDC mdc;//定义设备描述表对象
mdc.CreateCompatibleDC(&dc);
mdc.SelectObject(m_bblack);//SelectObject()将一个对象引入设备描述表
dc.BitBlt(24+x*36-x-18,25+y*36-y-18,33,33,&mdc,0,0,MERGEPAINT);//MERGEPAINT用布尔OR操作将反相的源位图和和目标位图结合起来
mdc.SelectObject(m_bblackchess);
dc.BitBlt(24+x*36-x-18,25+y*36-y-18,33,33,&mdc,0,0,SRCAND);//SRCAND用布尔AND操作将目标位图象
素和源位图象素结合起来
}
void CMyChessDlg1::DrawNowBlack(int x, int y)
{
//画当前的黑子
CClientDC dc(this);
CDC mdc;
mdc.CreateCompatibleDC(&dc);
mdc.SelectObject(m_bblack);
dc.BitBlt(24+x*36-x-18,25+y*36-y-18,33,33,&mdc,0,0,MERGEPAINT);
mdc.SelectObject(m_blastblackchess);
dc.BitBlt(24+x*36-x-18,25+y*36-y-18,33,33,&mdc,0,0,SRCAND);
}
void CMyChessDlg1::DrawNowWhite(int x, int y)
{
//画当前的白子.
CClientDC dc(this);//CClientDC类负责在构造时调用Windows函数GetDC,在析构时调用ReleaseDC CDC mdc;
mdc.CreateCompatibleDC(&dc);//CreateCompatibleDC()函数创建一个与&dc指定的设备兼容的内存设备描述表
mdc.SelectObject(m_bblack);//SelectObject()将一个对象引入设备描述表
dc.BitBlt(24+x*36-x-18,25+y*36-y-18,33,33,&mdc,0,0,MERGEPAINT);//MERGEPAINT 用布尔OR操作符将反相的源位图与目标位图结合起来
mdc.SelectObject(m_blastwhitechess);
dc.BitBlt(24+x*36-x-18,25+y*36-y-18,33,33,&mdc,0,0,SRCAND);//SRCAND用布尔AND操作符将目标位图象素与源位图象素结合起来
}
void CMyChessDlg1::DrawWhiteChess(int x, int y)
{
CClientDC dc(this);
CDC mdc;
mdc.CreateCompatibleDC(&dc);
mdc.SelectObject(m_bblack);
dc.BitBlt(24+x*36-x-18,25+y*36-y-18,33,33,&mdc,0,0,MERGEPAINT);
mdc.SelectObject(m_bwhitechess);
dc.BitBlt(24+x*36-x-18,25+y*36-y-18,33,33,&mdc,0,0,SRCAND);
}
void CMyChessDlg1::GetBoard(int tempboard[][15], int nowboard[][15])//获取当前棋盘状态
{
int i,j;
for(i=0;i<15;i++)
for(j=0;j<15;j++)
{
if(i==9)
i=9;
tempboard[i][j]=nowboard[i][j];
}
}
int CMyChessDlg1::GiveScore(int type, int x, int y) {
int i,score=0;
for(i=0;i<572;i++)
{
//计算机下
if(type==1)
{
if(ctable[x][y][i])
{
switch(win[1][i])
{
case 1:
score+=5;
break;
case 2:
score+=50;
break;
case 3:
score+=100;
break;
case 4:
score+=10000;
break;
default:
break;
}
}
}
//人下
else
{
if(ptable[x][y][i])
{
switch(win[0][i])
{
score-=5;
break;
case 2:
score-=50;
break;
case 3:
score-=500;
break;
case 4:
score-=5000;
break;
default:
break;
}
}
}
}
return score;
}
void CMyChessDlg1::InitializeBoard()//初始化
{
//初始化函数
int i,j,count=0,k;
m_pclastpos.x=-1;
m_pclastpos.y=-1;
m_pplastpos.x=-1;
m_pplastpos.y=-1;
start=true;
//判断哪方先开始
if(m_bwfirst)//计算机先
{
player=false;
computer=true;
}
else//人先
{
player=true;
computer=false;
}
pwin=cwin=false;//初始化计算机和玩家的获胜组合情况for(i=0;i<15;i++)
for(j=0;j<15;j++)
for(k=0;k<572;k++)
ptable[i][j][k]=false;
ctable[i][j][k]=false;
}
for(i=0;i<2;i++)
for(j=0;j<572;j++)
win[i][j]=0;
for(i=0;i<15;i++)
for(j=0;j<15;j++)
board[i][j]=2;
for(i=0;i<15;i++)
for(j=0;j<11;j++)
{
for(k=0;k<5;k++)
{
ptable[j+k][i][count]=true;
ctable[j+k][i][count]=true;
}
count++;
}
for(i=0;i<15;i++)
for(j=0;j<11;j++)
{
for(k=0;k<5;k++)
{
ptable[i][j+k][count]=true;
ctable[i][j+k][count]=true;
}
count++;
}
for(i=0;i<11;i++)
for(j=0;j<11;j++)
{
for(k=0;k<5;k++)
{
ptable[j+k][i+k][count]=true;
ctable[j+k][i+k][count]=true;
}
count++;
}
for(i=0;i<11;i++)
for(j=14;j>=4;j--)
{
for(k=0;k<5;k++)
{
ctable[j-k][i+k][count]=true;
}
count++;
}
}
void CMyChessDlg1::IsWin()
{
int i;
for(i=0;i<572;i++)
{
if(win[0][i]==5)//玩家赢
{
pwin=true;
break;
}
if(win[1][i]==5)
{
cwin=true;//电脑赢
break;
}
}
}
void CMyChessDlg1::OnLButtonDown(UINT nFlags, CPoint point)
{
int x,y,tx,ty;
// TODO: Add your message handler code here and/or call default if(player&&point.x<=535&&point.y<=535)//判断是否在有效区域
{
tx=x=point.x-24;
ty=y=point.y-25;
while(tx>=36)
tx-=36;
while(ty>=36)
ty-=36;
tx+=x/36;
ty+=y/36;
if(tx>18)
x=x/36+1;
else
x=x/36;
if(ty>18)
y=y/36+1;。