本系列博文仅为博主个人学习笔记,通过博客理清学习思路用于复习。如有记述不周到的地方请谅解;如能指出,更加感谢。
扫雷游戏它是由row * col的格子拼起来,游戏规则:这款游戏的玩法是在一个99(初级),1616(中级),16*30(高级),或自定义大小的方块矩阵中随机布置一定量的地雷(初级为10个,中级为40个,高级为99个)。由玩家逐个翻开方块,以找出所有地雷为最终游戏目标。如果玩家翻开的方块有地雷,则游戏结束。
// 本程序采用两个二维数组存储棋盘
char mine[row][col] ; // 用来存储雷的信息
char show[row][col] ; // 用来展示当前玩家展开棋盘的信息
```
## 1.该如何用c语言实现这样一款游戏 ---- 代码分析
该游戏主要步骤就是两步1.如何设置雷2.如何排查雷。
1. 设置雷
```c
//随机产生一对坐标,存储在x ,y当中
int x = rand() % row + 1 ;
int y = rand() % col + 1 ;
//若存储地雷的二维数组该坐标不是雷,则将其设置成雷
if(mine[x][y] == '0'){
mine[x][y] = '1';
}
2、排查雷
玩家输入一对坐标,对坐标进行判断是否是合法输入,如果是合法输入,则继续判断该坐标对应的mine数组是否为雷,若为雷,则结束游戏,提示玩家您不小心踩到啦雷,游戏结束;若没有踩到雷,则继续游戏,并将该格子对应坐标周围所有的雷数展示出来,玩家继续挖雷,直到所有的不是雷的格子被玩家全部挖出,则游戏结束,提示玩家获胜。
playerMove(char mine[][COLS],char show[][COLS], int row, int col) {
int x = 0;
int y = 0;
int count = 0;
while (count < row * col - NUM_MINE) {
printf("请输入您要排除的雷的坐标:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col) {
if (mine[x][y] == '1') {
printf("不好意思,你被炸啦,游戏结束\n");
break;
}
/*int ret = count_mine(mine, x, y);
show[x][y] = ret + '0';
count++;*/
else {
//对代码的递归优化,详细请见下文,功能是将与输入坐标周围8个格子所有不是雷的展开,提高用户游戏体验。
OpenMine(mine, show, row, col, x, y, &count);
//打印当前游戏棋盘的状态
Display(show, row, col);
}
}
else {
printf("输入坐标非法:\n");
}
}
if (count >= (col * row - NUM_MINE)) {
printf("恭喜您,扫雷成功\n");
}
}
本程序分为三个文件 game.h 头文件,game.c 具体实现文件,test.c测试文件 。
#include
#define NUM_MINE 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//initial array 1. mine 2. show
initial(char board[][COLS], int rows, int col,char set);
//display 1. mine 2. show
Display(char board[][COLS], int row, int col);
//set mine
set_mine(char mine[][COLS], int row, int col);
//remove mine
playerMove(char mine[][COLS],char show[][COLS], int row, int col);
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//initial array 1. mine 2. show
initial(char board[][COLS], int rows, int cols,char set) {
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
//display 1. mine 2. show
Display(char board[][COLS], int row, int col) {
printf("------扫雷游戏------\n");
for (int i = 0; i <= row; i++) {
printf("%d ", i);
}
printf("\n");
for (int i = 1; i <= row; i++)
{
printf("%d ", i);
for (int j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("------扫雷游戏------\n");
}
//set mine
set_mine(char board[][COLS], int row, int col) {
int count = NUM_MINE;
while (count) {
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0') {
board[x][y] = '1';
count--;
}
}
}
//count mine by every grid
static int count_mine(char mine[][COLS], int x, int y) {
return mine[x - 1][y - 1] +
mine[x-1][y] +
mine[x - 1][y + 1] +
mine[x][y - 1] +
mine[x][y + 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] - '0' * 8;
}
//open mines one by one
static void OpenMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y,int *level)
{
(*level)++;
if (mine[x][y] == '1' || x < 1 || x > row || y < 1 || y > col || show[x][y] != '*') {
(*level)--;
return;
}
int ret = count_mine(mine, x, y); //调用统计雷个数的函数。
if (!ret)
{
show[x][y] = ' ';
//要确定周围8个坐标本身不是雷,才递归它周围的。
OpenMine(mine, show, row, col, x - 1, y - 1,level);
OpenMine(mine, show, row, col, x, y - 1,level);
OpenMine(mine, show, row, col, x + 1, y - 1, level);
OpenMine(mine, show, row, col, x - 1, y, level);
OpenMine(mine, show, row, col, x + 1, y, level);
OpenMine(mine, show, row, col, x - 1, y + 1, level);
OpenMine(mine, show, row, col, x, y + 1, level);
OpenMine(mine, show, row, col, x + 1, y + 1, level);
}
else
{
show[x][y] = ret + '0'; //显示该坐标周围有几个雷
return;
}
}
//playermoving
playerMove(char mine[][COLS],char show[][COLS], int row, int col) {
int x = 0;
int y = 0;
int count = 0;
while (count < row * col - NUM_MINE) {
printf("请输入您要排除的雷的坐标:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col) {
if (mine[x][y] == '1') {
printf("不好意思,你被炸啦,游戏结束\n");
break;
}
/*int ret = count_mine(mine, x, y);
show[x][y] = ret + '0';
count++;*/
else {
OpenMine(mine, show, row, col, x, y, &count);
Display(show, row, col);
}
}
else {
printf("输入坐标非法:\n");
}
}
if (count >= (col * row - NUM_MINE)) {
printf("恭喜您,扫雷成功\n");
}
}
#include "game.h"
#include
#include
void menu() {
printf("*********************\n");
printf("******1. play *****\n");
printf("******0. exit *****\n");
printf("*********************\n");
}
void game() {
//定义两数组来存储数据
char mine[ROWS][COLS] = {
0 };
char show[ROWS][COLS] = {
0 };
//initial array
initial(mine, ROWS, COLS,'0');
initial(show, ROWS, COLS,'*');
//Display(mine, ROW, COL);
Display(show, ROW, COL);
//set mine
set_mine(mine, ROW, COL);
playerMove(mine,show, ROW, COL);
Display(mine, ROW, COL);
}
int main() {
srand((unsigned)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:> ");
scanf("%d",&input);
switch (input) {
case 1:
game();
break;
case 0:
printf("退出\n");
break;
default :
printf("输入错误\n");
break;
}
} while (input);
return 0;
}
此处重点来说说openmine 这个函数,功能是一个一个的展开周围的8个格子,若该格子的坐标不合法,曾访问过或者是雷,则满足条件,return返回,若满足以上条件均不满足,则将该格子周围的雷数进行统计,若统计数不为零,则不将其周围格子进行展开,只将其格子周围的雷数展示出来;若统计数为0,则将该格子置为‘ ’,并进入下一个格子 的判断:将该格子的左上,左,左下,正上,正下,右上,右,右下8个格子继续进行以上三个判断,并用一个变量count计数,依次判断,直到所有相邻的格子判断完毕。若count < row * col - 雷数, 则玩家继续输入坐标进行下一轮判断。重复上述动作,在玩家没有踩到雷的情况下正常,直到 count < row* col - 雷数不满足条件,跳出循环 ,提示玩家胜利。
扫雷游戏还是比较简单的,希望同学们一起努力,从c语言青铜慢慢变成c语言王者,我们一起在山顶相遇。