井字棋设计.docx
- 文档编号:11773121
- 上传时间:2023-04-01
- 格式:DOCX
- 页数:20
- 大小:205.84KB
井字棋设计.docx
《井字棋设计.docx》由会员分享,可在线阅读,更多相关《井字棋设计.docx(20页珍藏版)》请在冰豆网上搜索。
井字棋设计
学号:
************
上海海事大学
“程序设计”课程设计(报告)
设计题目:
井字棋
学院:
信息工程学院
专业:
计算机科学与技术
班级:
计算机
姓名:
指导老师:
完成日期:
1.引言
井字棋,又名Tic-Tac-Toe,是一种在3*3类似井字格子上进行的游戏,然后由分别代表O和X的两个对弈者轮流在格子里留下标记。
最先在任意一条直线上成功连接三个相同标记的一方,则判定为胜利,若双方都没有连成一直线,则判定为平局。
在这里,包括玩家与电脑之间的对弈。
1.1背景
玩过这个游戏的人大都会发现,这是一个界面友好、规则易懂以及玩法简单的小游戏。
为了使它能更方便的展现在游戏平台上,设计一个井字棋游戏的界面是一个很好的选择。
1.2动机
众所周知,井字棋是一个休闲类的游戏,主要在其玩法十分简便。
而自身通过对游戏开发的学习,同时在学习对界面的设置的过程中能吸收各方面知识,有利于提高解决实际问题的能力。
如果井字棋开发成功的话,可以使同学们享受到以下乐趣:
(1)友好的界面带给对弈者不同的体验。
(2)轻松、简单的玩法使同学们一玩就会,在课余时间享受简单玩法的乐趣。
(3)可以与同学们一起动脑求得必赢的对弈方法,充满乐趣。
所以,本系统旨在开发一个简单,能体验井字棋pc游戏平台。
1.3要解决的问题
当然,还需要解决以下问题:
(1)棋盘和棋子的绘制:
需要一个3*3的棋盘,还有两个玩家不同的“棋子”,O和X。
(2)盘初始化:
要在游戏开始前设置一个登录界面,输入名称后如何显示出棋盘界面。
在一局之后如果要继续,要怎么样清空棋盘并开始下一局。
(3)设置菜单栏,其中要包括开始、退出等操作。
(3)利用权重来计算下一步落棋位置。
(4)胜负判断:
给出胜负判断标准,要准确判断游戏的输赢并在最后显示出来,平局的时候应该如何判断,同时也要显示出来。
2.系统框架
井字棋的运行方式很简单,具体方法如下:
当对弈者选择对弈者先手并点击开始游戏的情况下,首先判断棋盘上有无空格,如果有,则对弈者先下,然后电脑判断下棋,继而判断有无三子连成一线,若有,则输出结果、游戏结束,若无,先判断棋盘上有无空格,如果有,则对弈者下,再判断。
直到有三点连成一线,则输出对弈结果;如果没有三点连成一线并且棋盘上再无空格,则输出结果为平局。
游戏结束后对弈者可选择重新开始或结束游戏。
井字棋流程示意图如下图2.1所示:
图2.1流程示意图
3.数据结构设计
(1)棋盘需要初始化privatevoidinitializeDisplay(),定义棋盘的大小以及下棋所需的9个格。
定义电脑判断下棋位置的权重矩阵int[,]weightMatrix以及表示每格中棋子的状态矩阵int[,]statusMatrix,0表示棋盘上无子,1表示电脑下子,10表示对弈者下子。
(2)记录对弈者信息:
在游戏开始前输入玩家的姓名,在游戏结束后输出结果switch(gameresult),记录输赢情况。
4.关键技术
计算下一步落子的位置,是本系统的关键。
权值指这个指标在整个分析过程中所占的重要程度,所以我们采用比较权值的大小来判断电脑的下一步落子位置。
4.1界面的初始化
在游戏中首先要定义的就是棋盘以及下子所需的棋子。
4.1.1棋子的绘制
在棋子的设置过程中,使用Graphics类,Graphics类表示封装一个GDI+绘制图面,其中Drawline(Pen,Point,Point)表示绘制一条连接两个Point结构的线,DrawEllipse(Pen,Single,Single,Single,Single)表示绘制一个由边框定义(该边框由一对坐标、高度和宽度制定)的椭圆(此地可用作圆)。
而Pen类表示对象制定绘制的图形外轮廓线宽度和颜色,即Pen(Colorcolor,floatwidth)。
Bitmap表示对象的作用是用来显示位图的。
//绘制对弈者棋子:
X
Bitmapuserchess=newBitmap(38,38);//对弈者棋子所占空间大小为38*38的格子
Graphicsg;//定义视图类
g=Graphics.FromImage(userchess);
Penp1=newPen(Color.DarkRed,4);//设置对弈者棋子颜色以及棋子宽度
g.DrawLine(p1,newPoint(1,1),newPoint(37,37));//直线表示X中的\
g.DrawLine(p1,newPoint(1,37),newPoint(37,1));//直线表示X中的/
human_pic.Image=userchess;
//绘制电脑棋子:
O
Bitmapcomputerchess=newBitmap(38,38);
g=Graphics.FromImage(computerchess);
Penp2=newPen(Color.DarkBlue,4);//设置电脑棋子颜色以及棋子宽度
g.DrawEllipse(p2,1,1,35,35);//绘制O
compu_pic.Image=computerchess;
4.1.2棋盘的设置
设置mainGround为主要的下棋界面,设置棋盘的大小为450*450,同时设置分割线的颜色以及宽度,形成一个友好的界面。
BitmapmainGround=newBitmap(450,450);//用Bitmap定义主要棋盘并设置整个棋盘为450*450的大小
g=Graphics.FromImage(mainGround);
Penp=newPen(Color.Gray,4);//设置棋盘框架的颜色以及宽度
for(inti=0;i<2;i++)
{
//在450*450的空间里分别绘制两条横向和两条纵向的线以此勾画出九个格子表示棋盘
g.DrawLine(p,newPoint((i+1)*150,0),newPoint((i+1)*150,450));//表示棋盘中的||
g.DrawLine(p,newPoint(0,(i+1)*150),newPoint(450,(i+1)*150));//表示棋盘中的=
}
4.1.3棋盘上棋子的设置
棋盘上的棋子要与棋盘上九个格子的大小成比例,使得下棋过程中的美观。
在设置过程中,对弈者棋子为X,电脑棋子为O,0表示棋盘上无子,1表示电脑下子,10表示对弈者下子。
BitmapmainGround=newBitmap(450,450);//表示在450*450已经建成棋盘的Panel中
Graphicsg;
g=Graphics.FromImage(mainGround);
Penp1=newPen(Color.DarkBlue,4);//表示电脑的棋子的颜色和宽度
Penp2=newPen(Color.DarkRed,4);//表示人的棋子的颜色和宽度
Penp=newPen(Color.Gray,4);//表示棋盘的颜色和宽度
//在棋盘上,i表示行,j表示列,用i、j表示棋子落子的位置,在对落子的确切位置和轮到谁落子确定后通过下面的代码可以在棋盘的每个格子上准确的显示出应该出现的棋子
for(inti=0;i<3;i++)
for(intj=0;j<3;j++)
{
if(statusMatrix[i,j]==1)//如果电脑下子,只要鼠标点到的格子,就会出现如下代码表示的O
g.DrawEllipse(p1,i*150+10,450-j*150-120-10,120,120);
if(statusMatrix[i,j]==10)//如果轮到人下子,只有鼠标点击到的格子,就会出现如下代码所示的X
{
g.DrawLine(p2,newPoint(i*150+10,450-j*150-10),newPoint(i*150+130,450-j*150-130));
g.DrawLine(p2,newPoint(i*150+10,450-j*150-130),newPoint(i*150+130,450-j*150-10));
}
}
4.2判断对弈输赢
定义判断输赢结局的函数名称为THINK,并创建两个3*3的矩阵:
状态矩阵statusMatrix和权直矩阵weightMatrix。
状态矩阵表示每个格子是否已有棋落子同时也判断谁落子了。
权值矩阵是针对电脑的落子而产生的,通过比较可落子位置的权值大小,电脑可以判断在空的格子中哪个格子更有利于游戏的胜利。
4.2.1棋盘初始化
publicclassTHINK
{
int[,]statusMatrix;
int[,]weightMatrix;
//在还没有落子前,空棋盘的状态矩阵statusMatrix[i,j]=0,而由于还未有人下子,所以权值矩阵weightMatrix[i,j]=-1,表示权值很小。
publicTHINK()
{
statusMatrix=newint[3,3];
weightMatrix=newint[3,3];
for(inti=0;i<3;i++)
for(intj=0;j<3;j++)
{
statusMatrix[i,j]=0;//这里是一个棋盘的初始化
weightMatrix[i,j]=-1;
}
}
publicint[,]getNextStep(int[,]inputMatrix)
{
intmaxWeight=0;
List
intpositionPicked=0;
for(inti=0;i<3;i++)
for(intj=0;j<3;j++)
statusMatrix[i,j]=inputMatrix[i,j];
for(inti=0;i<3;i++)
for(intj=0;j<3;j++)
//由于棋盘上还没有落子,当statusMatrix[i,j]==0即棋盘为空的时候,棋子的权重就毫无意义,所以weightMatrix[i,j]=0。
if(statusMatrix[i,j]==0)
{
weightMatrix[i,j]=0;
4.2.2权值大小判断
下面开始判断电脑下棋落子格子的权重大小,以此来确定电脑落子的具体位置。
其中权值大小A>B>C>D。
在考虑完各方面的因素并对相应的权重进行加减操作后可以得到最终的权值的结果,根据权值的大小进行下棋落子位置的操作
//A表示轮到电脑下棋时,在任意一条直线上,如果有两个格子为电脑下的子并且剩下的一个格子里为空,那么电脑下一步的落子位置将在那个剩下的格子中。
在这里将所有的可能性都考虑在内
if(statusMatrix[i,0]+statusMatrix[i,1]+statusMatrix[i,2]==2)
weightMatrix[i,j]+=10000;//表示在棋盘上横向的直线上有两个电脑的棋子
if(statusMatrix[0,j]+statusMatrix[1,j]+statusMatrix[2,j]==2)
weightMatrix[i,j]+=10000;//表示在棋盘上纵向的直线上有两个电脑的棋子
if(i==j&&statusMatrix[0,0]+statusMatrix[1,1]+statusMatrix[2,2]==2)
weightMatrix[i,j]+=10000;//表示在棋盘上正对角线上有两个电脑的棋子
if(i+j==2&&statusMatrix[0,2]+statusMatrix[1,1]+statusMatrix[2,0]==2)
weightMatrix[i,j]+=10000;//表示在棋盘上另一对角线上有两个电脑的棋子
//B表示轮到电脑下棋,并且在任意直线上,电脑没有可能获得胜利时,电脑需要考虑到对弈者有可能获得胜利,在这里主要在于堵住对弈者可能赢得胜利的格子
if(statusMatrix[i,0]+statusMatrix[i,1]+statusMatrix[i,2]==20)
weightMatrix[i,j]+=1000;//表示在棋盘上横向的直线上有两个对弈者的棋子
if(statusMatrix[0,j]+statusMatrix[1,j]+statusMatrix[2,j]==20)
weightMatrix[i,j]+=1000;//表示在棋盘上纵向的直线上有两个对弈者的棋
if(i==j&&statusMatrix[0,0]+statusMatrix[1,1]+statusMatrix[2,2]==20)
weightMatrix[i,j]+=1000;//表示在棋盘上正对角线上有两个对弈者的棋子
f(i+j==2&&statusMatrix[0,2]+statusMatrix[1,1]+statusMatrix[2,0]==20)
weightMatrix[i,j]+=1000;//表示在棋盘上另一对角线上有两个对弈者的棋子
//C表示当中心点为空时,电脑走中心的权重的大小。
在这里默认当电脑先手时,电脑走的必定为中心
if(i==1&&j==1)
weightMatrix[i,j]+=400;
//D表示在双方都没有有利于胜利的可落子的地方时,电脑在剩下的可落子的格子中的权值是很小的。
if(i+j==2&&i!
=j)
weightMatrix[i,j]+=300;//表示在非正对角线的位子上有两个电脑下的棋子
if(i==j&&i!
=1)
weightMatrix[i,j]+=300;
4.2.3特殊情况
当然在下棋的过程中还包括了许多特殊情况,这样的特殊情况需要在下面的代码中一一列出。
//当[0,0]和[2,2]位置上的棋子为对弈者的棋子时,在[0,2]和[2,0]位置上的权值会相对减少
if(statusMatrix[0,0]+statusMatrix[2,2]==20)
{
weightMatrix[0,2]-=500;
weightMatrix[2,0]-=500;
}
if(statusMatrix[2,0]+statusMatrix[0,2]==20)
{
weightMatrix[0,0]-=500;
weightMatrix[2,2]-=500;
}
}
//同时我们还使用了Random,对于同样的对弈者的布局,使用Random会使电脑下出不同的方案
privateintRandomInt(intmax)
{
intresult;
Randomrd=newRandom();
result=rd.Next(max);
returnresult;
}
4.3对弈者的选择
在对弈者开始下棋前要选择是对弈者先手还是电脑先手。
privatevoidradioButton1_CheckedChanged(objectsender,EventArgse)
{
Computerfirst=false;
}//对弈者先手
privatevoidradioButton2_CheckedChanged(objectsender,EventArgse)
{
Computerfirst=true;
}//电脑先手
4.4结局的输出
在游戏结束后,游戏会显示出游戏的输赢情况,在这里实用一个switch结构在解决这个问题,表明了输出结果的代码。
switch(gameresult)
{case1:
//1表示第一种情况,表明电脑赢了
finished=true;
label3.Text="电脑赢了";
break;
case10:
//10表示第二种情况,表明对弈者赢了
finished=true;
label3.Text="对弈者赢了";
break;
case100:
//100表示第三种情况,表明平手
finished=true;
label3.Text="平手";
break;
default:
//表明游戏的默认值,当没有输赢的情况下会一直显示直到游戏结束
finished=false;
label3.Text="请下子";
break;
}
4.4.1电脑赢
for(inti=0;i<3;i++)
if(statusMatrix[i,0]+statusMatrix[i,1]+statusMatrix[i,2]==3)
result=1;
for(intj=0;j<3;j++)
if(statusMatrix[0,j]+statusMatrix[1,j]+statusMatrix[2,j]==3)
result=1;
if(statusMatrix[0,0]+statusMatrix[1,1]+statusMatrix[2,2]==3)
result=1;
if(statusMatrix[0,2]+statusMatrix[1,1]+statusMatrix[2,0]==3)
result=1;
4.4.2对弈者赢
for(inti=0;i<3;i++)
if(statusMatrix[i,0]+statusMatrix[i,1]+statusMatrix[i,2]==30)
result=10;
for(intj=0;j<3;j++)
if(statusMatrix[0,j]+statusMatrix[1,j]+statusMatrix[2,j]==30)
result=10;
if(statusMatrix[0,0]+statusMatrix[1,1]+statusMatrix[2,2]==30)
result=10;
if(statusMatrix[0,2]+statusMatrix[1,1]+statusMatrix[2,0]==30)
result=10;
4.4.3平手
intblank=0;
for(inti=0;i<3;i++)
for(intj=0;j<3;j++)
if(statusMatrix[i,j]==0)
blank++;
if(result==0&&blank==0)
result=100;
returnresult;
}
4.5菜单栏
在菜单栏处包括游戏(新游戏,退出)和帮助(关于井字棋)。
向游戏界面上移动一个菜单栏MenuStrip到合适的位置,输入文本“游戏”,在下面分别输入“开始”和“退出”,在右边输入“帮助”,在其下输入“关于井字棋”,这样就建成了一个简单的菜单栏。
//“开始”表示不论之前如何,只要点击“开始”,界面又回到初始化,游戏重新开始
privatevoid开始ToolStripMenuItem_Click(objectsender,EventArgse)
{
initializeGame();
if(Computerfirst)//表明如果电脑先手,那么电脑就会根据之前的走法选择最有利于电脑本身的走法
{
toNextStep();
displayChess();
}
}
//设置“关于井字棋”的窗口并实现只要在游戏中点击“关于井字棋”就能出现有关井字棋介绍的小窗口。
privatevoid关于井字棋ToolStripMenuItem_Click(objectsender,EventArgse)
{
Form2frm=newForm2();
frm.Show();//show()函数表明制定窗口显示状态,在这里表明Form2在窗口中显示
}
//点击“退出”程序自动全部退出
privatevoid退出ToolStripMenuItem1_Click(objectsender,EventArgse)
{
Application.ExitThread();
}
4.6用户登录
井字棋游戏开始前需要一个用户的登录界面,使得游戏看起来更完整,而登录界面需要与游戏界面连接起来,所以这里用到了继承。
publicpartialclassForm3:
Form//继承
{
publicForm3()
{
InitializeComponent();
}
//button1设置为文本“确定”,点击确定后,显示游戏界面,继而开始游戏。
privatevoidbutton1_Click(objectsender,EventArgse)
{
Form1frm=newForm1();
rm.Show();
}
4.7应用程序
staticvoidMain()
{
Application.EnableVisualStyles();//应用程序启用可视样式
Application.SetCompatibleTextRenderingDefault(false);//在应用程序范围内设置控件显示文本的默认方式
if(newForm3().ShowDialog()==DialogResult.OK)//在确认用户登录后才能开始游戏
Application.Run(newForm1());//用户登录之后出现游戏界面
}
5.系统运行结果
5.1系统运行环境
硬件环境:
操作系统:
Windows7旗舰版
系统类型
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 井字棋 设计