扫雷小程序设计.docx
- 文档编号:30428754
- 上传时间:2023-08-14
- 格式:DOCX
- 页数:29
- 大小:440.01KB
扫雷小程序设计.docx
《扫雷小程序设计.docx》由会员分享,可在线阅读,更多相关《扫雷小程序设计.docx(29页珍藏版)》请在冰豆网上搜索。
扫雷小程序设计
第1章问题描述与分析
1.1问题描述
扫地雷是一个广泛游戏,扫地雷的游戏规则:
扫雷就是要把所有非地雷的格子揭开即胜利;踩到地雷格子就算失败。
当鼠标点击到棋盘范围外时,视为无效,无响应。
游戏主区域由很多个方格组成。
基本要求为:
1.用程序设计分析思想对选题进行分析设计
2.用C语言对选题进行代码实现
测试要求为:
1.进行系统功能性测试,验证基本功能实现情况。
2.进行边界测试及特殊数据用例测试,验证功能模块的逻辑分支流程。
1.2问题分析
仔细分析课题的要求并粗略分析可以得到大致得到:
1.选择棋盘的大小(6*6,9*9,11*11)
2.选择游戏的难度(简单10%的雷,一般20%的雷,困难30%的雷)
3.绘制一个扫雷的面板。
4.根据鼠标点击位置确定所点格子位置。
5.判断格子是否是地雷,若为地雷则游戏结束。
若非地雷显示周围8个格子所含地雷总数。
6.若所有非地雷的格子揭开,则胜利,否则一直循环进行2、3步。
7.
第2章算法设计与流程图
2.
2.1算法设计
扫雷游戏的设计可以从三方面进行考虑:
1.面板的选择(BoardChoice)
2.难度的选择(LevelChoice)
3.游戏主界面(Game)
这三方面即为游戏进行的过程,大致可以画出如图2-1的模块图:
图2-1扫雷游戏设计的模块图
(1)面板的选择
在该模块中,需要决定面板的大小,即每行每列有多少个格子。
在设计时,个人决定使用6*6,9*9和11*11的格子面板。
设计中,个人决定设置3个按钮分别作为3种面板的选择。
在具体实现时,需要从两方面进行考虑,即:
位置确定和数据传入。
位置确定即为确定点击位置是否有效,确定点击位置与按钮的关系。
数据传入即为确定按钮后,将相应的6或9或11载入行列统计变量ROWANDCOLUMN中。
(2)难度的选择
在该模块中,需要决定面板种雷的个数,面板中应包含多少的地雷。
在设计时,个人决定使用10%,20%和30%的总格子数作为雷的总个数。
设计中,个人决定设置3个按钮分别作为3种面板的选择。
在具体实现时,需要从两方面进行考虑,即:
位置确定和数据传入。
位置确定即为确定点击位置是否有效,确定点击位置与按钮的关系。
数据传入即为确定按钮后,将相应的雷数载入变量MINENUM中。
(3)游戏主界面
游戏主界面的设计可以包含图形的绘制模块,鼠标区域的获取模块,数据的生成模块。
各部分包含的内容如下:
a)图形的绘制
1基础线条的绘制
2单个地雷的绘制
3非雷区域的数字输出
4游戏结束后所有雷和数字的结果输出
b)鼠标区域的获取
1有效性判断
2获取鼠标区域将坐标转换为可以使用的相应的数组数据
c)数据的生成
1初始化数据
2随机位置设置雷
3非雷区域计算相应数值
2.2流程图
2.2.1总体流程图
函数的主流程图如图2-2。
在该流程图中,介绍了游戏的三个界面的切换情况,三者为依次展示的状态,完成前一步骤后方可进入下一界面。
图2-2程序的总流程图
2.2.2面板的选择的流程图
面板的选择流程图如图2-3。
在该流程图中,介绍了面板大小选择的流程,主要的部分为界面的绘制过程,鼠标点击区域的判断,以及相应数值的赋值。
该过程是扫雷游戏的第一个界面。
该流程的目的是为了传入相应的参数,使得在游戏主界面时,能够初始化相应数组以及绘制对应的界面。
图2-3面板选择的流程图
2.2.3难度的选择的流程图
难度的选择流程图如图2-4。
在该流程图中,介绍了游戏难度的选择流程,主要的部分为界面的绘制过程,鼠标点击区域的判断,以及相应数值的赋值。
该过程是扫雷游戏的第二个界面。
过程类似于面板选择的流程。
该流程的目的是为了传入相应的参数,使得在游戏主界面时,能够初始化相应数组以及绘制对应的界面。
图2-4难度选择的流程图
2.2.4游戏主界面的流程图
游戏主界面的流程图如图2-5。
在该流程图中,主要的操作为绘制相应的主界面面板,即多个格子。
获取鼠标点击的位置,而后进行储存数据的判断,雷区与非雷区的判断,游戏是否结束的判断等等操作,相应的过程如下所示。
图2-5游戏主界面的流程图
第3章编码与测试
3.
3.1程序编码
程序的编码部分可以分为四各模块,即:
主函数的程序部分,面板大小选择部分,难度选择部分,游戏主界面部分,每个部分内均可以分类编写,互不干扰,以下为代码的主要部分,详细代码由于篇幅的限制,可以在附录中查阅。
3.1.1主函数程序代码
#include
#include"BoardChoice.h"
#include"LevelChoice.h"
#include"Game.h"
intROWANDCOLUMN;//行列数
intMINENUM;//雷数
intCHESSSIZE;//格子大小
intmain()
{
BoardChoiceb1;//面板一
b1.main();
LevelChoiceb2;//面板二
b2.main();
Gameb3;//面板三
b3.main();
return0;
}
3.1.2面板选择的类声明及主要代码
1.BoardChoice类的声明
classBoardChoice
{
public:
voidmain();//面板控制
private:
voidDrawBoard();//主界面绘制
voidChoiceClick();//鼠标输入
};
2.主要代码
//主界面绘制
voidBoardChoice:
:
DrawBoard()
{
setcaption("扫雷游戏");
setbkcolor(WHITE);
setcolor(BLACK);
setfont(25,0,"宋体",0);
outtextxy(150,30,"面板选择");
rectangle(100,80,300,130);
rectangle(100,180,300,230);
rectangle(100,280,300,330);
outtextxy(169,93,"6*6");
outtextxy(169,193,"9*9");
outtextxy(156,293,"11*11");
}
//鼠标输入
voidBoardChoice:
:
ChoiceClick()
{
while(true)
{
mouse_msgm;
m=getmouse();
if(m.is_down()&&m.x>100&&m.x<300)
{
//判断鼠标所处坐标
if(m.y>80&&m.y<130)//6*6
{
ROWANDCOLUMN=6;
CHESSSIZE=60;
break;
}
if(m.y>180&&m.y<230)//9*9
{
ROWANDCOLUMN=9;
CHESSSIZE=50;
break;
}
if(m.y>280&&m.y<330)//9*9
{
ROWANDCOLUMN=11;
CHESSSIZE=45;
break;
}
}
}
}
3.1.3难度选择的类声明及主要代码
1.LevelChoice类的声明
classLevelChoice
{
public:
voidmain();//面板控制
private:
voidDrawBoard();//主界面绘制
voidChoiceClick();//鼠标输入
};
2.主要代码
//面板控制
voidLevelChoice:
:
main()
{
initgraph(400,400);
DrawBoard();
ChoiceClick();
closegraph();
}
voidLevelChoice:
:
ChoiceClick()
{
while(true)
{
mouse_msgm;
m=getmouse();
if(m.is_down()&&m.x>100&&m.x<300)
{
//判断鼠标所处坐标
if(m.y>80&&m.y<130)//10%的雷
{
MINENUM=ROWANDCOLUMN*ROWANDCOLUMN*0.1;
break;
}
if(m.y>180&&m.y<230)//20%的雷
{
MINENUM=ROWANDCOLUMN*ROWANDCOLUMN*0.15;
break;
}
if(m.y>280&&m.y<330)//30%的雷
{
MINENUM=ROWANDCOLUMN*ROWANDCOLUMN*0.2;
break;
}
}
}
}
3.1.4游戏主界面的类声明及主要代码
1.Game类的声明
classGame
{
public:
voidmain();//面板控制
private:
voidDrawBoard();//主界面绘制
boolChoiceClick();//鼠标输入
voidDataInital();//数据初始化
private:
voidDrawMine(intx,inty);//画一个雷
voidDrawNum(intx,inty,intnum);//画一个数字
voidPrintWhole();//游戏结束打印所有位置
boolDrawClickArea(intx,inty);//绘制所处位置返回true继续
//数组计算
private:
voidRandMine();//数组随机布雷
intCalculateMineNum(intx,inty);//计算指定位置周边雷个数
voidSetMineNum();//数组赋值周边雷个数
//数据
private:
intstatus[11][11];//每个状态
boolopenStatus[11][11];//是否点击
intcount;//计数器:
未按且不是雷
};
2.主要代码
//随机布雷
voidGame:
:
RandMine()
{
intn=MINENUM;
while(n!
=0)
{
inti=random(ROWANDCOLUMN);
intj=random(ROWANDCOLUMN);
if(status[i][j]==0)//若无雷则变雷
{
status[i][j]=-1;
n--;
}
}
}
//计算周边雷个数
intGame:
:
CalculateMineNum(intx,inty)
{
intnum=0;
if(x-1>=0&&y-1>=0&&status[x-1][y-1]==-1)num++;
if(x-1>=0&&status[x-1][y]==-1)num++;
if(x-1>=0&&y+1 if(y-1>=0&&status[x][y-1]==-1)num++; if(y+1 if(x+1 if(x+1 if(x+1 returnnum; } //设置非雷区的周边雷统计值 voidGame: : SetMineNum() { for(inti=0;i { for(intj=0;j { if(status[i][j]! =-1) { status[i][j]=CalculateMineNum(i,j); } } } } 3.2测试结果 本次课程设计中要求需要进行系统功能性测试,并且验证基本功能实现情况。 同时需要进行边界测试及特殊数据用例测试,验证功能模块的逻辑分支流程。 针对这些要求,我做了以下的测试。 3.2.1界面一: 面板选择的相关测试 针对面板一需要进行的测试为鼠标的相关测试。 面板一可以划分为以下四个区域: 空白的无效区域,按钮一6*6区域,按钮二9*9区域,按钮三11*11区域。 首先测试的是空白的无效区域,运行程序后,经过多次的鼠标点击空白的无效区域,可以从实际使用中发现,并没有任何效果。 而后测试三个按钮区域。 在调试过程中,可以发现三个区域判断无误,并且从变量区中,可以看到决定面板大小的变量ROWANDCOLUMN传值正确,说明界面一的功能无误。 图3.1即为面板选择界面的图示。 图3-1面板选择界面的运行图 3.2.2界面二: 难度选择的相关测试 针对面板二同样需要测试鼠标的相关点击。 具体区域可以划分以下四个: 空白的无效区域,按钮一6*6区域,按钮二9*9区域,按钮三11*11区域。 首先测试的是空白的无效区域,运行程序后,经过多次的鼠标点击空白的无效区域,在调试过程中可以发现,鼠标位置的传入正确,数值参数无误。 而后测试三个按钮区域。 在调试过程中,同样可以发现三个区域判断无误,并且从变量区中,可以看到决定雷数的百分比根据10%,20%,30%的比例设置正确,决定雷数的变量MINENUM计算值正确,说明界面二的功能和数值无误。 图3-2即为难度选择界面的图示。 图3-2难度选择界面的运行图 3.2.3界面三: 主界面的相关测试 在界面三中具体需要测试的内容有: (1)面板的绘制是否与预期相符。 (2)雷的布置是否正确以及非雷区域的周边雷数计算是否正确。 (3)鼠标点击的相关测试。 (4)游戏是否结束的判断及游戏结束后的真实界面公示。 首先需要测试面板的绘制是否与预期相符,这需要查看数值的传入对于面板的大小的影响,因而通过多次使用界面一和界面二来初步观察界面的格子数字是否与预期相符。 图3-3至图3-5为不同选择下面板的格子数与格子大小的变化。 图3-3界面为6*6的运行初始主界面图 图3-4界面为9*9的运行初始主界面图 图3-5界面为11*11的运行初始主界面图 其次雷的布置以及非雷区域的周边雷数计算是否正确。 以下为6*6以及适中难度下的测试。 在调试过程中,图3-6为观察变量区域status的初始状态,初始状态时各变量均为0,与预期相符。 图3-7为设置雷以及非雷区域的计算结果,各变量经过检验,均与预期吻合,测试结果正确。 图3-6面板6*6适中难度的初始雷区数组图 图3-7面板6*6适中难度的布雷后数组变量变化图 鼠标点击的相关测试中需要确认的有: 未点击的位置进行点击是否会正确显示雷或数字;无效区域点击是否会产生未知效果。 在实际检测中,在点击空白空格后能够正常显示数字,若点击范围为雷区,则正确显示雷。 在点击无效区域时,棋盘没有任何其他效果。 在调试中,数值的传入传出与预期均相符。 鼠标点击的结果,如图3-8所示。 图3-8界面为6*6简单模式的游戏过程图 游戏是否结束的判断及面板公示测试过程中,需要从两方面考虑即: 鼠标点击至雷区,游戏失败结束,并且打印失败的信息;所有非雷区都被点开,游戏胜利,打印获胜信息。 因此从这两方面单独对编写的程序进行测试。 图3-9为6*6面板大小简单难度下的游戏失败时的测试结果,该结果是用于测试点击至雷区后是否游戏真正结束。 在失败后,正确打印了失败的提示字符,并且此时鼠标点击任意位置均无效。 图3-10为游戏失败后的棋盘公示画面。 图3.11和图3-12为6*6面板大小简单难度下的游戏胜利的测试结果。 图3-11是在游戏过程中显示各数字区域的画面,图3.12为游戏胜利之后提示的游戏胜利的画面。 图3-13为游戏胜利后的棋盘公示画面。 以上测试说明游戏结束的判断及面板公示正确。 图3-9界面为6*6简单模式的游戏失败图 图3-10界面为6*6简单模式的游戏结果公示图 图3-11界面为6*6简单模式的游戏过程图 图3-12界面为6*6简单模式的游戏胜利图 图3-13界面为6*6简单模式的游戏结果公示图 第4章总结与分析 4. 在本次实验过程中,遇到的最大的问题是扫雷界面的制作以及对雷区和非雷区的布置和计算,即图形的绘制以及实际数据的生成及匹配。 在处理图形问题的时候我选择了使用EasyGraphicsEngine的图形库,利用里面的函数来绘制图形,具体操作时使用rectangle函数画矩形,利用line函数绘制相关格子的线条,并使用鼠标的相关函数,来获取鼠标点击的坐标点,从而且确定范围的有效性。 在处理数据以及相关问题时,我的解决方案是,利用两组二维数组来表示所有的格子。 第一组二维数组status用于存放与雷相关的数据,若为雷区,则对应数组的位置为-1,其余位置利用自定义的相关函数计算并存放周围8个区域所存放的雷的个数。 第二个二维数组openStatus用于存放鼠标是否点击的信息,若点击则置1,未点击则为0。 该数组的作用是,若点击前位置已被点击一次,则不展示数组数据,且点击无效;若点击前未曾点击,则展示数组数据,并将openStatus的相应位置置1表示为已点击。 通过上述的几个构思之后,我解决了扫雷小程序设计的大部分问题,在后续的实现中也更好的解决了相关的问题,完成了项目设计的目标。 此次实验中,我收获了很多。 从程序设计方面来说,首先需要需求分析,再进行总体的规划,而后是局部的设计,最终再到代码实现,逐层递进的方式,能够将问题解决的较为简便。 同时我也学到了模块化的思想,在具体完成设计的过程中,首先将各个界面相互独立,使用对应的类进行封装,并分开编写图形界面与数据的实现。 模块化的思想能将功能局部分解,简单实现。 最后还懂得了独立测试程序的方式,在测试程序时,需要考虑全面,不仅需要进行正确的测试,更要考虑到各种极端的情况,减少一些不易察觉的错误。 参考文献 1.EGE图形库主站EasyGraphicsEngine.http: //www.xege.org,2018. 2.EGE文档与源代码.http: //xege.org/ege-open-source,2018. 3.EGE(EasyGraphicsEngine)15.04.http: //xege.org/manual,2018. 4.EasyGraphicsEngine基础教程.http: //xege.org/category/lesson,2018. 5.谭浩强.C++程序设计(第3版).北京: 清华大学出版社,2015. 6.严蔚敏,李冬梅,吴伟民.数据结构(C语言版第2版).北京: 人民邮电出版社,2015. 7.王红梅,胡明,王涛.数据结构(C++版).北京: 清华大学出版社,2011. 8.严蔚敏,陈文博.数据结构及应用算法教程(修订版),北京: 清华大学出版社,2011. 9.严蔚敏,陈文博.数据结构及应用算法教程(修订版),北京: 清华大学出版社,2011. 10.Decoder.C/C++程序设计.北京: 中国铁道出版社,2002. 11.谭浩强.C++面向对象程序设计(第2版).北京: 清华大学出版社,2014. 12. 附录 1.必选题题目 使用折半插入排序的方法对10个数进行排序,按照要求画流程图,给出代码及结果截图。 2.流程图 图附-1排序算法流程图 3.程序代码 #include usingnamespacestd; voidBInsertSort(int*arr,intlength) { for(inti=1;i { inttemp=arr[i];//需要插入的值存放入temp intlow=0; inthigh=i-1; while(low<=high) { intmid=(low+high)/2; if(temp high=mid-1; else low=mid+1; } for(intj=i-1;j>=high+1;j--)//记录后移 arr[j+1]=arr[j]; arr[high+1]=temp;//插入正确位置 } } intmain() { //输入数据 cout<<"请输入需要排序的十个数字"< int*arr=newint[10];//十个数字 for(inti=0;i<10;i++) cin>>arr[i]; cout< //折半排序 BInsertSort(arr,10); //输出结果 cout<<"排序结果"< for(inti=0;i<10;i++) cout< cout< return0; } 4.测试结果 实验测试输入了多组数据,在测试结果该模块中展示的为三个具有代表性的程序结果截图。 图6-2为顺序输入10个数据后的测试结果,在控制台中输入了1-10十个数字的顺序序列,即12345678910,在折半插入排序之后,正常显示从小到大的10个数字序列,排序结果与预期相符,结果正确。 图附-2顺序输入10个数字的测试结果 图6-3为逆序输入10个数据后
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 扫雷 程序设计