基于c#的五子棋游戏的设计与实现.doc
《基于c#的五子棋游戏的设计与实现.doc》由会员分享,可在线阅读,更多相关《基于c#的五子棋游戏的设计与实现.doc(36页珍藏版)》请在咨信网上搜索。
郑 州 科 技 学 院 课 程 设 计 论 文 基于C#的五子棋游戏的设计与实现 1 引言 1 1.1 五子棋介绍 1 2 软件架构 2 3 五子棋设计说明 2 3.1 主要成员变量说明 2 3.2 回溯栈元素类——StackElement 3 3.3 棋子点属性类——qzdianshuxing 3 3.4 主要成员函数说明 4 3.5 实现人机对弈的主要函数 7 3.6 实现菜单功能的函数 27 3.6 程序运行界面 30 4 心得体会 31 1 引言 1.1 五子棋介绍 五子棋是起源于中国古代的传统黑白棋种之一。现代五子棋日文称之为“連珠”,英译为“Renju”,英文称之为“Gobang”或“FIR”(Five in a Row的缩写),亦有“连五子”、“五子连”、“串珠”、“五目”、“五目碰”、“五格”等多种称谓。 五子棋不仅能增强思维能力,提高智力,而且富含哲理,有助于修身养性。五子棋既有现代休闲的明显特征“短、平、快”,又有古典哲学的高深学问“阴阳易理”;它既有简单易学的特性,为人民群众所喜闻乐见,又有深奥的技巧和高水平的国际性比赛;它的棋文化源渊流长,具有东方的神秘和西方的直观;既有“场”的概念,亦有“点”的连接。它是中西文化的交流点,是古今哲理的结晶。 人机对战 人人对战 主界面 游戏控制 游戏模式 重新开始 退出 声音控制 悔棋 开始 2 软件架构 软件的总体架构如图2.1: 图2.1 软件架构 3 五子棋设计说明 3.1 主要成员变量说明 1) 选择游戏模式标志——m_renren 用来表示当前玩家选择游戏的情况,当m_renren为false时,表示人机对战;为true时,表示人人对弈。 2) 游戏开始标志——begin 用来判断当前游戏是否开始 3) 音效标志——sound 在下棋过程中,判断是否需要声音,当sound为true时,表示玩家需要声音,否则的话,玩家不需要声音。 4) 谁先下的标志——first 这个标志只对人机对弈时有效。当first为true时,表示人先下,否则,电脑先下。 5) 棋盘数据——points points为棋盘情况数组,是用一个15*15的二维数组来表示的。points[i,j]=2表示此处无子,points[i,j]=1表示此处为黑子 points[i,j]=0表示此处为白子。 6) 棋子颜色标志——qzcolor 用来表示当前棋子的颜色,qzcolor=1时表示黑棋,qzcolor=0时表示百棋。 7) 棋子数据——qz 表示棋子所放的位子,是用一个15*15的PictureBox类型的二维数组来表示。它还可以用来显示当前棋子的图片。 8) oldMovePoint 用来记录鼠标经过后点的位置。 9) backStack 用于悔棋的栈。 10)backTrackStack 用于回溯的栈 11)结局——result 用枚举类型来表示结局。如: public enum result : int//结局 { lose = -1, equal, win } 3.2 回溯栈元素类——StackElement 成员变量: 1) qzColor 棋子的颜色 2) bestFivePoints 最好点的位置 3) pointsCount 计算最好点的数目 4) pointNumber 点的数目 5) Theresult 结局 6) stepNumber 预测的步数 3.3 棋子点属性类——qzdianshuxing 成员变量: 1)blackConnect 黑棋子i个(包括活棋)的连接条数 2)blackActive 黑活棋i个的连接条数 3)whiteConnect 白棋子i个(包括活棋)的连接条数 4)whiteActive 白活棋i个的连接条数 5)tempActive3 活棋数为3的连接条数 3.4 主要成员函数说明 1) 初始化棋盘——Initializeqp 初始化操作包括以下几个步骤: l 设置棋子所在的位置 l 设置棋子的大小 l 初始化棋子的背景颜色 l 将棋子的sizemode设置为 CenterImage l 将棋子的可见性设置为false l 将棋子添加到form上。 2) 绘制棋盘——Form1_Paint 其主要是画出以40*40的大小为每一小格,代码如下: for (i = 0; i < 15; i++) { g.DrawLine(myPen, 30 + i * 40, 50, 30 + i * 40, 610); g.DrawLine(myPen, 30, 50 + i * 40, 590, 50 + i * 40); } 3) 绘制光标——Form1_MouseMove 当鼠标在棋盘上移动时,当前的显示画红方框,过去的显示和背景一样颜色的方框。 当前的红方框代码如下: if (10 < e.X && 10< e.Y &&e.X <ClientRectangle.Width && e.Y <ClientRectangle.Height) { x = ((e.X - 10) / 40) * 40 + 30; y = ((e.Y - 10) / 40) * 40 + 50; g.DrawLine(newpen, x - 15, y - 15, x - 15, y - 5); g.DrawLine(newpen, x - 15, y - 15, x - 5, y - 15); g.DrawLine(newpen, x + 15, y - 15, x + 5, y - 15); g.DrawLine(newpen, x + 15, y - 15, x + 15, y -5); g.DrawLine(newpen, x - 15, y + 15, x - 15, y + 5); g.DrawLine(newpen, x - 15, y + 15, x - 5, y + 15); g.DrawLine(newpen, x + 15, y + 15, x + 15, y + 5); g.DrawLine(newpen, x + 15, y + 15, x + 5, y + 15); oldMovePoint.X = x; oldMovePoint.Y = y; } 过去的方框代码如下: if (oldMovePoint.X != -1) { g.DrawLine(oldpen, oldMovePoint.X - 15, oldMovePoint.Y - 15, oldMovePoint.X - 15, oldMovePoint.Y - 5); g.DrawLine(oldpen, oldMovePoint.X - 15, oldMovePoint.Y - 15, oldMovePoint.X - 5, oldMovePoint.Y - 15); g.DrawLine(oldpen, oldMovePoint.X + 15, oldMovePoint.Y - 15, oldMovePoint.X + 5, oldMovePoint.Y - 15); g.DrawLine(oldpen, oldMovePoint.X + 15, oldMovePoint.Y - 15, oldMovePoint.X + 15, oldMovePoint.Y - 5); g.DrawLine(oldpen, oldMovePoint.X - 15, oldMovePoint.Y + 15, oldMovePoint.X - 15, oldMovePoint.Y + 5); g.DrawLine(oldpen, oldMovePoint.X - 15, oldMovePoint.Y + 15, oldMovePoint.X - 5, oldMovePoint.Y + 15); g.DrawLine(oldpen, oldMovePoint.X + 15, oldMovePoint.Y + 15, oldMovePoint.X + 15, oldMovePoint.Y + 5); g.DrawLine(oldpen, oldMovePoint.X + 15, oldMovePoint.Y + 15, oldMovePoint.X + 5, oldMovePoint.Y + 15); } 4) 下棋子——putqz 下棋子有两种可能性,一 是知道一个点的横纵坐标;二 是知道一个点。 下面我就说一说知道x,y坐标的情况,第二种情况只要调用第一种情况就行了。 假如下的是一个黑棋子,将qz的背景图设置为blackstone,并将此处标记为已下黑棋,并将此棋子标记为最后落子指示。如果悔棋的栈不为空,将其弹出栈,并将qz的图像设置为什么都没有,再将其压入栈。同理,白旗也跟这一样做。代码如下: if (qzcolor==1) { qz[x, y].BackgroundImage = global::五子棋.Properties.Resources.blackstone; points[x, y] = 1; qz[x, y].Image = global::五子棋.Properties.Resources.lastblackstone; if (backStack.Count > 0) { temp = (Point)backStack.Pop(); qz[temp.X, temp.Y].Image = global::五子棋.Properties.Resources.nullll; backStack.Push(temp); } } else { qz[x, y].BackgroundImage = global::五子棋.Properties.Resources.whitestone; points[x, y] = 0; qz[x, y].Image = global::五子棋.Properties.Resources.lastwhitestone; if (backStack.Count > 0) { temp = (Point)backStack.Pop(); qz[temp.X, temp.Y].Image = global::五子棋.Properties.Resources.nullll; backStack.Push(temp); } } 最后将其可见性设置为true。 5) 开始函数——start 当棋局开始时,就应将棋盘初始化,使棋盘上没有棋子。如果有悔棋,就要将悔棋栈清空。代码如下: if (!begin) { begin = true; for (x = 0; x < 15; x++) for (y = 0; y < 15; y++) { qz[x, y].Visible = false; points[x, y] = 2; } while (backStack.Count > 0) backStack.Pop(); } 3.5 实现人机对弈的主要函数 6) 察看两点之间的棋子数函数——ConnectqpCount 这个函数主要求两点之间可能形成五连子的qzcolor色棋的连子数(包括活期)。首先,求出两点之间总共的棋子数,并判断棋子所在哪个方向。沿着这个方向每个点的坐标,并察看这几个点中有没有反色的棋子。如果有,棋子数设为0,否则的话,棋子数自加1。代码如下: int x, y, i, j, length, xPlus = 0, yPlus = 0, sum, maxSum = 0; length = Math.Max(Math.Abs(point1.X - point2.X), Math.Abs(point1.Y - point2.Y)) + 1; if (point1.X != point2.X) xPlus = 1; if (point1.Y != point2.Y) yPlus = (point2.Y - point1.Y)/Math.Abs(point2.Y - point1.Y); for (i = 0; i < length - 4; i++) { x = point1.X + i * xPlus; y = point1.Y + i * yPlus; sum = 0; for (j = 0; j < 5; j++) {//察看两点之间当中有没有反色 if (points[x + j * xPlus, y + j * yPlus] == qzcolor) sum++; else if (points[x + j * xPlus, y + j * yPlus] == -qzcolor+1) { sum = 0; break; } } if (maxSum < sum) maxSum = sum; } return maxSum; 7) 察看两点之间是否存在活棋的函数——ActiveConnectqp 这个函数主要求两点之间qzcolor色棋是否存在活棋。temp1变量表示在一直线上,比如, 一条向下的直线,则表示点point1上方可下的个数;而temp2表示点point2下方可下的个数。代码表示为: temp1 = Math.Min(Math.Min(Math.Min(5 - count, point1.X), point1.Y), 14 - point1.Y); temp2 = Math.Min(Math.Min(Math.Min(5 - count, 14 - point2.X), 14 - point2.Y), point2.Y); 则长度表示为: length = Math.Max(Math.Abs(point1.X - point2.X), Math.Abs(point1.Y - point2.Y)) + 1 + temp1 + temp2; 先求两点之间qzcolor色棋的棋子个数,做法和函数ConnectqpCount一样。再判断它是否是活棋。当参数count和所得两点之间qzcolor色棋的棋子个数相等,并且两头都没下棋子时,它为活棋。否则,反之。代码如下: if (point1.X != point2.X) xPlus = 1; if (point1.Y != point2.Y) yPlus = (point2.Y - point1.Y) / Math.Abs(point2.Y - point1.Y); for (i = 0; i < length - 4; i++) { x = point1.X - temp1 * xPlus + i * xPlus; y = point1.Y - temp1 * yPlus + i * yPlus; if (x + 4 * xPlus > 14 || y + 4 * yPlus > 14) break; sum = 0; for (j = 0; j < 4; j++) { if (points[x + j * xPlus, y + j * yPlus] == qzcolor) sum++; else if (points[x + j * xPlus, y + j * yPlus] == -qzcolor+1) { sum = 0; break; } } if (0 < x && 0 <= y - yPlus && y - yPlus <= 14) { if (sum == count && points[x - xPlus, y - yPlus] == 2 && points[x + 4 * xPlus, y + 4 * yPlus] == 2) return true; } } 8) 查看是否被破坏活期——BreakActiveConnectqp 在(x,y)处放qzcolor色棋后形成活count,且放一反色棋后破坏棋形成活count。代码如下: if (!ActiveConnectqp(qzcolor, count, point1, point2)) return false; if (count == 5) return false; else if (count == 4) return true; else { bool blnFlag; points[x, y] = -qzcolor+1; blnFlag = !ActiveConnectqp(qzcolor, count - 1, point1, point2); points[x, y] = qzcolor; return blnFlag; } 9) 查看是否是最好的点——FindBestPoint 首先,查看有没有最佳点,并形成栈元素。如果没有,返回false;否则,将这栈元素压入回溯栈中。当栈非空时,将栈元素弹出,如果栈中的pointNumber小于pointCount时,在棋盘上下一棋。如果赢棋,不再继续探测,并在棋盘上退一棋。如果和棋的话,也不再继续探测,并在棋盘上退一棋。否则,继续下棋并探测。如果栈顶元素无点,弹出后栈必非空,并在棋盘上退一棋。如果栈顶元素中点均已试过,则寻找栈顶元素中点的最好结局,并寻找最佳步数。实现的代码如下: result totalresult = result.lose; int i, bestStepNumber = 0; StackElement tempStackElement = new StackElement(); if (first) { qzcolor = 0; if (!FindBestFivePointsAndFormAStackElement(qzcolor, ref tempStackElement)) return false; } else { qzcolor = 1; if (!FindBestFivePointsAndFormAStackElement(qzcolor, ref tempStackElement)) return false; } backTrackStack.Push(tempStackElement); while (backTrackStack.Count > 0)//栈非空 { tempStackElement = (StackElement)backTrackStack.Pop(); if (tempStackElement.pointNumber < tempStackElement.pointsCount) { //在棋盘上下一棋 points[tempStackElement.bestFivePoints[tempStackElement.pointNumber].X, tempStackElement.bestFivePoints[tempStackElement.pointNumber].Y] = tempStackElement.qzColor; if (Win(tempStackElement.qzColor, tempStackElement.bestFivePoints[tempStackElement.pointNumber])) {//赢棋,不在继续探测 tempStackElement.theresult[tempStackElement.pointNumber] = result.win; tempStackElement.stepNumber[tempStackElement.pointNumber] = backTrackStack.Count + 1; //在棋盘上退一棋 points[tempStackElement.bestFivePoints[tempStackElement.pointNumber].X, tempStackElement.bestFivePoints[tempStackElement.pointNumber].Y] = 2; tempStackElement.pointNumber++; backTrackStack.Push(tempStackElement); } else if (backTrackStack.Count == M - 1) {//将此元素压入栈后栈满,不在继续探测 tempStackElement.theresult[tempStackElement.pointNumber] = result.equal; tempStackElement.stepNumber[tempStackElement.pointNumber] = M; //在棋盘上退一棋 points[tempStackElement.bestFivePoints[tempStackElement.pointNumber].X, tempStackElement.bestFivePoints[tempStackElement.pointNumber].Y] = 2; tempStackElement.pointNumber++; backTrackStack.Push(tempStackElement); } else {//另一方继续下棋向下探测 tempStackElement.pointNumber++; backTrackStack.Push(tempStackElement); FindBestFivePointsAndFormAStackElement(-tempStackElement.qzColor+1, ref tempStackElement); backTrackStack.Push(tempStackElement); } }//end if else//栈顶元素无点或点均已试过 { if (tempStackElement.pointsCount == 0)//栈顶元素无点,且弹出后栈必非空 { tempStackElement = (StackElement)backTrackStack.Pop(); tempStackElement.theresult[tempStackElement.pointNumber - 1] = result.win; tempStackElement.stepNumber[tempStackElement.pointNumber - 1] = backTrackStack.Count + 1; //在棋盘上退一棋 points[tempStackElement.bestFivePoints[tempStackElement.pointNumber - 1].X, tempStackElement.bestFivePoints[tempStackElement.pointNumber - 1].Y] = 2; backTrackStack.Push(tempStackElement); } else//栈顶元素中点均已试过 { //寻找栈顶元素中点的最好结局 totalresult = tempStackElement.theresult[0]; for (i = 0; i < tempStackElement.pointsCount; i++) if (totalresult < tempStackElement.theresult[i]) totalresult = tempStackElement.theresult[i]; //寻找最佳步数 if (totalresult == result.win) { bestStepNumber = M + 2; for (i = 0; i < tempStackElement.pointsCount; i++) if (totalresult == tempStackElement.theresult[i] && bestStepNumber > tempStackElement.stepNumber[i]) bestStepNumber = tempStackElement.stepNumber[i]; } else//totalresult==result.equal或lose { bestStepNumber = 0; for (i = 0; i < tempStackElement.pointsCount; i++) if (totalresult == tempStackElement.theresult[i] && bestStepNumber < tempStackElement.stepNumber[i]) bestStepNumber = tempStackElement.stepNumber[i]; } if (backTrackStack.Count > 0)//栈非空 { tempStackElement = (StackElement)backTrackStack.Pop(); tempStackElement.theresult[tempStackElement.pointNumber - 1] = (result)(0 - totalresult); tempStackElement.stepNumber[tempStackElement.pointNumber - 1] = bestStepNumber; //在棋盘上退一棋 points[tempStackElement.bestFivePoints[tempStackElement.pointNumber - 1].X, tempStackElement.bestFivePoints[tempStackElemen- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基于 c# 五子棋 游戏 设计 实现
咨信网温馨提示:
1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前自行私信或留言给上传者【天****】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时私信或留言给本站上传会员【天****】,需本站解决可联系【 微信客服】、【 QQ客服】,若有其他问题请点击或扫码反馈【 服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【 版权申诉】”(推荐),意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:4008-655-100;投诉/维权电话:4009-655-100。
1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前自行私信或留言给上传者【天****】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时私信或留言给本站上传会员【天****】,需本站解决可联系【 微信客服】、【 QQ客服】,若有其他问题请点击或扫码反馈【 服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【 版权申诉】”(推荐),意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:4008-655-100;投诉/维权电话:4009-655-100。
关于本文