简易版扫雷游戏实验报告
一、 问题描述
模仿 windows 扫雷游戏,开发一个简易版扫雷游戏系统。
二、功能分析
总体游戏过程分析:在屏幕中央位置显示一个雷区,雷区范围内
预先埋设了一定数量的随机分布的地雷;玩家通过上下左右键控制光
标在雷区的各个小方块之间移动并做标记;若能正确标记出雷区中的
所有地雷,则游戏胜利;否则踩雷,游戏失败。
简易版扫雷游戏要具备以下功能:
1) 开局:首先选择游戏等级,然后生成不同等级的雷区界面。
游戏等级分为三级:各等级方块数为——初级:8×8、中级:
16×16、高级:24×24;各级地雷数=总方块数/6;雷区每个
方块下面或埋藏有 1 个地雷,或者没有地雷;
2) 挖雷:将光标移到某个方块,并按空格或回车键,可挖开它;
若所揭方块下有雷,则踩雷,此时所有含地雷的块都标记,
该局游戏失败;如果方块上出现数字,它代表在它周围的 8
个方块中共有多少颗地雷;
3) 标记地雷:在光标所在的某个方块上按 F 或 f 键,则标记此
块下埋着地雷(实际上可能是误标),显示为 F。每标记一个
地雷,地雷数减少 1;
4) 标记疑问:在光标所在的某个方块上按 Q 或 q 键,则在某方
块上面标一个问号(?),意味着没有把握判定它是否有雷。标
记为?的块可在恰当的时候再按标记地雷或挖开;
5) 自动挖开:如果某个数字方块周围的地雷全都标记完,则在
该方块上按 A 或 a 键,将其剩下的方块挖开;
6) 输入:通过键盘输入相关指示信息;
7) 输出:提示游戏是否成功,是否继续。
三、程序设计
扫雷游戏系统的顶层层次图如下:
扫雷游戏(主框架)
开局
输入
输出
挖雷
标记雷
标记疑问
自动挖开
图 1 扫雷系统的顶层层次图
从以下几方面“自顶向下”进一步逐步求精:
继续分析已有功能,直到精化出所有子功能,确定模块间接口;
描述精化后每个模块的处理过程;
确定主要的数据及其数据结构;
确定输入输出数据的内外部形式;
界面的设计
以下是详细设计:
(1)确定游戏的界面。游戏屏幕中央显示由小方块组成的雷区,小
方块的背景显示为浅灰,表示该方块没有被挖开或标记;小方块的背
图 2 扫雷游戏的界面
景显示为深灰,表示它已经被挖开或标记为“F”、“?”或“*”;当
选中一个方块要操作时,它的边框线为红色。在屏幕的左上方显示游
戏是否成功等信息,这也是游戏结果的表现形式。如图 2 所示。
(2)决定游戏的输入方式。采用键盘,通过光标的移动来选择操作
的小方块,根据所敲击的键值来选择游戏的功能。
下面是对键盘功能键的定义:
上,下,左,右键用来移动光标的位置;
回车或者空格键用来挖开光标当前指向的一个方块;
F, f 标记当前光标指向的方块有地雷;
Q, q 在光标指向方块打一个问号,表示可能有地雷;
A , a 自动挖开光标周围的方块;
ESC 退出游戏。
(3)确定主要的数据,这里主要是有关雷区的数据。
雷区界面数据
int MAXCOL=640;
/*屏幕最大宽度*/
int MAXROW=480;
/*屏幕最大高度*/
#define _ROW 24
/*雷区最多方块行数*/
#define _COL 24
/*雷区最多方块列数*/
int ROW=8;
int COL=8;
/*当前游戏雷区行数*/
/*当前游戏雷区列数*/
#define SIZEX 20
/*雷区方块的水平大小(像素数)*/
#define SIZEY 20
/*雷区方块的垂直大小(像素数)*/
#define STARTX (MAXCOL-COL*SIZEX)/2
/*水平起始位置
*/
#define STARTY (MAXROW-ROW*SIZEY)/2 /*垂直起始位置
*/
雷区内部数据
int totalMine;
/* 整个雷区所含的地雷总数*/
int table[_ROW][_COL];
/* 数组 table 的每个元素值记录
了雷区对应方块是否有雷:1 表示有雷,0 表示没有雷*/
int num[_ROW][_COL];
/* 数组 num 的每个元素值记录了雷区对应方块周围有多少个地雷*/
int flag[_ROW][_COL];
/* 数组 flag 的每个元素值记录了雷区对应方块当前的状态*/
在 整 个 系 统 中 table[_ROW][_COL] 、 num[_ROW][_COL] 、
flag[_ROW][_COL]是最核心的数据,是雷区的内部表示,游戏的挖雷、
标记雷、标记疑问、自动挖开等界面操作,在内部实际上是对这些数
据的操作。
方块(i,j)的状态取值:
#define UNFLAG 0 /* 表示该方块还没有被打开或者标记*/
#define FLAGED 1 /* 标记该方块有地雷*/
#define QUESTION 20 /* 表示该方块可能有地雷*/
#define EXPLOD 30
/* 踩到地雷爆炸了*/
#define OPEN 40
/* 一个没有地雷的方块被打开*/
光标当前位置数据
int pi,pj; /* 记录光标的当前位置,初始时光标在(0,0)上*/
int di[8]={-1,-1,0,1,1,1,0,-1};
/*x 方向偏移量*/
int dj[8]={0,1,1,1,0,-1,-1,-1}; /*y 方向偏移量*/
游戏状态数据
int gameRes;
/*记录游戏结束的结果状态,值为 0 表示按 esc 键退出游戏;-1 表示
游戏失败;gameRes = 1 表示游戏胜利。实际为输出数据的内部形
式*/
功能键的键值
/*为避免书写错误和明确含义,对系统的按键值用符号常量来定义*/
0x4800
0x5000
0x4b00
0x4d00
/*上,下,左,右键*/
#define UP
#define DOWN
#define LEFT
#define RIGHT
/*回车、空格键*/
#define ENTER 0x1c0d
#define SPACE 0x3920
/*F, f */
#define UPPERF 0x2146
#define LOWERF 0x2166
/*Q, q*/
#define UPPERQ 0x1051
#define LOWERQ 0x1071
/*A , a*/
#define UPPERA 0x1e41
#define LOWERA 0x1e61
/*ESC*/
#define ESC 0x011b
(4)功能模块进一步求精
在 C 系统中屏幕的输出默认的方式是文本方式,所以需要首先
将显示方式设置为图形方式。简易版扫雷程序主控模块的流程如图 3
所示,下面从主控模块入手,继续利用逐步求精的方法来设计系统。
开始
图形方式初始化
初始化新游戏
从键盘读入键值
是 ESC?
F
对其他键值进行判断处理
F
本次游戏结束
T
重新游戏?
F
关闭游戏,结束
图 3 扫雷游戏的主控模块流程
T
T
第一步,写出主程序的基本框架,确定各子模块名字和参数。
int main()
{
/*图形显示方式初始化*/
/*初始化新游戏,即开局*/
initGraph();
do {
newGame();
int gameRes=0;
do {
int key = getKey();
if (key == ESC)
/*读入操作信息*/
{gameRes = 0;break;}
switch(key){
对其他 key 值进行判断处理;
/*判断游戏是否胜利*/
}
if (checkWin())
gameRes = 1;
}while(!gameRes);
}while (!confirm(gameRes));
return 0;
}
主控模块的各子模块说明:
void initGraph()函数:用于将显示器显示方式设置为图形方
式。
void newGame()函数:开局—初始化新游戏界面及数据。
int getKey()函数:得到从键盘读入的操作信息。
int checkWin()函数:用于判断游戏是否获胜。若返回值为 1
表示胜利,返回值为 0 表示游戏还没结束。
int confirm(int) 函数:用于判断游戏是否重新开始。参数的
值 来 自 gameRes ,gameRes=0 , 表 示 按 esc 键 退 出 游 戏 ;
gameRes = -1,表示踩到地雷,游戏失败;gameRes = 1,表