基于c#的五子棋游戏的设计与实现.docx
- 文档编号:25667095
- 上传时间:2023-06-11
- 格式:DOCX
- 页数:34
- 大小:92.55KB
基于c#的五子棋游戏的设计与实现.docx
《基于c#的五子棋游戏的设计与实现.docx》由会员分享,可在线阅读,更多相关《基于c#的五子棋游戏的设计与实现.docx(34页珍藏版)》请在冰豆网上搜索。
基于c#的五子棋游戏的设计与实现
郑州科技学院
课程设计论文
基于C#的五子棋游戏的设计与实现
1 引言
1.1 五子棋介绍
五子棋是起源于中国古代的传统黑白棋种之一。
现代五子棋日文称之为“連珠”,英译为“Renju”,英文称之为“Gobang”或“FIR”(FiveinaRow的缩写),亦有“连五子”、“五子连”、“串珠”、“五目”、“五目碰”、“五格”等多种称谓。
五子棋不仅能增强思维能力,提高智力,而且富含哲理,有助于修身养性。
五子棋既有现代休闲的明显特征“短、平、快”,又有古典哲学的高深学问“阴阳易理”;它既有简单易学的特性,为人民群众所喜闻乐见,又有深奥的技巧和高水平的国际性比赛;它的棋文化源渊流长,具有东方的神秘和西方的直观;既有“场”的概念,亦有“点”的连接。
它是中西文化的交流点,是古今哲理的结晶。
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
用枚举类型来表示结局。
如:
publicenumresult:
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
初始化操作包括以下几个步骤:
●设置棋子所在的位置
●设置棋子的大小
●初始化棋子的背景颜色
●将棋子的sizemode设置为CenterImage
●将棋子的可见性设置为false
●将棋子添加到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 { 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。 代码如下: intx,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 { 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++; elseif(points[x+j*xPlus,y+j*yPlus]==-qzcolor+1) { sum=0; break; } } if(maxSum maxSum=sum; } returnmaxSum; 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 { 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++; elseif(points[x+j*xPlus,y+j*yPlus]==-qzcolor+1) { sum=0; break; } } if(0 { if(sum==count&&points[x-xPlus,y-yPlus]==2&&points[x+4*xPlus,y+4*yPlus]==2) returntrue; } } 8)查看是否被破坏活期——BreakActiveConnectqp 在(x,y)处放qzcolor色棋后形成活count,且放一反色棋后破坏棋形成活count。 代码如下: if(! ActiveConnectqp(qzcolor,count,point1,point2))returnfalse; if(count==5)returnfalse; elseif(count==4)returntrue; else { boolblnFlag; points[x,y]=-qzcolor+1; blnFlag=! ActiveConnectqp(qzcolor,count-1,point1,point2); points[x,y]=qzcolor; returnblnFlag; } 9)查看是否是最好的点——FindBestPoint 首先,查看有没有最佳点,并形成栈元素。 如果没有,返回false;否则,将这栈元素压入回溯栈中。 当栈非空时,将栈元素弹出,如果栈中的pointNumber小于pointCount时,在棋盘上下一棋。 如果赢棋,不再继续探测,并在棋盘上退一棋。 如果和棋的话,也不再继续探测,并在棋盘上退一棋。 否则,继续下棋并探测。 如果栈顶元素无点,弹出后栈必非空,并在棋盘上退一棋。 如果栈顶元素中点均已试过,则寻找栈顶元素中点的最好结局,并寻找最佳步数。 实现的代码如下: resulttotalresult=result.lose; inti,bestStepNumber=0; StackElementtempStackElement=newStackElement(); if(first) { qzcolor=0; if(! FindBestFivePointsAndFormAStackElement(qzcolor,reftempStackElement)) returnfalse; } else { qzcolor=1; if(! FindBestFivePointsAndFormAStackElement(qzcolor,reftempStackElement)) returnfalse; } backTrackStack.Push(tempStackElement); while(backTrackStack.Count>0)//栈非空 { tempStackElement=(StackElement)backTrackStack.Pop(); if(tempStackElement.pointNumber { //在棋盘上下一棋 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); } elseif(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,reftempStackElement); backTrackStack.Push(tempStackElement); } }//endif 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 if(totalresult totalresult=tem
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基于 c# 五子棋 游戏 设计 实现