基于C#的五子棋游戏开发

发布时间:2020-10-24 12:07:04

青岛理工大学琴岛学院

设 计 报 告

课题名称:基于C#的五子棋游戏开发

学 院:计算机工程系

专业班级:计科(专升本)14-21

学 号:20140371006

学 生:

指导教师:

青岛理工大学琴岛学院教务处

2015年 12月 18日

学 生

指导教师

课题名称

基于C#的五子棋游戏开发

设计时间

2015.11.23-2015.12.18

设计地点

动漫1

设计目的

课程设计的目的就是培养学生的理论联系实际的能力。通过课程设计,使得学生能够加深对讲授内容的理解、累积经验、学会独立上机调试程序;并且逐步达到综合运用网页相关知识,真正掌握.NET技术的精华,从而达到熟练应用程序设计语言的目的。也为将来做较大的系统打下坚实基础。

通过本次课程设计,应该达到以下教学任务:

巩固所学知识,培养学生的上机实践能力以及独立调试程序的能力,更主要的是使学生了解做项目的大体流程。

每一个小组制定一题,项目成员要在项目经理的带领下,完成项目的所有内容。

重点掌握ASP.NET网站设计开发流程,界面要友好,功能齐全,完成一个综合项目。

指导教师

评语

系部教研室

意 见



需求分析

1.选题:

通过学习window窗体应用程序的开发与实现,对C#程序开发逐渐产生了浓厚的兴趣,

心中有了设计游戏的想法,通过学习和查资料慢慢对游戏制作有了一定的了解,后来通过深入学习,对五子棋游戏设计有了进一步了解,慢慢理清了其中的开发过程与原理,最终确定了基于C#五子棋游戏的设计与实现项目。

2.界面:

(1)通过上网学习,对游戏界面风格有了一定的认知,于是决定走界面美观风。手游中的主界面给人一种简单明了的感觉,通常有模式关卡,让玩家越玩越带感,于是决定模仿它们,游戏主界面有四个模式,玩家可以选择不同模式进行对弈。如图1所示:

模式四

模式三

模式二

模式一

图1.主界面

(2)游戏模式一,双人对战模式。界面右侧有悔棋、返回、排行榜、关于、重新开始等功能按钮,点击各按钮,执行各功能。如图2所示:

棋 盘

关于按钮

排行榜按钮

悔棋按钮

返回按钮

重新开始按钮n

图2.模式一界面

3)游戏模式二,人机对战模式。游戏界面中左部是棋盘,悔棋、返回、排行榜、关于、重新开始等功能按钮,此模式实现了人和电脑的交互。如图3所示:

棋 盘

关于按钮

排行榜按钮

悔棋按钮

返回按钮

重新开始按钮n

图3.模式二界面

(4)游戏模式三,让子挑战模式。游戏界面中左部是棋盘,右部有悔棋、返回、排行榜、关于、重新开始功能选项按钮。和模式二不同的地方是让子,开局后棋盘中布好了让给电脑的白子。正所谓有人的地方就会有争斗,游戏中有菜鸟就会有高手。高手喜欢挑战,于是挑战模式应运而生。此模式的界面和模式二界面相同,在此不再重画。

(5)游戏模式四,收拾残局模式。游戏界面中左部是棋盘,右部有摆棋、对战、悔棋、返回、再来一局功能选项按钮。和模式二不同的地方是开局,开局后玩家需先摆放棋子,然后点击对战按钮开始游戏。此模式界面设计参造模式二,不再重画。

3.功能划分:

通过对五子棋游戏的分析与了解,可知其基本功能有开始、保存、打开、悔棋、认输、和棋、返回、退出及聊天等功能。在这里,由于条件时间有限,仅实现悔棋、返回、重新开始及模式选择等功能。

(1)模式选择功能:在打开游戏后,出现在玩家面前的是模式选择窗口,即主窗口。玩家可通过点击相应按钮进入相应模式进行对弈。此功能参照手游及单机小游戏主界面简约美观的特性制作的,多模式的增加符合广大玩家的喜好。

(2)悔棋功能:在每个模式中都有悔棋功能,在模式一中每次悔棋退后一子,模式二到模式四每次悔棋退后两子,棋盘开局后就有的让子的棋子悔棋无效。人无完人,谁能不犯错,根据玩家的棋艺高低程度难以把握,为了让玩家不至于因电脑太强对开发者产生怨言,从而有了悔棋功能,进而对五子棋菜鸟起引导作用,使其怀着开心的心情与保持兴趣走向棋圣之路。对于高手而言,棋品也是要有的,悔棋功能形同虚设而已。

(3)从新开始功能:此功能是菜鸟提升棋艺的首选功能,当玩家进行游戏到中途时,因棋势不明,或要败时,不能接受这一现状,导致心情低落,怎么办?只需轻轻一点,一切回归起点,也就是初始化而已。

(4)返回功能:此功能的作用是退出当前模式,回到游戏主窗口,也就是模式选择窗口。方便玩家在各个模式自由出入,尽情的展现自己的风采。

(5)人机对弈电脑下棋功能:在模式二到模式四中,玩家的对手都是电脑,电脑棋力取决于开发者,在某中意义上来说,玩家在和开发者对弈也是正确的。此功能是程序按照一定的算法循环扫描,算出己方和敌方最佳落子点,再判断出攻守,选出最终的落子点,落子后等待玩家落子。

(6)让子功能:在模式三中,为了增加游戏难度,对棋艺大成者量身打造了让子功能。开局后,一般都是黑棋先行,在这里玩家执黑,让电脑1子,棋盘上变成了电脑执白先行1子,白棋落在天元位置上,难度一般。玩家赢后,挑战难度+1,玩家让电脑2子,棋盘上电脑执白先行2子,白棋落在天元位置左右两侧,难度适中,适合一段棋手挑战。玩家赢两局后,挑战难度+1,玩家让电脑3子,棋盘上电脑执白先行3子,考录到一般玩家没有如此高深棋力,因此白棋分散落在棋盘交叉线上,难度相对适中,适合一段及以上棋手挑战。让4子和5子也是一样的原理,难度较高,适合二段及以上棋手挑战。对战后,会在棋盘中部上方显示让子数目,为迎合玩家的虚荣心理而设计。

(7)判断胜负功能:在每个模式中都需要对对局进行胜负判断,进而产生了胜负判断功能。其功能原理是对玩家或电脑下的棋子进行循环扫描,对各个方向扫描黑白子双方是否形成五子连珠,根据形成五子连珠方判断胜负,根据判断弹出对应的胜负提示框。再根据所属模式对胜负后的对局进行参数修改,如:模式一和模式二,不论胜负只需对其进行初始化;模式三,玩家胜出,让子加一,难度增加,需对其让子参数进行修改,反之则不进行任何处理操作;模式四,玩家胜出,对局胜出参数加一,呼应必胜模式的让子布局功能,玩家失败则不进行参数修改操作等。

(8)初始化界面功能:在每个模式中都需对窗口界面进行初始化,考录到原有界面运行后的效果略显呆板,为增加美观性,需要对各窗口进行导入图片处理,美化界面。根据对局情形,在棋盘中部上方显示提示文字,并在棋盘上显示存在的棋子,对各参数进行初始化处理。

4.自定义类描述、各类方法描述及添加的命令响应。如表1所示:

表1.用到的类

类名

描述说明

Form3

模式一游戏窗口类,该类主要对该模式下的窗口初始化并对鼠标等事件消息进行处理,实现悔棋功能、返回功能、排行榜功能、关于功能、重新开始功能等。

Form4

模式二游戏窗口类,该类主要对该模式下的窗口进行初始化并对鼠标等事件消息进行处理,实现人机对弈功能、悔棋功能、返回功能、排行榜功能、关于功能、重新开始功能、提示胜败功能等。

Form5

模式三游戏窗口类,该类主要对该模式下的窗口进行初始化并对鼠标等事件消息进行处理,实现让子功能、人机对弈功能、悔棋功能、返回功能、排行榜功能、关于功能、重新开始功能、提示胜败功能等。

Form6

模式四游戏窗口类,该类主要对该模式下的窗口进行初始化并对鼠标等事件消息进行处理,实现摆棋功能、人机对弈功能、悔棋功能、返回功能、排行榜功能、关于功能、重新开始功能、提示胜败功能等。

二、总体设计

1.游戏功能概述

打开程序,游戏开始运行,登录进入模式窗口,选择游戏模式窗口弹出,窗口中有四个模式选择按钮,点击按钮,分别弹出对应的模式一、二、三、四窗口,完成具体模式的跳转。

对于模式一,玩家点击鼠标进行下棋操作,判断点击点在棋盘内且无子时,在点击点画出棋子;如果点击点在棋盘外或有子时,则不处理,返回等待鼠标命令。然后判断是否存在五子连珠,如果不存在五子连珠,则返回等待鼠标命令;如果存在五子连珠,则进行判断胜负并提示胜负信息,再调用OnStart()函数初始化模式一窗口,重新开始游戏。

玩家点击悔棋按钮,调用悔棋功能函数OnHuiqi(),在窗口中重画棋盘,去掉最后下的一个棋子,把悔棋后存在的棋子重新画在棋盘上。

玩家点击重新开始按钮,程序调用OnStart()函数,初始化模式一窗口,重新开始游戏。

对于模式二、三、四,玩家点击鼠标进行下棋操作,首先调用MouseMove函数。此函数的作用是判断点击点在棋盘内且无子时,在点击点画出棋子,如果点击点在棋盘外或有子时,则不处理,返回等待鼠标命令。然后调用gameOver()函数判断是否存在五子连珠,如果存在五子连珠,则进行判断胜负并提示胜负信息,再调用OnStart()函数初始化这一模式窗口,重新开始游戏;如果不存在五子连珠,则调用AiGo()函数,进行电脑扫描最佳落子点完成电脑下棋操作。再调用Over()函数判断是否存在五子连珠,如果不存在五子连珠,则返回等待鼠标命令;如果存在五子连珠,则进行胜负判断并提示胜负信息,再调用OnStart()函数初始化这一模式窗口,重新开始游戏。玩家点击悔棋按钮,程序调用悔棋功能函数OnHuiqi(),在窗口中重画棋盘,去掉最后下的两个棋子,把悔棋后存在的棋子重新画在棋盘上。玩家点击重新开始按钮,程序调用OnStart()函数,初始化模式一窗口,重新开始游戏。

1.绘制游戏进程图,如图4所示:

图4.流程图

三、详细设计与实现

1.悔棋功能的实现:

为悔棋按钮添加类向导,再添加int变量bushu、qi[400]、wzq[19][19],用于记录先后下棋的具体坐标,以便于悔棋功能的实现。bushu用于记录下棋的落子数,qi[400]用于记录棋子的具体坐标,wzq[19][19]用于记录棋盘上各点存在棋子的黑白及有无情况。悔棋功能的实现原理是重新画出棋盘及悔棋后存在棋子。先判断是否刚刚开局,bushu不为0,就执行悔棋命令,把最后落下的第bushu个棋子的信息初始化,再画出棋盘,重画悔棋后存在的棋子。模式一与模式二、三、四的悔棋不同之处在于悔棋棋子数。

具体代码如下:

private void OnHuiqi()

{

if(bushu>0&&star==true)

{

if(colorwhite)

colorwhite=false;

else

b = new SolidBrush(Color.White);

g.FillEllipse(b, 20 * i + 20, 20 * j + 30, 20, 20);

b.Dispose();

g.Dispose();

}

else if (wzq[i, j] == -1)

{

Graphics g = this.pictureBox1.CreateGraphics();

Brush b;

b = new SolidBrush(Color.Black);

g.FillEllipse(b, 20*i+20, 20*j+30, 20, 20);

b.Dispose();

g.Dispose();

}

}

}

}

悔棋功能的具体实现过程是先判断是否刚开局,有无可悔棋的棋子,如果有,就在窗口中重新画出棋盘,根据模式不同将最后落下的1个或2个棋子的信息初始化,再重新把悔棋后存在的棋子画在棋盘上。

2.鼠标点击落子功能的实现:

添加鼠标事件处理函数MouseDown(),先获取点击点位置坐标,再判断出点击点是否在棋盘内且无子,当点击点可落子时,就在棋盘上画出棋子,让wzq[19][19]记录该点棋子信息,把该手棋的具体坐标交给qi[bushu],用于悔棋操作,后检查游戏是否形成五子连珠,完成本次落子任务。具体代码如下:

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)

{

int x, y;

x =(e.X - 20) / 20;

y =(e.Y - 30) / 20;

if(star==true&&x>=0&&x<19&&y>=0&&y<19)

{

if (wzq[x, y] == 0)

{

Graphics g = this.pictureBox1.CreateGraphics();

Brush b;

bushu++;

if (colorwhite)

{

b = new SolidBrush(Color.White);

wzq[x, y] = 1;

colorwhite = false;

}

else

{

b = new SolidBrush(Color.Black);

wzq[x, y] = -1;

colorwhite = true;

}

g.FillEllipse(b, 20*x+20, 20*y+30, 20, 20);

b.Dispose();

g.Dispose();

gameOver(x, y);

qi[bushu] = x * 100 + y;

}

}

}

鼠标点击落子功能的运行过程是,获取点击点坐标并进行提取处理,方便棋子画在交叉线上判断点击点是否在棋盘内,如果在棋盘内。再判断点击点是否有棋子,如果没有,就根据上一手棋的颜色在点击点画上相反颜色的棋子。调用gameOver(x, y)方法,判断是否形成五子连珠,把落子点记录到qi[bushu]数组中。

3.检查游戏是否形成五子连珠,判断游戏是否结束功能:

新建gameOver()函数,进行循环扫描横竖撇捺四方向上有无黑子或白子形成五子连珠棋形,判断游戏是否结束,是否弹出胜负提示框。

具体代码如下:

private void gameOver(int x,int y)

{

int xx, yy;

if (x < 4)

xx = 0;

else

xx = x - 4;

if (y < 4)

yy = 0;

else

yy = y - 4;

int i, j, a;

for (i = xx; i < 15; i++)

{

a = 0;

for (j = i; j < i + 5; j++)

{

a = a + wzq[j,y];

if (a == 5)

{

MessageBox.Show("白棋胜!");

star = false;

return;

}

if (a == -5)

{

MessageBox.Show("黑棋胜!");

star = false;

return;

}

}

}

……

}

先获取下棋点的坐标并转化为棋盘上对应的棋子坐标,判断棋子在棋盘上的位子是否在棋盘边缘。如果是,就从棋盘(0,0)位置开始向后扫描;不是,则从点击点棋子坐标向左上方移动四个交叉位,开始向后扫描。进行循环扫描横竖撇捺四方向上有无黑子或白子形成五子连珠棋形,进而判断游戏是否结束,根据情况决定是否弹出胜负提示框。

4.让子功能实现:

在模式三中,为了增加游戏难度,开发者首创让子功能。开局后,先进行让子布局。一般都是黑棋先行,在这里玩家执黑,让电脑1子,棋盘上变成了电脑执白先行1子,白棋落在天元位置上,难度一般。玩家赢后,挑战难度+1,玩家让电脑2子,棋盘上电脑执白先行2子,白棋落在天元位置左右两侧,难度适中,适合一段棋手挑战。玩家赢两局后,挑战难度+1,玩家让电脑3子,棋盘上电脑执白先行3子,考录到一般玩家没有如此高深棋力,因此白棋分散落在棋盘交叉线上,难度相对适中,适合一段及以上棋手挑战。让4子和5子也是一样的原理,难度较高,适合二段及以上棋手挑战。

具体代码如下:

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)

{

if (jushu == 1 && wzq[9, 9] == 0&&star == true)

{ Graphics g = this.pictureBox1.CreateGraphics();

Brush b;

b = new SolidBrush(Color.White);

wzq[9, 9] = 1;

colorwhite = false;

g.FillEllipse(b, 20 * 9 + 20, 20 * 9 + 30, 20, 20);

b.Dispose();

g.Dispose();

}

……

}

鼠标移动让子功能的运行过程是,判断是否刚刚开局,如果刚开局,就根据赢棋局数进行让子布局,把让电脑先下的棋子在棋盘上画出来。如果不是刚开局,说明已经对让子布局处理过,则跳过不再处理。

5. 模式选择窗口到各模式的跳转功能实现:

新建四个window窗体,各自添加按钮控件,为模式选择窗口添加四个模式跳转按钮并对其建立点击事件,完成模式窗口到各模式的跳转。具体函数代码如下:

private void button1_Click(object sender, EventArgs e)

{

Form3 f3 = new Form3();

this.Hide();

DialogResult dr = f3.ShowDialog();

if (dr == DialogResult.OK)

this.Visible = true;

}

调用此函数后,会弹出模式一游戏窗口。其余跳转按钮代码处理与此相似,只是弹出的窗体不同,进入的模式窗口也就不同,也就实现了模式窗口的跳转功能。

6.人机对战电脑下棋功能:

添加电脑下棋方法AiGo(),循环扫描棋盘上的棋形,算出最优下棋点坐标,处理代码如下:

private void AiGo()

{ ……

for (i = 0; i < 19; i++)

for (j = 0; j < 19; j++)

{ if (a1[x1, y1] < a1[i, j])

{ y1 = j; x1 = i;

}

}

for (i = 0; i < 19; i++)

for (j = 0; j < 19; j++)

{ if (a2[x2, y2] < a2[i, j])

{ y2 = j; x2 = i;

}

}

if (a2[x2, y2] >= a1[x1, y1])

{ px = x2; py = y2;

}

else

{ px = x1; py = y1;

}

}

该算法先对棋盘上的棋子进行循环扫描,分析横竖撇捺四方向上的棋子分布情况,算出黑白棋子在棋盘上各点的棋形得分情况,分数越高,该点越重要,此部分为函数中省略部分,由于代码量庞大,不再阐述。接下来对是循环比较,分别找出黑白棋子在棋盘上的最高得分点坐标,进而比较出二者中的得分最高点坐标,即最优下棋点坐标。

7.初始化功能的实现:

private void OnStart()

{ for (int i = 0; i < 19; i++)

for (int j = 0; j < 19; j++)

wzq[i,j] = 0;

colorwhite = false;

star = true;

bushu = 0;

pictureBox1.Refresh();

}

在每个模式中都需对窗口界面进行初始化,对各参数进行初始化处理。

8.返回功能的实现:

private void button1_Click(object sender, EventArgs e)

{

this.DialogResult = DialogResult.OK;

this.Close();

}

关闭子窗体,恢复隐藏的父窗体。

四、遇到的问题及解决方案

问题1:窗口间的跳转,实现不了。

解决方法:查找资料,上网学习,百度知道,当然搜索到的答案不一定正确且不全面,需要反复尝试,于是经过慢慢尝试,解决了窗口跳转问题。

问题2:在窗口中的棋盘上画棋子,棋子有时不会落在交叉线上。

解决方法:经过仔细观察,总结规律,发现画棋子用的方法不对,画在棋盘上的棋子坐标与棋盘上的交叉点有出入。经过尝试,找到了方法,于是改变了画棋盘的方法,让每一个交叉点都有具体的坐标,这样,不管鼠标点在哪里,想办法在交叉点坐标画棋子就可以了。

问题3:实现悔棋功能时,想着把最后下的棋子去掉,却实现不了。

解决方法:静下心来,仔细看自己编写的代码,模拟电脑运行调用程序的先后顺序看代码,想象运行的结果,于是发现悔棋的棋子信息是初始化了,但没有在棋盘上表现出来,没想到好办法,只好麻烦电脑再重新画出棋盘,循环画出悔棋后存在的棋子。

问题4:判断游戏是否结束,扫描是否产生五子连珠,老是判断出错误。

解决方法:经过请教度娘后,借鉴了前辈们的方法,完成了游戏结果分析函数。

问题5:加载自己处理的图片作为游戏棋盘背景,却加载不进去或图片不管用。

解决方法:直接在属性中设置背景图片。

问题6:人机对战,机器下棋功能的实现,算法写不出来,没有头绪,不知道从何处下手。

解决方法:经过多次尝试失败后,决定借鉴前辈们的算法,于是搜索到了不少算法,心中的贪念让人无法取舍,不知道用哪个好,看着这些算法不知道怎么用,更不清楚原理。几经波折终于意识到了自己的当务之急是先理解,于是选了一个注释全面的算法,深入理解,经过尝试学会了调用这个算法的工作过程,也实现了机器下棋的功能。

问题7:让子对战模式中让电脑先下的棋子,怎样画在棋盘上,出现了问题。

解决方法:首先把这些棋子放在了OnPaint()函数中来绘制,结果有偏差,也没弄懂原因,于是尝试着在OnLButtonDown()函数中来绘制,运行界面后棋盘上无棋子,结果鼠标点击的一瞬间出现了3颗棋子,这才意识到鼠标事件产生了冲突,也想到了在点击鼠标时,鼠标的移动事件先触发,然后点击事件才被触发。想到做到,马上把这些棋子放在了OnMouseMove()中来绘制,运行正确,让子对战功能完成了。

问题8:在模式二的制作中,发现模式一的一些功能模式二都有用到,于是想到了继承,想让模式二继承模式一,尝试后发现,继承后的模式二运行界面和模式一很像,但是模式二中自建的按钮却不见了,变成了模式一中存在的按钮,和设计计划产生了误差。实现不了。

解决方法:经过取舍,决定用笨方法,不怕麻烦,方法重写一遍,虽然代码存在冗余,但为了更好的完成设计计划,先这样处理,只能以后找机会来完善了。

五、总结与体会

通过本次课程设计,学到了很多知识,接触了一些以前没接触过的领域,对C#编程有了深入的了解,也学会了很多解决问题的方法,认识到了自己的不足,同时发现原来自己也是可以做出小游戏的。在做这个项目之前,想到了自己会的和能实现的功能有哪些,自己会的也就窗口跳转和鼠标处理事件等。于是想着用到这些知识的项目有哪些是自认为可以轻松实现的,经过对比选择了五子棋小游戏开发,因为这个项目中的棋盘自己是能画出来的。对于下棋而言,也就是一个鼠标处理事件,也能实现。难点在于人机对战的算法上。于是清楚了自己接下来要做的事情,对于未知的先不要去考虑了,自己有多大能耐还不清楚,先做会做的,能实现再说。不做不知道,一做吓一跳,想着简单,做起来难,往往是在人最得意的时候来一记狠得,让人都不知道怎么着程序突然就报错了。经过慢慢尝试,一步步做下来,终于完成了基本功能的实现。接下来就是一步一步的去完善这个游戏,如何设计的更加有难度与挑战性,比如在游戏中玩家可以选择不同的模式来进行游戏,在让子模式三中玩家可以让电脑先下几颗棋子,在玩家获胜后会在棋盘中部上方显示让子数量满足玩家的虚荣心与好胜心,激起玩家的挑战欲望;如何设计的更加有趣味性,比如在模式四中玩家可以通过下残局获得荣誉称号,而且还是棋力评级称号,让玩家对未知的棋局产生兴趣。

另外,对于这个游戏还有很多需要改进的地方,比如让子模式可以把固定的让子位置做成随机的,这样给玩家一种未知的探险感觉,让玩家全身心的融入到游戏中。还可以在游戏中加入排行榜,得分记录等功能。对于这些问题,由于时间问题只能在以后的进一步学习过程中想办法对其进行解决与改进。项目能够按计划完成,需要技术与知识的支持,也少不了个人的坚持与努力,为了以后更好的完成项目,而时刻努力着。

基于C#的五子棋游戏开发

相关推荐