C语言中如何实现扫雷小游戏

这篇文章给大家分享的是有关C语言中如何实现扫雷小游戏的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

游戏简介

扫雷,是一款益智类小游戏。 游戏目标是找出所有没有地雷的方格,完成游戏;要是按了有地雷的方格,游戏失败;玩家可标记雷的位置。游戏以完成时间来评高低。有不同的游戏难度可选择。

实现的功能介绍

1.计时 2.初始化雷盘 3.打印雷盘 4.随机设置雷的分布,可选择游戏难易程度 5.统计坐标位置周围的雷数 6.第一次排雷不会被炸死 7.扩展式排雷,展开周围的非雷区 8.给所选坐标位置做标记,或取消标记

该程序分为三个文件:

1.game.h :包含头文件的引用、函数的声明和宏定义 2.game.c :包含游戏各功能函数的具体实现 3.pro.c :各功能函数的调用(程序的流程) PS:文章末尾附完整代码 及 游戏效果图

因为排雷时要计算每个位置周围八个位置的雷数,所以在创建数组时要多一圈,即行列都要加2。给用户显示的数组不需要加。

游戏功能代码详解

1.计时

运用clock函数,该函数需要的头文件为 “time.h” 函数原型:clock_t clock(void); 功能:程序从启动到函数调用占用CPU的时间 这个函数返回从“开启这个程序进程”到“程序中调用clock()函数”时之间的CPU时钟计时单元(clock tick)数,在MSDN中称之为挂钟时间;若挂钟时间不可取,则返回-1。其中clock_t是用来保存时间的数据类型。

voidset_time()//计时
{
printf("用时:%u秒\n",clock()/CLOCKS_PER_SEC);
}

2.初始化雷盘 这里我用到的是memset函数,需要的头文件为“memory.h”或“string.h” 函数原型:void *memset(void *s, int ch, size_t n); 功能:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。在一段内存块中填充某个给定的值。

voidinit_board(charboard[ROWS][COLS],introw,intcol,charc)//初始化雷盘
{
memset(board,c,row*col*sizeof(board[0][0]));
}

3.打印雷盘 运用两个循环体实现雷盘数组的赋值、行号、列号的打印。正式游戏时可以加上system(“CLS”); 清屏语句,每次调用时都清屏一次,使游戏画面更简洁清晰。 我们把计时函数放在里面,每次打印雷盘时就可以显示所用的时间。

voiddisp_board(charboard[ROWS][COLS],introw,intcol)//打印雷盘
{
inti=0;
intj=0;
//system("CLS");//清屏
for(i=0;i<=row;i++)
{
printf("%2d",i);//打印行号
}
printf("\n");
for(i=1;i<=row;i++)
{
printf("%2d",i);//打印列号
for(j=1;j<=col;j++)
{
printf("%2c",board[i][j]);
}
printf("\n");
}
printf("\n");
set_time();//打印所用的时间
}

4.随机设置雷的分布,可选择游戏难易程度 放置雷必须是随机的,这里用到了rand函数,它和srand函数配合使用产生随机数。srand(time(NULL))放在主函数中调用一次,通过系统时间提供的种子值,使rand函数生成不同的伪随机数序列。

voidset_mine(charboard[ROWS][COLS],introw,intcol,intcount)//置雷
{
intx=0;
inty=0;
while(count)
{
x=rand()%row+1;//随机位置范围1~row
y=rand()%col+1;//随机位置范围1~col
if(board[x][y]=='0')//判断是否已有雷
{
board[x][y]='1';//有雷的位置赋为1
count--;
}
}
}

5.统计坐标位置周围的雷数 及 未扫的位置的个数 当扫到一个没有雷的位置时,会显示这个位置周围一圈八个位置的含雷的总数,所以我们要写一个“数雷”函数来数。

intcount_mine(charmine[ROWS][COLS],intx,inty)//数雷
{
returnmine[x-1][y]+mine[x-1][y+1]+mine[x][y+1]+mine[x+1][y+1]+mine[x+1][y]+
mine[x+1][y-1]+mine[x][y-1]+mine[x-1][y-1]-8*'0';//数周围一圈八个位置的雷数
}

intcount_print(charprint[ROWS][COLS],introw,intcol)//数未扫位置
{
intcount=0;
inti=0;
for(i=1;i<=row;i++)
{
intj=0;
for(j=1;j<=col;j++)
{
if(print[i][j]=='@'||print[i][j]=='*')
{
count++;
}
}
}
returncount;
}

6.第一次排雷不会被炸死 为了增加游戏的可玩性,加入“第一次排雷不被炸死”这个函数。当第一次排就遇到雷时,我们把雷偷偷挪走,随机放在一个原本无雷的位置。

voidsafe_mine(charmine[ROWS][COLS],charprint[ROWS][COLS],intx,inty,introw,intcol)//第一次排雷不炸死
{
charch=0;
intret=1;
intnumber=0;
if(mine[x][y]=='1')//第一次踩到雷后补救
{
mine[x][y]='0';
charch=count_mine(mine,x,y);
print[x][y]=ch+'0';//数字对应的ASCII值和数字字符对应的ASCII值相差48,即'0'的ASCII值
extend_board(mine,print,x,y);
while(ret)//在其余有空的地方设置一个雷
{
intx=rand()%row+1;//产生1到row的随机数,在数组下标为1到10的范围内布雷
inty=rand()%col+1;//产生1到col的随机数,在数组下标为1到10的范围内布雷
if(mine[x][y]=='0')//找不是雷的地方布雷
{
mine[x][y]='1';
disp_board(print,row,col);
//disp_board(mine,row,col);
ret--;
break;
}
}
}
}

7.扩展式排雷,展开周围的非雷区 当游戏中排到一个周围一圈都无雷的位置时,运用递归,实现扩展展开周围的一片无雷区。

voidextend_board(charmine[ROWS][COLS],charprint[ROWS][COLS],intx,inty)//运用递归扩展周围
{
intn=0;
n=count_mine(mine,x,y);
if(n==0)//当该位置周围雷数为0时扩展
{
print[x][y]='';//扩展的位置变为“空格”打印出来
if(mine[x-1][y]=='0'&&print[x-1][y]=='@')
{
extend_board(mine,print,x-1,y);//递归
}
if(mine[x+1][y]=='0'&&print[x+1][y]=='@')
{
extend_board(mine,print,x+1,y);
}
if(mine[x][y+1]=='0'&&print[x][y+1]=='@')
{
extend_board(mine,print,x,y+1);
}
if(mine[x-1][y+1]=='0'&&print[x-1][y+1]=='@')
{
extend_board(mine,print,x-1,y+1);
}
if(mine[x+1][y+1]=='0'&&print[x+1][y+1]=='@')
{
extend_board(mine,print,x+1,y+1);
}
if(mine[x][y-1]=='0'&&print[x][y-1]=='@')
{
extend_board(mine,print,x,y-1);
}
if(mine[x+1][y-1]=='0'&&print[x+1][y-1]=='@')
{
extend_board(mine,print,x+1,y-1);
}
if(mine[x-1][y-1]=='0'&&print[x-1][y-1]=='@')
{
extend_board(mine,print,x-1,y-1);
}
}
else
print[x][y]=n+'0';
}

intfind_mine(charmine[ROWS][COLS],charprint[ROWS][COLS],introw,intcol,intcount)//排雷
{
intx=0;
inty=0;
intnumber=0;
intret=0;
while(1)
{
printf("输入坐标扫雷\n");
scanf("%d%d",&x,&y);//玩家输入扫雷的坐标位置
if((x>=1&&x<=row)&&(y>=1&&y<=col))//判断输入坐标是否有误,输入错误重新输入
{
if(mine[x][y]=='0')//没踩到雷
{
number++;//记录扫雷的次数
charch=count_mine(mine,x,y);//数雷数
print[x][y]=ch+'0';//数字对应的ASCII值和数字字符对应的ASCII值相差48,即'0'的ASCII值
extend_board(mine,print,x,y);
disp_board(mine,row,col);
disp_board(print,row,col);
if(count_print(print,row,col)==count)//剩余未扫位置=雷数时胜利
{
return0;
}
to_sign(print);//判断是否标记
disp_board(print,row,col);
}
elseif(mine[x][y]=='1')//踩到雷
{
if(ret==0&&number==0)
{
ret++;
safe_mine(mine,print,x,y,row,col);
}
else
return1;
}
}
else
{
printf("输入错误!请重新输入\n");
}
}
}

8.给所选坐标位置做标记,或取消标记 扫雷游戏还有一个功能:可以给你认为是雷的位置标记,或者取消标记。 我通过三个函数来实现,一个判断用户是否需要标记;一个实现标记功能,将@标记成* ;一个实现取消标记功能,将* 改回@。

voidto_sign(charboard[ROWS][COLS])//判断是否标记
{
intchose_b=0;
intx=0;
inty=0;
printf("是否需要标记/取消标记:>\n(1.标记;2.取消标记;3.跳过该步骤):>");
scanf("%d",&chose_b);
do{
switch(chose_b)
{
case1:
{
printf("请输入需要标记的位置坐标:>\n");
scanf("%d%d",&x,&y);
sign(board,x,y);
break;
}
case2:
{
printf("请输入取消标记的位置坐标:>\n");
scanf("%d%d",&x,&y);
unsign(board,x,y);
break;
}
case3:
{
printf("跳过此步骤。\n");
chose_b=0;
break;
}
default:
{printf("输入错误!\n");
chose_b=0;
break;
}
}
chose_b=0;
}while(chose_b);
}
voidsign(charboard[ROWS][COLS],intx,inty)//用‘*'标记雷
{
if(board[x][y]=='@')
{
board[x][y]='*';
}
}

voidunsign(charboard[ROWS][COLS],intx,inty)//取消标记
{
if(board[x][y]=='*')
{
board[x][y]='@';
}
}

附:完整代码

game.h

#ifndef_GAME_H_
#define_GAME_H_
//用到的头文件
#include
#include
#include
#include
#include
//定义打印的雷盘行、列
#define_ROW9
#define_COL9
#defineROW16
#defineCOL16
//定义数组的行、列
#define_ROWS_ROW+2
#define_COLS_COL+2
#defineROWSROW+2
#defineCOLSCOL+2
//定义难、易程度雷数
#defineEASY_COUNT10
#defineHARD_COUNT40
//定义游戏中的函数
voidinit_board(charboard[ROWS][COLS],introw,intcol,charc);//初始化
voiddisp_board(charboard[ROWS][COLS],introw,intcol);//打印
voidset_mine(charboard[ROWS][COLS],introw,intcol,intcount);//置雷
voidsafe_mine(charmine[ROWS][COLS],charprint[ROWS][COLS],intx,inty,introw,intcol);//第一次排雷不炸死
intfind_mine(charmine[ROWS][COLS],charprint[ROWS][COLS],introw,intcol,intcount);//排雷
intcount_mine(charmine[ROWS][COLS],intx,inty);//数雷
voidextend_board(charmine[ROWS][COLS],charprint[ROWS][COLS],intx,inty);//扩展
voidto_sign(charboard[ROWS][COLS]);//判断是否标记
voidsign(charboard[ROWS][COLS],intx,inty);//标记
voidunsign(charboard[ROWS][COLS],intx,inty);//取消标记
intcount_print(charprint[ROWS][COLS],introw,intcol);//数未扫位置

#endif//_GAME_H_

game.c

#define_CRT_SECURE_NO_WARNINGS
#include"game.h"

voidset_time()//计时
{
printf("用时:%u秒\n",clock()/CLOCKS_PER_SEC);
}
voidinit_board(charboard[ROWS][COLS],introw,intcol,charc)//初始化雷盘
{
memset(board,c,row*col*sizeof(board[0][0]));
}

voiddisp_board(charboard[ROWS][COLS],introw,intcol)//打印雷盘
{
inti=0;
intj=0;
system("CLS");//清屏
for(i=0;i<=row;i++)//加行号
{
printf("%2d",i);
}
printf("\n");
for(i=1;i<=row;i++)//加列号
{
printf("%2d",i);
for(j=1;j<=col;j++)
{
printf("%2c",board[i][j]);
}
printf("\n");
}
printf("\n");
set_time();//打印所用的时间
}

voidset_mine(charboard[ROWS][COLS],introw,intcol,intcount)//置雷
{
intx=0;
inty=0;
while(count)
{
x=rand()%row+1;//随机位置范围1~row
y=rand()%col+1;//随机位置范围1~col
if(board[x][y]=='0')//判断是否已有雷
{
board[x][y]='1';
count--;
}
}
}

voidsafe_mine(charmine[ROWS][COLS],charprint[ROWS][COLS],intx,inty,introw,intcol)//第一次排雷不炸死
{
charch=0;
intret=1;
intnumber=0;
if(mine[x][y]=='1')//第一次踩到雷后补救
{
mine[x][y]='0';
charch=count_mine(mine,x,y);
print[x][y]=ch+'0';//数字对应的ASCII值和数字字符对应的ASCII值相差48,即'0'的ASCII值
extend_board(mine,print,x,y);
while(ret)//在其余有空的地方设置一个雷
{
intx=rand()%row+1;//产生1到row的随机数,在数组下标为1到10的范围内布雷
inty=rand()%col+1;//产生1到col的随机数,在数组下标为1到10的范围内布雷
if(mine[x][y]=='0')//找不是雷的地方布雷
{
mine[x][y]='1';
disp_board(print,row,col);
//disp_board(mine,row,col);
ret--;
break;
}
}
}
}


intcount_mine(charmine[ROWS][COLS],intx,inty)//数雷
{
returnmine[x-1][y]+mine[x-1][y+1]+mine[x][y+1]+mine[x+1][y+1]+mine[x+1][y]+
mine[x+1][y-1]+mine[x][y-1]+mine[x-1][y-1]-8*'0';//数周围一圈八个位置的雷数
}

intcount_print(charprint[ROWS][COLS],introw,intcol)//数未扫位置
{
intcount=0;
inti=0;
for(i=1;i<=row;i++)
{
intj=0;
for(j=1;j<=col;j++)
{
if(print[i][j]=='@'||print[i][j]=='*')
{
count++;
}
}
}
returncount;
}


voidextend_board(charmine[ROWS][COLS],charprint[ROWS][COLS],intx,inty)//运用递归扩展周围
{
intn=0;
n=count_mine(mine,x,y);
if(n==0)//当该位置周围雷数为0时扩展
{
print[x][y]='';//扩展的位置变为“空格”打印出来
if(mine[x-1][y]=='0'&&print[x-1][y]=='@')
{
extend_board(mine,print,x-1,y);//递归
}
if(mine[x+1][y]=='0'&&print[x+1][y]=='@')
{
extend_board(mine,print,x+1,y);
}
if(mine[x][y+1]=='0'&&print[x][y+1]=='@')
{
extend_board(mine,print,x,y+1);
}
if(mine[x-1][y+1]=='0'&&print[x-1][y+1]=='@')
{
extend_board(mine,print,x-1,y+1);
}
if(mine[x+1][y+1]=='0'&&print[x+1][y+1]=='@')
{
extend_board(mine,print,x+1,y+1);
}
if(mine[x][y-1]=='0'&&print[x][y-1]=='@')
{
extend_board(mine,print,x,y-1);
}
if(mine[x+1][y-1]=='0'&&print[x+1][y-1]=='@')
{
extend_board(mine,print,x+1,y-1);
}
if(mine[x-1][y-1]=='0'&&print[x-1][y-1]=='@')
{
extend_board(mine,print,x-1,y-1);
}
}
else
print[x][y]=n+'0';
}

intfind_mine(charmine[ROWS][COLS],charprint[ROWS][COLS],introw,intcol,intcount)//排雷
{
intx=0;
inty=0;
intnumber=0;
intret=0;
while(1)
{
printf("输入坐标扫雷\n");
scanf("%d%d",&x,&y);//玩家输入扫雷的坐标位置
if((x>=1&&x<=row)&&(y>=1&&y<=col))//判断输入坐标是否有误,输入错误重新输入
{
if(mine[x][y]=='0')//没踩到雷
{
number++;//记录扫雷的次数
charch=count_mine(mine,x,y);//数雷数
print[x][y]=ch+'0';//数字对应的ASCII值和数字字符对应的ASCII值相差48,即'0'的ASCII值
extend_board(mine,print,x,y);
//disp_board(mine,row,col);
disp_board(print,row,col);
if(count_print(print,row,col)==count)//剩余未扫位置=雷数时胜利
{
return0;
}
to_sign(print);//判断是否标记
disp_board(print,row,col);
}
elseif(mine[x][y]=='1')//踩到雷
{
if(ret==0&&number==0)
{
ret++;
safe_mine(mine,print,x,y,row,col);
}
else
return1;
}
}
else
{
printf("输入错误!请重新输入\n");
}
}
}


voidsign(charboard[ROWS][COLS],intx,inty)//用‘*'标记雷
{
if(board[x][y]=='@')
{
board[x][y]='*';
}
}

voidunsign(charboard[ROWS][COLS],intx,inty)//取消标记
{
if(board[x][y]=='*')
{
board[x][y]='@';
}
}
voidto_sign(charboard[ROWS][COLS])//判断是否标记
{
intchose_b=0;
intx=0;
inty=0;
printf("是否需要标记/取消标记:>\n(1.标记;2.取消标记;3.跳过该步骤):>");
scanf("%d",&chose_b);
do{
switch(chose_b)
{
case1:
{
printf("请输入需要标记的位置坐标:>\n");
scanf("%d%d",&x,&y);
sign(board,x,y);
break;
}
case2:
{
printf("请输入取消标记的位置坐标:>\n");
scanf("%d%d",&x,&y);
unsign(board,x,y);
break;
}
case3:
{
printf("跳过此步骤。\n");
chose_b=0;
break;
}
default:
{printf("输入错误!\n");
chose_b=0;
break;
}
}
chose_b=0;
}while(chose_b);
}

pro.c

#define_CRT_SECURE_NO_WARNINGS
#include"game.h"

voidmenu()
{
printf("+---------------------------------+\n");
printf("+Welcometo扫雷世界!+\n");
printf("+ο(=>ω<=)ρ⌒☆+\n");
printf("+1、play+\n");
printf("+0、exit+\n");
printf("+---------------------------------+\n");
}

voidgame()
{
charmine[ROWS][COLS]={0};
charprint[ROWS][COLS]={0};
intchose_m=0;
intret=0;
printf("请选择模式(1、简单2、困难):>");//选择游戏难易程度,产生不同大小的棋盘和雷数
scanf("%d",&chose_m);
switch(chose_m)
{
case1:
{
init_board(mine,ROWS,COLS,'0');//初始化雷盘
init_board(print,ROWS,COLS,'@');
set_mine(mine,_ROW,_COL,EASY_COUNT);//布雷
//disp_board(mine,_ROW,_COL);//打印雷盘
disp_board(print,_ROW,_COL);
intret=find_mine(mine,print,_ROW,_COL,EASY_COUNT);//扫雷,踩到雷返回1,没有踩到雷返回0
while(1)//循环扫雷
{
if(ret==0)//若返回0则胜利
{
disp_board(print,_ROW,_COL);
printf("WOW~YOUWIN!\n\n");
break;
}
if(ret)//若返回1则失败
{
disp_board(mine,_ROW,_COL);//打印雷盘
printf("GAMEOVER!\n");
break;
}
disp_board(print,_ROW,_COL);//打印玩家棋盘
}
break;
}
case2:
{
init_board(mine,ROWS,COLS,'0');//初始化雷盘
init_board(print,ROWS,COLS,'@');
set_mine(mine,ROW,COL,HARD_COUNT);//布雷
//disp_board(mine,ROW,COL);//打印雷盘
disp_board(print,ROW,COL);
while(1)//循环扫雷
{
intret=find_mine(mine,print,ROW,COL,HARD_COUNT);//扫雷,踩到雷返回1,没有踩到雷返回0
if(ret==0)//若返回0胜利
{
disp_board(print,ROW,COL);
printf("WOW~YOUWIN!\n\n");
break;
}
if(ret)//若返回1失败
{
disp_board(mine,ROW,COL);//打印雷盘
printf("GAMEOVER!\n");
break;
}
disp_board(print,ROW,COL);//打印玩家棋盘
}
break;
}
default:
{
printf("输入错误!\n");
break;
}
}
}
voidtext()
{
srand((unsignedint)time(NULL));//产生随机值发生器
intchose=0;//选择是否开始游戏
do
{
menu();//菜单
printf("请选择:>");
scanf("%d",&chose);
switch(chose)
{
case1:
game();//开始游戏
break;
case0:
printf("退出游戏\n");
break;
default:
printf("输入错误,没有该选项\n");
break;
}
}while(chose);
}
intmain()
{
text();
system("pause");
return0;
}

游戏效果图

①开始选择菜单、难易模式选择②两种难度扫雷 ↓9×9雷盘 10颗雷↓16×16雷盘 40颗雷③演示标记④GAME OVER 玩家失败演示⑤WIN 玩家成功演示

感谢各位的阅读!关于“C语言中如何实现扫雷小游戏”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

发布于 2021-05-30 14:07:36
分享
海报
189
上一篇:C语言如何实现AT指令ASCII码的拼接处理下一篇:C语言如何实现简单扫雷小程序
目录

    忘记密码?

    图形验证码