扫雷游戏Word文档下载推荐.docx
《扫雷游戏Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《扫雷游戏Word文档下载推荐.docx(18页珍藏版)》请在冰豆网上搜索。
![扫雷游戏Word文档下载推荐.docx](https://file1.bdocx.com/fileroot1/2022-12/10/ebfa99ca-5b44-4568-91c5-8effa5f78bdc/ebfa99ca-5b44-4568-91c5-8effa5f78bdc1.gif)
1.4课程设计要求1
第2章课程设计内容2
2.1程序功能介绍2
2.2程序整体设计说明2
2.2.1设计思路2
2.2.2数据结构设计及用法说明3
2.2.3程序结构(流程图)4
2.2.4各模块的功能及程序说明4
2.2.5程序结果5
2.3程序源代码及注释5
第3章课程设计总结17
参考资料18
第1章课程设计的目的与要求
1.1课程设计目的
本课程设计是计算机科学与技术专业重要的实践性环节之一,是在学生学习完《程序设计语言(C)》课程后进行的一次全面的综合练习。
本课程设计的目的和任务:
1.巩固和加深学生对C语言课程的基本知识的理解和掌握
2.掌握C语言编程和程序调试的基本技能
3.利用C语言进行基本的软件设计
4.掌握书写程序设计说明文档的能力
5.提高运用C语言解决实际问题的能力
1.2课程设计的实验环境
硬件要求能运行Windows2000/XP操作系统的微机系统。
C语言程序设计及相应的开发环境。
1.3课程设计的预备知识
熟悉C语言及C语言开发工具。
1.4课程设计要求
1.分析课程设计题目的要求
2.写出详细设计说明
3.编写程序代码,调试程序使其能正确运行
4.设计完成的软件要便于操作和使用
5.设计完成后提交课程设计报告
第2章课程设计内容
2.1程序功能介绍
我们已经分析出扫雷游戏的目标和主要的功能,即根据输入的信息,执行相应的诸挖雷、标记雷、标记疑问、自动挖开等功能,以期在尽快的时间内标识出开局时所埋的所地雷。
但是,这仅仅是程序层次结构中最上层的部分,划分的功能比较抽象,需要进一步的精化;
与系统实现的其它相关细节还是空白,需要进一步完善,从而最后的实现
2.2程序整体设计说明
扫雷游戏的输赢规则为挖开一个含有雷的方块,游戏失败;
正确的标记出所有含有雷的方块,游戏胜利。
我们已经分析出扫雷游戏的目标和主要的功能,即根据输入的信息,执行相应的诸如挖雷、标记雷、标记疑问、自动挖开等功能,以期在尽快的时间内标识出开局时所埋设的所有地雷。
但是,这仅仅是程序层次结构中最上层的部分(如图2-7所示):
划分的功能比较抽象,需要进一步的精化;
与系统实现的其它相关细节还是空白,需要一步完善,从而逐渐逼近最后的实现。
2.2.1设计思路
游戏过程中始终维护两张地图。
map[10][10]是游戏本身的地图,usermap[10][10]是用户可见的地图。
map[10][10]中每个格子的取值均有0~8和15这几种情况。
15表示此处有雷,0~8的意义见游戏规则中说明。
usermap[10][10]中的取值除了有上述几种情况外,还有9,表示此处尚未被探测到。
游戏开始时map[10][10]中已有初始化的地图,而usermap[10][10]中所有取值均为9。
在游戏过程中,map[10][10]中的值始终不变,而usermap[10][10]则根据玩家操作,将相应的元素更新为map[10][10]中对应元素的值。
算法主要包括两个部分:
一是根据玩家的操作更新usermap[10][10]中的元素值;
二是根据usermap[10][10]中各元素的值来绘制用于屏幕显示的数组中各像素点的值。
下面按照模块中的几个主要进程来介绍算法的具体结构。
(1)响应键盘输入进程:
敏感信号为enclk=en&
clk。
首先将刷新标志变量refresh置为0。
用curi和curj两个变量来表示当前光标在地图中的坐标。
判断输入的键盘扫描码的内容。
若为方向控制,则控制光标移动。
若为回车确定,则置refresh为1。
(2)更新显示索引进程敏感信号为refresh的上升沿。
因此这个进程会在接收到回车确定扫描码之后被激发。
索引的含义如下所述。
虽然usermap对应的矩阵为10*10,但在屏幕上显示时显然不能只用一个像素来显示usermap中的一个元素。
这里用10*10的像素块来显示usermap中一个元素,称此像素块为一个宏块。
根据usermap中元素的取值,每个宏块中要显示的内容有以下可能:
取值为0~8,宏块中显示对应的数字;
取值为15,宏块中显示雷。
而对于其中的数字和雷,采用七段数码管的方式显示。
也就是对每一个宏块均有一个7个元素的索引数组来表示其中的显示内容。
当然,由于usermap中元素的取值只可能在curi和curj指示的位置发生改变,所以只用一个索引数组来指示当前宏块的显示情况即可,不需要为每个宏块都建立独立的索引数组。
设这个数组为lighted[6:
0]。
lighted中每个元素对应七段数码管中的一段。
在这个进程中就根据usermap中当前元素的取值来更新lighted中的元素取值。
lignted中某元素为0则表示该段数码管为暗,为1则表示该段数码管为亮。
对于0~8的数字,与七段数码管的对应关系就如一般情况;
对于雷,用只亮起最上端的一横来表示。
在此进程中通过curi和curj以及usermap中当前元素的取值来设置lighted中各元素的取值。
(3)更新显示矩阵进程敏感信号为lighted。
只有玩家在一个尚未探测的地方按下了回车时,才需要更新屏幕显示情况,而这种操作下lighted是必然会改变的,所以用lighted做敏感信号没有问题。
虽然在移动光标过程中由于当前位置的指向发生了变化,lighted也有可能发生改变,但此时usermap不会发生改变,于是就相当于根据usermap中对应元素的值将该宏块重绘一次,不会有任何问题。
所谓更新显示矩阵,即根据curi和curj找到在显示矩阵中当前宏块的位置,然后跟lighted中7个元素的取值来控制宏块中与七段数码管位置对应的像素点的明暗情况,这样就可以用来进行显示。
可以看出,由于lighted中每个元素只有0和1两种取值,所以在显示矩阵中每个像素也只有0和1两种取值,在显示时分别将它们映射为背景色和前景色。
背景色用来表示背景,包括未探测到的地图和已探测到地图的背景部分。
前景色用来显示数字和雷。
在此进程中通过curi和curj以及lighted的取值确定了显示矩阵screen中各像素点的取值,就可以用来输出给VGA进行显示了。
这样就实现从接收键盘输入到生成屏幕显示的整个过程。
至于dead信号,就判断usermap中当前元素是否为15即可。
其他解决的问题还有显示当前光标所在位置,和显示不同宏块之间的边界等。
2.2.2数据结构设计及用法说明
做一个NxM的扫雷游戏,每个方格包含两种状态:
关闭(closed)和打开(opened),初始化时每个方格都是关闭的,一个打开的方格也会包含两种状态:
一个数字(clue)和一个雷(bomb)。
你可以打开(open)一个方格,如果你打开的是一个bomb,那么就失败;
否则就会打开一个数字,该数字是位于[0,8]的一个整数,该数字表示其所有邻居方格(neighboringsquares)所包含的雷数。
1.能够打开一个方格,一个已打开的方格不能再关闭。
2.能够标记一个方格,标记方格的含义是对该方格有雷的预测(并不表示真的一定有雷),当一个方格标记后该方格不能被打开,只能执行取消标记的操作,只能在取消后才能打开一个方格。
3.能够给出游戏结果(输、赢、剩余的雷数、用掉的时间按秒计)。
2.2.3程序结构(流程图)
2.2.4各模块的功能及程序说明
这一模块是扫雷游戏的具体算法。
实现从接收键盘输入到生成屏幕显示的整个中间过程。
本部分共一个模块,modulesbomb(clk,en,control,dead),各输入输出说明如下。
clk
同步时钟信号。
en
使能信号,从0到1的一个跳变指示游戏开始。
control
输入的键盘扫描码,有上(75H)下(72H)左(6BH)右(74H)回车(5AH)五种情况。
上下左右表示方向移动,回车表示探测地图。
dead
是否踩到雷,游戏结束。
踩到雷则值为1,否则为0。
2.2.5程序结果
2.3程序源代码及注释
#include"
graphics.h"
#include<
stdlib.h>
string.h>
stdio.h>
bios.h>
#defineENTER0x1c0d
#defineLEFT0x4b00
#defineRIGHT0x4d00
/*c语言扫雷代码*/
#defineESC0x011b
#defineSPACE0x3920
#defineLOWERF0x2166
#defineUPPERF0x2146
#defineLOWERA0x1e61
#defineUPPERA0x1e41
#defineLOWERQ0x1071
#defineUPPERQ0x1051
#defineROW16
#defineCOL16
#defineSTARTX50
#defineSTARTY50
#defineSIZEX20
#defineSIZEY20
#defineUNFLAG0/*blocknotflaged*/
#defineFLAGED1/*blockthatisflagedtobehavemine*/
#defineOPEN40/*ablockwhichischeckedtohavenomine*/
inttable[ROW][COL];
intnum[ROW][COL];
intflag[ROW][COL];
intpi,pj;
intdi[8]={-1,-1,0,1,1,1,0,-1};
intdj[8]={0,1,1,1,0,-1,-1,-1};
intstop=0;
intgetKey(void){
while
(1){
intkey=bioskey(0);
switch(key){
caseENTER:
caseUP:
caseDOWN:
caseLEFT:
caseRIGHT:
caseESC:
caseSPACE:
caseLOWERF:
caseUPPERF:
caseLOWERA:
caseUPPERA:
caseLOWERQ:
caseUPPERQ:
returnkey;
}
voidDrawHead()
{
setcolor(6);
rectangle(10,10,400,400);
rectangle(15,15,395,395);
setcolor(7);
outtextxy(410,30,"
WelcometoMinegame!
"
);
outtextxy(410,70,"
ressarrowkeytomoved!
outtextxy(410,85,"
F(f)--->
flagmine"
outtextxy(410,100,"
Q(q)--->
flagquestion"
outtextxy(410,115,"
ENTER--->
Open"
outtextxy(410,130,"
A(a)--->
autoOpen"
outtextxy(410,145,"
ressESCtoquitthegame!
outtextxy(410,365,"
Modibyxiao2006/08/06"
setcolor
(2);
outtextxy(160,30,"
Mine"
voidinitGraph(){
/*requestautodetection*/
intgdriver=DETECT,gmode,errorcode;
registerbgidriver(EG***GA_driver);
/*initializegraphicsmode*/
initgraph(&
gdriver,&
gmode,"
/*readresultofinitialization*/
errorcode=graphresult();
if(errorcode!
=grOk)
printf("
Graphicserror:
%s\n"
grapherrormsg(errorcode));
ressanykeytohalt:
getch();
exit
(1);
/*returnwitherrorcode*/
voidgenerateMine(){
inttotalMine;
inti,k;
intri,rj;
intni,nj;
staticintseed=0;
totalMine=ROW*COL/6;
memset(table,0,sizeof(table));
memset(num,0,sizeof(num));
srand(seed++);
for(i=0;
i<
totalMine;
i++){
do{
ri=rand()%ROW;
rj=rand()%COL;
}while(table[ri][rj]);
for(k=0;
k<
8;
k++){
ni=ri+di[k];
nj=rj+dj[k];
if(ni>
=0&
&
ni<
ROW&
nj>
nj<
COL)num[ni][nj]++;
table[ri][rj]=1;
memset(flag,UNFLAG,sizeof(flag));
voiddrawBlock(inti,intj){
intx,y,xx,yy;
intcolor;
intmx,my;
x=STARTX+j*SIZEX;
y=STARTY+i*SIZEY;
xx=x+SIZEX-1;
yy=y+SIZEY-1;
color=(flag[j]==OPEN||flag[j]==EXPLOD)?
DARKGRAYIGHTGRAY;
setcolor(WHITE);
rectangle(x,y,xx,yy);
setfillstyle(SOLID_FILL,color);
floodfill(x+1,y+1,WHITE);
line(x,y,xx,y);
line(x,y,x,yy);
setcolor(***ACK);
line(xx,y,xx,yy);
line(x,yy,xx,yy);
if(pi==i&
pj==j){
setcolor(RED);
rectangle(x+1,y+1,xx-1,yy-1);
mx=x+5;
my=y+5;
setcolor(***UE);
switch(flag[j]){
caseUNFLAG:
outtextxy(mx,my,"
"
break;
caseFLAGED:
F"
caseQUESTION:
?
caseEXPLOD:
*"
caseOPEN:
if(num[j]>
=1&
num[j]<
=8){
charbuf[3];
itoa(num[j],buf,10);
outtextxy(mx,my,buf);
voiddrawTable(){
inti,j;
ROW;
i++)
for(j=0;
j<
COL;
j++)drawBlock(i,j);
voidnewGame(){
cleardevice();
DrawHead();
generateMine();
pi=pj=0;
drawTable();
intcheckWin(){
j++){
if(table[j]==0&
flag[j]!
=OPEN)return0;
stop=1;
return1;
intconfirm(intres){
charbuffer[100];
intkk;
if(res==1){
strcpy(buffer,"
Youwinthegame,playagain(Y/N)?
elseif(res==-1){
Youlosethegame,playagain(Y/N)?
else{
Exitgame,playagain(Y/N)?
outtextxy(0,0,buffer);
kk=bioskey(0);
kk=(kk&
0xff);
if(kk=='
Y'
||kk=='
y'
)return0;
voidmoveUp(){
if(pj>
0){
pj--;
drawBlock(pi,pj);
drawBlock(pi,pj+1);
voidmoveDown(){
if(pj<
ROW-1){
pj++;
drawBlock(pi,pj-1);
voidmoveLeft(){
if(pi>
pi--;
drawBlock(pi+1,pj);
voidmoveRight(){
COL){
pi++;
drawBlock(pi-1,pj);
voidflagBlock(inti,intj){
if(flag[j]==FLAGED){
flag[j]=UNFLAG;
elseif(flag[j]==UNFLAG){
flag[j]=FLAGED;
drawBlock(i,j);
voidquestBlock(inti,intj){
if(flag[j]==QUESTION){
if(flag[j]==UNFLAG)flag[j]=QUESTION;
intopenMine(inti,intj){
intii,jj,k;
if(flag[j]==OPEN)return0;
if(table[j]){/*meetamine*/
for(ii=0;
ii<
ii++){
for(jj=0;
jj<
jj++){
if(table[ii][jj]&
flag[ii][jj]==UNFLAG){
flag[ii][jj]=EXPLOD;
drawBlock(ii,jj);
return-1;
/*losethegame*/
else{
flag[j]=OPEN;
if(num[j]==0){
intni=i+di[k];
intnj=j+dj[k];
COL)
openMine(ni,nj);
return0;
intautoOpen(inti,intj){
intk,c=0;
intret=0;
if(!
(flag[j]==OPEN))return0;
ni=i+di[k];
nj=j+dj[k];
if(flag[ni][nj]==FLAGED)c++;
if(c==num[j]){
if(flag[ni][nj]==UNFLAG){
if(openMine(ni,nj)==-1)ret=-1;
returnret;
intmain(){
intgameRes;
initGraph();
begin:
newGame();
gameRes=0;
/*mainloopdealingwithkeystrokemessages*/
intkey=getKey();
if(key==ESC)break;
caseSPACE:
gameRes=openMine(pi,pj);
moveUp();
moveDown();
cas