扫雷游戏大家都耳熟能详,描述一下主要功能:在棋盘中埋着已知的雷数。选择坐标后,会返回该坐标周围的雷点个数。根据提示的雷点个数,进行扫雷,争取获得游戏的胜利。
分析:首先要有一个棋盘,在这个棋盘中需要提前设置一定个数的雷。具体分析如下图

1.打印棋盘。我们需要两个二维数组,一个二维数组用来布置雷的位置,有一个二维数组用来显示我们排查雷的位置。映入眼帘的是9*9的棋盘,但是考虑到扫雷时需要反映出周围雷的个数,于是就存在越界的情况。解决方法:上下左右各加一行棋格。此时棋盘格为11*11,实际上只显示9*9即可。
void DisplayBoard(char board[ROWS][COLS],int row,int col)
{
color(7);
int i = 0;
int j = 0;
//打印列号
for ( i = 0; i <= col; i++)
{
printf("%d ",i);
}
printf("\n");
for ( i = 0; i <= col; i++)
{
printf("——");
}
printf("\n");
for ( i = 1; i <= row; i++)
{
printf("%d |",i);
for ( j = 1; j <= col; j++)
{
printf("%c ",board[i][j]);
}
printf("\n");
}
color(6);
printf("\n-----扫雷游戏------\n");
}
2.设置雷。规定雷为1,非雷为0。用到随机函数在前面文章中都有讲过,不清楚的同学可以往前回顾一下。需要注意的就是随机函数所调用的头文件,以及此处随机函数所用的范围。
void SetMine(char board[ROWS][COLS],int row,int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
3.扫雷。过程:首先要输入一个坐标,于是需要判断这个坐标是否合法,如果不合法就重新输入,如果合法就要在该位置上显示周围雷的个数。如果周围雷数为0,就需要依次展开,这里需要用到递归。

get_mine_count()中为什么要-8*‘0’:当我们排查雷的信息时,需要显示目标位置周围雷的数量,而字符’0’的ASCII码是48,字符‘1’的ASCII码是49,我们把目标位置周围的坐标加起来然后减去字符‘0’x8,就得到了该目标位置雷的数量,然后把该字符数量显示到show数组中。
排雷成功:假设一共有10个雷,一共有9*9=81个格子,那如果我们一次雷都没有踩到并且全部格子都走完,我们就获胜。即9*9-雷数 = 所走的格子数,就胜利;如果9*9-雷数 > 所走的格子数,说明还没有走完,继续进行。
//获得坐标周围雷的个数
int get_mine_count(char mine[ROWS][COLS],int x, int y)
{
return mine[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';
}
//扫雷
void Fide_mine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col)
{
int x = 0;
int y = 0;
int win = 0;
while (win < row*col-EASY_COUNT)
{
printf("请输入排查雷的坐标:>");
scanf("%d%d",&x,&y);
//判断x,y的合法性
if (x >=1 && x <= row && y >= 1 && y <= col)
{
//踩雷
if (mine[x][y] == '1')
{
color(4);
printf("很遗憾,你被炸死了\n");
DisplayBoard(mine,row,col);
break;
}
//不是雷
else{
Unfold(mine, show, x, y);
DisplayBoard(show,row,col);
win ++;
}
}else
{
printf("输入坐标非法,请重新输入!\n");
}
}
if (win == row*col-EASY_COUNT)
{
printf("恭喜你,排雷成功!\n");
DisplayBoard(mine,row,col);
}
}
展开的条件:
- 在坐标x,y处不为雷:mine[x][y] != 1(也就是踩雷的情况)
- x,y没有越界(实际已经判断是否合法)
- 在坐标x,y周围没有雷,get_mine_count == 0
- 递归条件:查看该位置是否被排查过,如果被排查过就跳出。
//展开
void Unfold(char mine[ROWS][COLS],char show[ROWS][COLS],int x, int y)
{
//判断是否排查过(如果没有被排查过那么,show数组元素的值应该是*)
if (show[x][y] != '*')
{
return;
}
//x,y周围的雷数
int count = get_mine_count(mine,x,y);
if (count > 0)
{
show[x][y] = count + '0'; // 必须得是count + '0' 这样才是字符类型;
return ;
}else if (count == 0)
{
show[x][y] = ' ';
//循环遍历x,y周围的八个位置
Unfold(mine, show, x - 1, y);
Unfold(mine, show, x - 1, y-1);
Unfold(mine, show, x - 1, y+1);
Unfold(mine, show, x + 1, y-1);
Unfold(mine, show, x + 1, y);
Unfold(mine, show, x + 1, y+1);
Unfold(mine, show, x , y-1);
Unfold(mine, show, x , y+1);
}
}
自定义函数后要进行函数声明。game.h
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<windows.h>
#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
#define EASY_COUNT 10
void color(short x);
void InitBoard(char board[ROWS][COLS],int rows,int cols,char set);
void DisplayBoard(char board[ROWS][COLS],int row,int col);
void SetMine(char board[ROWS][COLS],int row,int col);
void Unfold(char mine[ROWS][COLS],char show[ROWS][COLS],int x, int y);
void Fide_mine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col);
本文详细介绍了扫雷游戏的实现过程,包括创建棋盘、设置雷点、扫雷逻辑以及使用ASCII码计算周围雷点数。游戏的核心是通过递归展开无雷区域,并利用随机函数生成雷的位置。当所有非雷格子都被安全标记时,玩家获胜。
263

被折叠的 条评论
为什么被折叠?



