扫雷程序设计.docx
《扫雷程序设计.docx》由会员分享,可在线阅读,更多相关《扫雷程序设计.docx(22页珍藏版)》请在冰点文库上搜索。
扫雷程序设计
程序设计报告
(2014/2015学年第一学期)
题目:
利用C#开发的扫雷程序
专业理工科强化班
组员学号姓名栗森安Q13010423
胡涛Q13010421
指导教师俞琼
指导单位南京邮电大学
日期2014年10月24日
成员分工
组员(胡涛)
负责编写程序核心代码调试程序
组员(栗森安)
负责扫雷程序各个界面的设计;
编写调用各资源的代码以及界面按钮操作;
共同检验核心代码正确性;
负责查错,调试程序;
评分细则
评分项
优秀
良好
中等
差
遵守机房规章制度
上机时的表现
学习态度
程序准备情况
程序设计能力
团队合作精神
课题功能实现情况
算法设计合理性
用户界面设计
报告书写认真程度
内容详实程度
文字表达熟练程度
回答问题准确度
简短评语
教师签名:
年月日
评分等级
胡涛Q13010421
栗森安Q13010423
备注
评分等级共五种:
优秀、良好、中等、及格、不及格
利用C#开发的扫雷程序
一、实验内容和要求
(1)定义一个矩阵,随机产生地雷的分布并由此产生提供给游戏者的数字信息。
(2)定义成绩排行榜,记录前五名的用户名及时间。
(3)提供菜单功能,定义不同等级的地雷地图供选择。
(4)游戏者通过坐标(如1(1,2)、0(3,4)判定第一行第二列位置为地雷,第3行第四列不是地雷)判定是否为地雷,标记地雷位置正确,则正确位置显示@符号,如触碰地雷,游戏结束,没有触碰地雷,显示该坐标位置周边地雷分布情况,如果周边有地雷不显示。
(5)成绩排行榜以文件形式保存。
(6)鼓励采用TurboC/C++、MFC等开发工具,实现彩色或图形操作界面。
二、实验目的
1.掌握窗体设计步骤、窗体调用
2.学习Form窗体中控件的灵活使用,能基本理解所学代码的基本含义
3.会使用button、panel、label、textbox、menustrip等按钮,并会使用二维数组的定义与使用二维数组定义雷区,通过enable按钮控制器可使用性
4.能通过Location、size等控制界面的合理大方
5.能使用picturebox、timer等控件的加入,并能通过属性按钮来完成所需要的结果
三、实验任务
(1)随机产生地雷的分布并由此产生提供给游戏者的数字信息;
(2)定义成绩排行榜,记录用户名和时间;
(3)提供菜单功能,定义不同等级的地雷地图供选择;
(4)可通过鼠标操作(右键插旗,左键点击格子);
(5)成绩排行榜保存为.txt文件;
四、实验内容
1.完成扫雷游戏主界面、自定义界面、游戏成功后登记界面,扫雷排名界面的创建;添加各界面的控件(menustrip、button、label、panel等)
2.对各个button和menustrip插入代码
NewGame
privatevoidnesToolStripMenuItem_Click(objectsender,EventArgse)
{
button1.Image=Image.FromFile("face.bmp");
DelAllMines();
RestMine=MineNum;
CostTime=0;
label1.Text=CostTime.ToString();
GamesBegin();
GameInit();
timer1.Enabled=true;
}
Beginner
privatevoidbeginnerToolStripMenuItem_Click(objectsender,EventArgse)
{
button1.Image=Image.FromFile("face.bmp");
beginnerToolStripMenuItem.Checked=true;
intermediateToolStripMenuItem.Checked=false;
expertToolStripMenuItem.Checked=false;
customToolStripMenuItem.Checked=false;
DelAllMines();
XNum=9;
YNum=9;
MineNum=10;
RestMine=MineNum;
label1.Text=CostTime.ToString();
GamesBegin();
GameInit();
timer1.Enabled=true;
detform();
}
Intermediate
privatevoidintermediateToolStripMenuItem_Click(objectsender,EventArgse)
{
button1.Image=Image.FromFile("face.bmp");
beginnerToolStripMenuItem.Checked=false;
intermediateToolStripMenuItem.Checked=true;
expertToolStripMenuItem.Checked=false;
customToolStripMenuItem.Checked=false;
DelAllMines();
XNum=16;
YNum=16;
MineNum=40;
RestMine=MineNum;
label1.Text=CostTime.ToString();
GamesBegin();
GameInit();
timer1.Enabled=true;
detform();
}
Expert
privatevoidexpertToolStripMenuItem_Click(objectsender,EventArgse)
{
button1.Image=Image.FromFile("face.bmp");
beginnerToolStripMenuItem.Checked=false;
intermediateToolStripMenuItem.Checked=false;
expertToolStripMenuItem.Checked=true;
customToolStripMenuItem.Checked=false;
DelAllMines();
XNum=30;
YNum=16;
MineNum=99;
RestMine=MineNum;
label1.Text=CostTime.ToString();
GamesBegin();
GameInit();
timer1.Enabled=true;
detform();
}
Custom
privatevoidcustomToolStripMenuItem_Click(objectsender,EventArgse)
{
button1.Image=Image.FromFile("face.bmp");
beginnerToolStripMenuItem.Checked=false;
intermediateToolStripMenuItem.Checked=false;
expertToolStripMenuItem.Checked=false;
customToolStripMenuItem.Checked=true;
Formzdy=newForm2();
zdy.ShowDialog();
if(zdy.DialogResult==DialogResult.OK)
zdyGames();
}
核心代码
初始定义
privateButton[,]Mines;//定义二维动态数组用于显示雷区
privateintXNum=9;//初始化累的列数(即为:
初级时的行列数)
privateintYNum=9;//初始化雷的行数
publicstaticintzdyXNum;//用于自定义中的列数
publicstaticintzdyYNum;//用于自定义中的行数
privateintMineNum=10;//初始化雷的总数
publicstaticintzdyMineNum;//用于记录自定义中的雷数
privateint[,]Turn;//用二维数组赋值:
-1表示这个位置已经翻开;0表示这个位置没有翻开;1表示这个位置插上红旗;
publicstaticintCostTime=0;//计量所用的时间
privateintStartTime=0;//初始化时间
privateintRestMine=10;//用于改变等级时载入剩余雷数
privateintMineWidth=20;//控制雷块的大小
删除雷区
privatevoidDelAllMines()
{
for(inti=0;ifor(intj=0;j{
Buttonn=newButton();
n=(Button)Mines[i,j];
this.Controls.Remove(Mines[i,j]);
}
}
游戏开始
privatevoidGamesBegin()//用于开始游戏,主要是定义雷区
{
Turn=newint[XNum,YNum];//定义新的二维数组
Mines=newButton[XNum,YNum];//定义按钮
for(intx=0;xfor(inty=0;y{
Mines[x,y]=newButton();
this.Controls.Add(Mines[x,y]);//增加新按钮
Mines[x,y].Left=20+MineWidth*x;//定义雷区开始在Form窗体中的左边界
Mines[x,y].Top=72+MineWidth*y;//定义雷区开始在Form窗体中的上边界
Mines[x,y].Width=MineWidth;//定义雷块的宽度
Mines[x,y].Height=MineWidth;//定义雷块的高度
Mines[x,y].Font=newFont("宋体",10.5F,FontStyle.Bold,GraphicsUnit.Point,((byte)(134)));//定义字体
Mines[x,y].BackgroundImageLayout=System.Windows.Forms.ImageLayout.Stretch;//定义backgroundimageLayout
Mines[x,y].Name="Mines"+(x+y*XNum).ToString();//定义雷区的名字
Mines[x,y].MouseUp+=newMouseEventHandler(bt_MouseUp);//定义单击事件
Mines[x,y].Visible=true;//控制Mines按钮的可见
}
detform();
}
游戏初始化
privatevoidGameInit()
{
RestMine=MineNum;
label1.Text=RestMine.ToString();
for(intx=0;xfor(inty=0;y{
Mines[x,y].Text="";
Mines[x,y].Visible=true;
Mines[x,y].Enabled=true;
Mines[x,y].Tag=null;
Mines[x,y].BackgroundImage=null;
Turn[x,y]=0;
}
随机布雷
privatevoidLayMines()
{
intx,y;
Randoms=newRandom();
for(inti=0;i{
x=s.Next(XNum);
y=s.Next(YNum);
if(Convert.ToInt16(Mines[x,y].Tag)!
=1)
{
Mines[x,y].Tag=1;
i++;
}
}
label1.Text=MineNum.ToString();
CostTime=0;
label2.Text=StartTime.ToString();
}
获取方块周围雷数
privatevoiddetpicture(intn,inti,intj)//用于调用不同的图片显示所单击按钮周围所剩的雷数
{
switch(n)
{
case1:
{
Mines[i,j].BackgroundImage=Image.FromFile("1.PNG");
break;
}
case2:
{
Mines[i,j].BackgroundImage=Image.FromFile("2.PNG");
break;
}
case3:
{
Mines[i,j].BackgroundImage=Image.FromFile("3.PNG");
break;
}
case4:
{
Mines[i,j].BackgroundImage=Image.FromFile("4.PNG");
break;
}
case5:
{
Mines[i,j].BackgroundImage=Image.FromFile("5.PNG");
break;
}
case6:
{
Mines[i,j].BackgroundImage=Image.FromFile("6.PNG");
break;
}
case7:
{
Mines[i,j].BackgroundImage=Image.FromFile("7.PNG");
break;
}
case8:
{
Mines[i,j].BackgroundImage=Image.FromFile("8.PNG");
break;
}
}
}
载入
privatevoidForm1_Load_1(objectsender,EventArgse)
{
stringpath;
path=System.Windows.Forms.Application.StartupPath;
if(!
File.Exists(path+"\\Beginner.txt"))
File.Create(path+"\\Beginner.txt");
if(!
File.Exists(path+"\\Intermediate.txt"))
File.Create(path+"\\Intermediate.txt");
if(!
File.Exists(path+"\\Expert.txt"))
File.Create(path+"\\Expert.txt");
beginnerToolStripMenuItem.Checked=true;
Load_Mine();
GameInit();
timer1.Enabled=true;
}
自定义设置
privatevoidzdyGames()//自定义游戏
{
DelAllMines();//删除残余雷片
XNum=zdyXNum;//定义雷区的列数
YNum=zdyYNum;//定义雷区的行数
MineNum=zdyMineNum;//定义总雷数
label1.Text=CostTime.ToString();//用于在开始界面显示所用的时间
GamesBegin();//开始游戏
GameInit();//游戏初始化
timer1.Enabled=true;//触发计时器
}
胜利条件
privateboolVictory()//检测是否胜利
{
for(inti=0;ifor(intj=0;j{
//没翻开且未标示,则未成功
if(Mines[i,j].Enabled==true&&Turn[i,j]!
=1)
returnfalse;
//不是雷却误标示为雷,则也未成功
if(Convert.ToInt16(Mines[i,j].Tag)!
=1&&Turn[i,j]==1)
returnfalse;
}
returntrue;
}
五、测试游戏
1.游戏打开界面
2.排行榜
3.自定义界面输入查错
3.游戏胜利界面
输入成绩界面
六、测试中发现的问题
1.保存成绩的文本文档需要手动选择,不能在选择游戏难度时自动选择
2.扫雷中的控件不随界面的大小变化而变化
3.扫雷排行榜可以在外部对保存文件进行修改。
(最好保存为.dat格式)
七、程序设计总结
一个星期的程序设计,虽然很短暂但在小伙伴的帮助下我们还是完成了任务,还记得当初刚拿到题目的时候感觉题目要求都很简单,所以决定用上学期自学的C#窗体弄出一个扫雷的图形化界面(显得高大上一些),可真正到做界面、码代码的时候发现一些事情根本没有想象中那么简单。
(1)首先窗体设计看似分分钟的事情,结果却花了我接近一天的时间,因为界面大小不是一定的,要随玩家选择不同难度而改变大小,所以里面的一些Button、label等控件的位置是一个跟雷区的宽和高有关的函数。
(2)其次是后台函数的书写,这个我不得不说函数个数和难度远远超出我的想象。
特别是Expandmines()这个函数,根本不知道怎么写,最后还是上网查的,那个递归方法虽然我知道存在但在我还处于婴儿阶段的年龄里至今还未用过这么方法。
所以还是那句话,理论不能应用于实际都是浮云。
(3)最后就是调试阶段了,我觉得让这个我有生以来写得最长的代码不报错已经差不多了,后来调试过程中的问题更是让我崩溃。
程序跑起来的时候发现数字与周围雷的个数不匹配,于是我仔细看那个GetAroundNum(intR,intC)函数,看了三四遍才发现少了一个“=”号,想想我也是醉了。
多简单的一个错误花了我那么长时间。
所以码代码不仅需要智慧还需要耐心和细心,那些你不经意间留下的错误有可能毁了你前面所有的努力。
Allinall,虽然走了很多弯路但结果还是完美的,程序设计中不仅提高了自己编程的能力而且教会了我很多其它方面的能力,加强了我的查阅资料和与人合作的能力,在团体中也要发挥团体的合作的精神,互相帮助方能共同进步@栗森安。
最后,还要感谢俞琼老师在这一周的指导,你的信任更是给我们凌晨码代码提供动力和精神。
胡涛Q13010421
一个星期的程序设计,虽然短暂但是收获了很多surprise。
刚开始只是准备“抱大腿”。
但一周后证明自己不是打酱油的,完全能胜任所负责的部分。
一周前,扫雷的程序本来只是脑中早已想到的黑白界面,一周的努力将它变为“亲民”和“绚烂”的视窗界面。
所以需要有敢于尝试的决心。
当然也要感谢胡涛同学的灵感,否则也想不到设计窗体。
作为程序的优化人员,我的职责就是负责窗体各项属性的调整,使它看起来比较舒服。
听起来很简单,实际操作却遇到了很多麻烦。
例如扫雷排行榜界面曾出现过这样的问题:
后台的代码没有问题,但是实际只需要把textbox回拉一下。
这样的问题还有不少。
当整个程序主体完工后,我和胡涛的创造(恶搞)精神让我们将整个程序提升了一个境界。
扫雷的音效,排行榜分级排名(仍然存在一定的问题,见六),cheatmod;再一次感受到到程序可以改变世界。
这些虽然和程序设计的核心内容不太沾边,但是一个好的程序也是离不开这些的;在这个方面所投入的精力不亚于核心代码。
作为胡同学的队友,纠错也是我的工作,胡同学经常陷入此类困境,这个时候就由略冷静的我来发现一些小错误,==();堪称好队友。
(上面心得的格式要不要帮他改呢?
?
?
)。