基于c#的五子棋游戏的设计与实现.docx

上传人:b****2 文档编号:23153308 上传时间:2023-05-08 格式:DOCX 页数:34 大小:92.56KB
下载 相关 举报
基于c#的五子棋游戏的设计与实现.docx_第1页
第1页 / 共34页
基于c#的五子棋游戏的设计与实现.docx_第2页
第2页 / 共34页
基于c#的五子棋游戏的设计与实现.docx_第3页
第3页 / 共34页
基于c#的五子棋游戏的设计与实现.docx_第4页
第4页 / 共34页
基于c#的五子棋游戏的设计与实现.docx_第5页
第5页 / 共34页
点击查看更多>>
下载资源
资源描述

基于c#的五子棋游戏的设计与实现.docx

《基于c#的五子棋游戏的设计与实现.docx》由会员分享,可在线阅读,更多相关《基于c#的五子棋游戏的设计与实现.docx(34页珍藏版)》请在冰豆网上搜索。

基于c#的五子棋游戏的设计与实现.docx

基于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

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 机械仪表

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1