




已阅读5页,还剩12页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
五子棋人机对战游戏摘要:本文用visual c+来设计与实现简单的五子棋人机对战游戏的基本功能,玩家可以在游戏区域中适当的位置来放棋子,通过程序设计让电脑选择最佳的落棋点,来实现人机对战。文中对该游戏的算法进行了详细的介绍,其中核心内容包括界面的设计、最佳落棋位置的判断以及游戏胜利判断功能的实现。程序实现起来较简单,同时也比较实用。关键词: 五子棋 ,vc,人机对战游戏 1.引言1.1 游戏介绍五子棋是一种很受人们喜爱的智力游戏,它的规则简单,但玩法变化多端,富有趣味性,特别锻炼人的智力,适合人们消遣。1.2 目的网络小游戏制作的目的是满足了人们休闲的需要,在紧张工作之余休闲类的小游戏能够给人带来最大程度的放松,也可以增进人们之间的交流,沟通,通过游戏还可以认识更多的朋友,也可以到达跨省、跨市,甚至跨国间人们互相娱乐的目的。 1.3 主要问题 开始制作游戏时,主要要解决的问题有以下几个方面:1. 如何设置整个游戏的界面;2 判断是否可以放下棋子;3. 如何让电脑选择最佳位置;4. 判断是黑棋胜还是白棋胜。2 需求分析关于五子棋游戏的功能描述如下:运行游戏并进行初始化工作,将整个游戏区域中纵线和横线相交的点坐标化,并且这些点是将来下棋的位置。玩家可以在任意没有放棋子的点放下棋子,直到一方有五个棋子连成一条线为胜方。 游戏的整体运行效果如图1.1。图1.13. 功能模块的设计3.1 变量和函数 在view类中添加变量函数如下:保存vscomputer时白棋位置 CPoint vspoint;CPoint bpointcan4, /这个位置空,它旁边有四个黑棋wpointcan4, /这个位置空,它旁边有四个白棋bpointcan3, /这个位置空,它的旁边有三个黑棋wpointcan3, /这个位置空,它的旁边有三个白棋bpointcan2, /这个位置空,它的旁边有两个黑棋wpointcan2, /这个位置空,它的旁边有两个白棋bpointcan1; /不是以上情况,这个位置空 在得到最大值和方向上寻找落棋点,其中i、j表示搜索起点,n表示方向void searchcandown1(int i,int j,int n);void searchcandown2(int i,int j,int n);void searchcandown3(int i,int j,int n);void searchcandown4(int i,int j,int n);计算最大值及方向CPoint maxnum(int a,int b,int c,int d);最好落棋点void bestputdown(int i,int j);计算机下棋void computerdown();在位置point放下棋子void putdown(CPoint point);人对机菜单afx_msg void OnCpmputer();3.2.框架的搭建 新建工程,选择单文档,在Step 4 of 6中先中Windows Sockets复选框4 算法分析与设计4.1游戏界面的设计由于游戏的棋盘大小是一定的,不能改变大小的,是应该符合要求的。用如下函数设置窗口大小:BOOL CMainFrame:PreCreateWindow(CREATESTRUCT& cs) if( !CFrameWnd:PreCreateWindow(cs) ) return FALSE; / TODO: Modify the Window class or styles here by modifying / the CREATESTRUCT cs cs.dwExStyle=cs.dwExStyle|WS_EX_TOPMOST; / cs.style=WS_SYSMENU|WS_OVERLAPPED|WS_MINIMIZEBOX;/; /设置窗口大小:400*340 cs.cx=450; cs.cy=500; return TRUE;画棋盘: 在OnDraw(CDC* pDC)函数中画棋盘,由于在游戏过程中有可能重画棋盘,而那时棋盘上面有棋子,所以,我们在这个函数里面必须有画棋子的语句。在此用数组的做为1表示白棋,-1表示黑棋。 void CMy3_1View:OnDraw(CDC* pDC) CMy3_1Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); /画背景 CBrush mybrush1; mybrush1.CreateSolidBrush(RGB(192,192,192); CRect myrect1(0,0,1200,800); pDC-FillRect(myrect1,&mybrush1); /画棋盘框线 CPen mypen; CPen*myoldPen; mypen.CreatePen(PS_SOLID,1,RGB(0,0,0); myoldPen=pDC-SelectObject(&mypen); for(int i=0;iMoveTo(40,40+i*20); pDC-LineTo(400,40+i*20); pDC-MoveTo(40+i*20,40); pDC-LineTo(40+i*20,400); /重画时显示存在的棋子 CDC Dc; if(Dc.CreateCompatibleDC(pDC)=FALSE) AfxMessageBox(Cant create DC); for(int n=0;n19;n+) for(int m=0;mBitBlt(n*20+32,m*20+32,160,160,&Dc,0,0,SRCCOPY); else if(wzqnm=-1) /显示黑棋 Dc.SelectObject(m_bmblack); pDC-BitBlt(n*20+32,m*20+32,160,160,&Dc,0,0,SRCCOPY); 棋盘的效果如图5. 核心算法 在完成界面设计后,就开始展开游戏核心的设计,该部分主要包括计算机搜索最佳落棋位置,游戏胜利判断的实现。5.1 搜索最佳落棋位置 计算机是怎样下棋?这就是定位的问题了。即搜索棋盘,找出一个最佳点,放下黑棋。我们实现的方法是:全盘搜索,并把搜索到的位置,保存在变量。由于有多种情况,我们定义变量如下:CPoint bpointcan4, /这个位置空,它旁边有四个黑棋 wpointcan4, /这个位置空,它旁边有四个白棋 bpointcan3, /这个位置空,它的旁边有三个黑棋 wpointcan3, /这个位置空,它的旁边有三个白棋 bpointcan2, /这个位置空,它的旁边有两个黑棋 wpointcan2, /这个位置空,它的旁边有两个白棋 bpointcan1; /不是以上情况,这个位置空 并在搜索之前都赋值为(-1,-1),然后,进行搜索,并把相应的值保存在相应变量里面,而如果前面已经对变量赋值,我们依然赋值,用新值代替旧值。注意:只保存最后一个值,这样的一个好处是,避免了每次都从左上角开始,并且它的随机性比随机函数还随机。全盘搜索完之后,由于上面的变量中至少有一个已经被赋值,即不是(-1,-1),可以采用多数优先的方法,让已经有多个同色棋子的位置先下棋。其原理是,如果已经有四个黑棋,计算机再下一个黑棋就赢了;否则,如果人已经有四个白棋,那么计算机就必须放下一个黑棋,阻止白棋下一步赢;如果已经有三个黑棋,再下一个黑棋,变成四个;否则,如果已经有三个白棋,下一个黑棋,破坏它;两个棋子的同理;否则,在刚才白棋下的地方,顺便找一个位置,下棋。computerdown()函数如下:/轮到计算机下棋void CMy3_1View:computerdown() /把各种情形赋值为如下 bpointcan4=(-1,-1); wpointcan4=(-1,-1); bpointcan3=(-1,-1); wpointcan3=(-1,-1); bpointcan2=(-1,-1); wpointcan2=(-1,-1); bpointcan1=(-1,-1); /搜索最好的落棋点 for(int i=0;i19;i+) for(int j=0;jBitBlt(point.x*20+32,point.y*20+32,160,160,&Dc,0,0,SRCCOPY); wzqpoint.xpoint.y=-1;/由于原来我们检查是否结束时用的是鼠标点下的坐标,而现在/putdown(CPoint point)函数用的是数组棋盘的坐标,所以必须转换 CPoint overpoint; overpoint.x=point.x*20+30; overpoint.y=point.y*20+30; over(overpoint); colorwhite=true; 搜索最佳落棋点: 现在还有void bestputdown(int i,int j)函数没有定义。它的实现原理是:在四个方向上,各自计算那个方向上棋子的状态,利用原来定义的白棋为1,黑棋为-1的思想,让同个方向上的五个棋子的值相加,取绝对值并赋值给为这个方向定义的局部变量numi。 如果几个棋子是同色的,无论黑白,它的绝对值必然大,而对于几个棋子中有黑棋和白棋的,其值必然相加而抵消变小。所以我们可以利用这种方法来寻找旁边有多个同色棋子的空位置(前面已经具体说明)。在每一个棋盘位置,计算以它为起点的四个方向(横、竖、撇、捺),再比较这四个方向中哪个值最大,然后在这个方向上寻找落棋点。/检查四个方向,各算出五个棋子的和并赋值void CMy3_1View:bestputdown(int i,int j) /四个方向的值 int num4; int a,k; / num0 - a=0; if(i15) for(k=0;k5;k+) a=a+wzqi+kj; num0=abs(a); / num1 | a=0; if(j15) for(k=0;k5;k+) a=a+wzqij+k; num1=abs(a); / num2 a=0; if(i15&j15) for(k=0;k4)&(j15) for(k=0;k=b) point.x=0; point.y=a; else point.x=1; point.y=b; if(cpoint.y) point.x=2; point.y=c; if(dpoint.y) point.x=3; point.y=d; return point; 而另外的四个函数,有其相似性,分别介绍如下: void searchcandown4(int i,int j,int n)函数: 如果最大值是四,它必然有一个空位置;可以这样计算,如果第一个是空,那我们把它赋值给相应变量;否则,先找那个空位置,然后判断第一个棋子的颜色,并赋相应的值。 /由于相似,下面代码只解释第一个方向 /有四个同色棋void CMy3_1View:searchcandown4(int i, int j, int n) int k; / num0 - if(n=0) for(k=0;k5;k+) /如果第一个是空 if(wzqij=0) /如果下面有白棋 if(wzqi+1j=1) /下面位置可以下棋,已经有四个白棋 wpointcan4.x=i; wpointcan4.y=j; break; else /下面位置可以下棋,已经有四个黑棋 bpointcan4.x=i; bpointcan4.y=j; break; /如果找到下棋位置,一定能找到! else if(wzqi+kj=0) /如果第一个是白棋 if(wzqjj=1) wpointcan4.x=i+k; wpointcan4.y=j; break; /否则第一个是黑棋 else bpointcan4.x=i+k; bpointcan4.y=j; break; / num1 | if(n=1) for(k=0;k5;k+) if(wzqij=0) if(wzqij+1=1) wpointcan4.x=i; wpointcan4.y=j; break; else bpointcan4.x=i; bpointcan4.y=j; break; else if(wzqij+k=0) if(wzqij=1) wpointcan4.x=i; wpointcan4.y=j+k; break; else bpointcan4.x=i; bpointcan4.y=j+k; break; / num2 if(n=2) for(k=0;k5;k+) if(wzqij=0) if(wzqi+1j+1=1) wpointcan4.x=i; wpointcan4.y=j; break; else bpointcan4.x=i; bpointcan4.y=j; break; else if(wzqi+kj+k=0) if(wzqij=1) wpointcan4.x=i+k; wpointcan4.y=j+k; break; else bpointcan4.x=i+k; bpointcan4.y=j+k; break; / num3 / if(n=3) for(k=0;k5;k+) if(wzqij=0) if(wzqi-1j+1=1) wpointcan4.x=i; wpointcan4.y=j; break; else bpointcan4.x=i; bpointcan4.y=j; break; else if(wzqi-kj+k=0) if(wzqij=1) wpointcan4.x=i-k; wpointcan4.y=j+k; break; else bpointcan4.x=i-k; bpointcan4.y=j+k; break; void searchcandown3(int i,int j,int n)函数: 如果最大值是三,它有两种情况,一种是三个同色和两个空;一种是四个同色和一个异色。前一种必定能找到一个空位置,赋值;后一种必定找不到空位置,不赋值。所以我们的想法很简单,先找到空位置,证明有三个同色,这对于玩五子棋来说三个同色是很重要的,再判断是哪种颜色,赋相应的值。void searchcandown2(int i,int j,int n)函数: 如果最大值是二,也有两种情况:一种是有两个同色和三个空位置;一种是有三个同色和一个异色和一个空位置,并且只算三个同色不连在一起的情况(因为如果有三个连续的情况,重全盘搜索的角度看,必然会被另外的情况所代替)。分两种算法:一种是有一个空位置,一种是有三个空位置。前者先找到空位置,再判断它下面两个是否同色,同色则赋值给相应变量,异色则不赋值,因为意义不大;后者只要找到一个空位置就行了。void searchcandown1(int i,int j,int n)函数: 最后的一个函数是searchcandown1(int i, int j, int n),这是为了预防用的,如果以上情况不发生,这个函数就是为了处理这种情况。这里就说明了为什么我们要添加vspoint的原因了,它保存了上次白棋下棋的位置,而我们在没有办法的情况下,在白棋旁边随便找个位置就可以了。 /如果五个位置的和是一void CMy3_1View:searchcandown1(int i, int j, int n) /计算刚才白棋落棋点 int ii=(vspoint.x-30)/20; int jj=(vspoint.y-30)/20; int a; for(a=0;a5;a+) /如果不到边界 if(ii+a19) /向右,如果有空位置 if(wzqii+ajj=0) /在这个位置下黑棋 bpointcan1.x=ii+a; bpointcan1.y=jj; return; /到了边界 else /向左,如果有空位置 if(wzqii-1jj=0) bpointcan1.x=ii-a; bpointcan1.y=jj; return; 5.2 判断游戏是否结束 用一个over()函数判断是否结束,是则结束并重新开始;否则,接着把鼠标变成棋子,表示继续下棋。此函数是利用刚下棋的位置为中心,检查它各个方向上的连续五个棋子是否同色,是则结束并重新开始。利用连续五个棋子的值相加,如果它们的值的绝对值等于5,则说明是同色。void CMy3_1View:over(CPoint point) /获取鼠标指向数组位置,即中心位置 int x=(point.x-30)/20; int y=(point.y-30)/20; /计算开始判断的坐标 xx,yy int xx,yy; if(x4) xx=0; else xx=x-4;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 智能开关什么协议书好
- 金属网制作工多工种协调能力考核试卷及答案
- 机械产品检验员岗位安全技术规程
- 公司精细木工现场作业技术规程
- 公司油母页岩供料工岗位职业健康、安全、环保技术规程
- 2026届太原市数学九上期末质量检测试题含解析
- 管理心理学精要
- 2026届四川省成都东辰国际学校九年级数学第一学期期末综合测试模拟试题含解析
- 山西省吕梁市名校2026届数学八上期末预测试题含解析
- 代谢综合征的中医治疗
- 三年级数学计算题专项练习及答案集锦
- 2025邮政储蓄银行四川省分行社会招聘考试参考试题及答案解析
- 【100题】2025年时政试题及答案
- 2024年南京大学公开招聘辅导员笔试题含答案
- 2025年高考全国二卷数学真题(解析版)
- DB11T 2441-2025 学校食堂清洁和消毒规范
- 现代化农业与农业机械化新技术
- DB37∕T 5263-2023 《民用建筑氡检测与防治技术标准》
- 羽毛球技术分析与训练课件
- 德胜洋楼的员工手册
- 人教部编版七年级上册第三单元名著导读《朝花夕拾》复习考点
评论
0/150
提交评论