前言
全篇无任何废话,本文的解释大多数都在代码段中,所以一定要看代码,边看边学边理解。
这只是初学者入门的一个小游戏,不难懂,没有什么复杂的内容
可以先学习一下比扫雷还简单的猜数字和三子棋
C语言趣味小游戏——猜数字
C语言趣味小游戏——三子棋
游戏实现的条件(简单版)
1:创建三个文件
1:(test.c):用于游戏的逻辑测试,游戏菜单的打印,游戏设计的展示2:(game.c):用于游戏功能的具体实现,游戏的核心代码
3:(game.h):用于头文件的包含,符号以及函数的声明
2:先布置10个雷
3:扫雷
(1):输入坐标,是雷游戏结束
(2):输入坐标,不是雷,以坐标为中心,遍历周围的8个位置中有多少雷,就显示对应的数字
3:直到把所有非雷的位置找出来,游戏结束,扫雷成功
打印简易的菜单
1:先打印一个简单的菜单,过程不过多赘述,这个链接有详解
三子棋——打印一个简易的菜单
void menu()
{printf("**********************\n");printf("****** 1.play ******\n");printf("****** 0.over ******\n");printf("**********************\n");
}// void test()
{int input = 0;do {menu();printf("选择 1 进入游戏,选择 0 退出游戏\n");scanf("%d", &input);switch (input){case 1:// game(); 假设这是游戏printf("扫雷游戏\n");break;case 0:printf("退出游戏\n");break;default:printf("请重新输入\n");}} while (input);
}//int main()
{test();return 0;
}
雷盘的初始化
1:创建一个9*9的二维数组并且创建数组存放10个雷
2:把雷赋值为 1 放进数组里,如果不是雷(非雷)就为 0
3:开始扫雷 ↓ 例如下图,以为坐标(4,1)为中心,它周围有两个雷,就显示2

在下图中坐标为(3,1)的位置,它的周围只有一个雷,所以显示的是1

但是在第2步,我们将雷赋值为了1放进数组中
这样就会产生bug,这是绝对不允许的
而且还有一个问题,如果坐标在雷盘的边缘,就不可能遍历周围的8个坐标,如果用代码实现会太麻烦
出现的问题
至此已近出现两个问题
1:我们赋值雷为1,但是在遍历坐标周围8个位置的时候,只有1个雷,这个 ‘ 1 ’ 究竟是周围8个坐标中有1个雷,还是我们赋值的雷
2:在雷盘边缘,我们遍历不了8个位置,但是用代码实现又会太麻烦
解决方案
1(1):再创建一个数组,也就是雷盘2,我们将雷盘1和雷盘2的数据都一致,将雷盘1中显示雷个数的数字放到雷盘2,其他数据放在雷盘1,这样只会显示雷盘2,不会分不清 ‘ 1 ’ 究竟是什么

1(2):将雷盘1的 非雷(0),在雷盘2中以 ‘ * ’ 打印出来

2(1):在坐标(3,3)中,可以遍历周围8个位置,但是在坐标(9,1)中,只能遍历3个位置
如果修改代码,那将会是一个极其复杂的过程

2(2):所以我们将雷盘再扩大一圈,雷盘还是9×9,但是大小是11×11,多余的是防止越界遍历

至此,问题已经解决,下面开始代码的实现过程
游戏的实现
在文件中使用宏来定义雷盘的大小,以及防数组越界雷盘的大小
// 所在的文件 → game.h// ↓ 雷盘#define ROW 9#define COL 9// ↓ 防雷盘越界#define ROWS ROW+2#define COLS COL+2
定义两个雷盘
// 所在的文件 → test.cvoid game()
{// 游戏的实现char mine[ROWS][COLS] = { 0 }; // 雷盘 1char show[ROWS][COLS] = { 0 }; // 雷盘 2}
初始化雷盘
// 所在的文件 → test.cvoid game()
{// 游戏的实现char mine[ROWS][COLS] = { 0 }; // 雷盘 1char show[ROWS][COLS] = { 0 }; // 雷盘 2// 初始化雷盘Init_board(mine, ROWS, COLS,'0');Init_board(show, ROWS, COLS,'*');}
声明雷盘的信息
// 所在的文件 → game.hvoid Init_board(char arr[ROWS][COLS], int rows, int cols,char set);// 雷盘 ,行 ,列 ,内容
定义雷盘的信息
// 所在的文件 → game.cvoid Init_board(char arr[ROWS][COLS], int rows, int cols,char set)
{int i = 0;int j = 0;for (i = 0; i < rows; i++){for (j = 0; j < cols; j++){arr[i][j] = set;}}
}
打印雷盘,防止bug
// 所在的文件 → test.c
void game()
{ // 打印雷盘show_board(mine, ROW, COL);}
// 所在的文件 → game.h
// 打印void show_board(char arr[ROWS][COLS], int row, int col);
所在的文件 game.c
// 打印void show_board(char arr[ROWS][COLS], int row, int col)
{int i = 0;int j = 0;for (i = 1; i <= row; i++){for (j = 1; j <= col; j++){printf("%C ", arr[i][j]);}printf("\n");}
}
效果图

如果用这样的信息去扫雷,每次还要找坐标,所以在数组的周围加上显示长和宽的数字,会很方便
// 所在的文件 → game.c
void show_board(char arr[ROWS][COLS], int row, int col)
{int i = 0;int j = 0;int a = 0;for (a = 0; a <= col; a++){printf("%d ", a);}printf("\n");for (i = 1; i <= row; i++){printf("%d ", i);for (j = 1; j <= col; j++){printf("%C ", arr[i][j]);}printf("\n");}
}
效果图

布置雷
// 所在的文件 → test.c
void game()
{// 布置雷set_mine(mine, ROW, COL);}
// 所在的文件 → game.h
// 布置雷void set_mine(char mine[ROWS][COLS], int row, int col);
// 所在的文件 → game.c
// 布置雷void set_mine(char mine[ROWS][COLS], int row, int col)
{int count = EASY_COUNT;int x = 0;int y = 0;while (count){x = rand() % row + 1;y = rand() % col + 1;if (mine[x][y] == '0'){mine[x][y] = '1'; // 布置雷count--;}}
}
排查雷
// 所在的文件 → test.c
void game()
{// 排查雷find_mine(mine, show, ROW, COL);}
// 所在的文件 → game.h
// 排查雷void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
// 所在的文件 → game.c
int get_mine_count(char mine[ROWS][COLS], int x, int y) // 遍历坐标周围的8个位置
{returnmine[x - 1][y] +mine[x - 1][y - 1] +mine[x][y - 1] +mine[x + 1][y - 1] +mine[x + 1][y] +mine[x + 2][y + 1] +mine[x][y + 1] +mine[x - 1][y + 1] -8 * '0';
}
// 排查雷
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{printf("请输入要排查的坐标");int x = 0;int y = 0;while (1){scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (mine[x][y] == '1'){printf("游戏结束,被雷炸死\n");show_board(mine, ROW, COL);break;}else{int count = get_mine_count(mine, x, y);show[x][y] = count + '0';show_board(show, ROW, COL);}}else{printf("输入坐标非法,请重新输入\n");}}
}
所有代码
// 所在的文件 → test.c
#define _CRT_SECURE_NO_WARNINGS 1#include"game.h"void menu()
{printf("**********************\n");printf("****** 1.play ******\n");printf("****** 0.over ******\n");printf("**********************\n");}
void game()
{// 游戏的实现char mine[ROWS][COLS] = { 0 }; // 雷盘 1char show[ROWS][COLS] = { 0 }; // 雷盘 2// 初始化雷盘Init_board(mine, ROWS, COLS,'0'); // 雷盘 1Init_board(show, ROWS, COLS,'*'); // 雷盘 2// 打印雷盘// show_board(mine, ROW, COL);// 布置雷set_mine(mine, ROW, COL);show_board(show, ROW, COL);// show_board(show, ROW, COL);// 排查雷find_mine(mine, show, ROW, COL);
}int main()
{int input = 0;srand((unsigned int)time(NULL));do{menu();printf("请选择 1 进入游戏 0 退出游戏 \n");scanf("%d", &input);switch(input){case 1:game();printf("扫雷游戏\n");break;case 0:printf("退出游戏!\n");break;default :printf("输入错误,请重新选择!\n");}} while (input);return 0;
}
// 所在的文件 → game.h
#pragma once#include<stdio.h>#include<stdlib.h>#include<string.h>#include<time.h>#define ROW 9#define COL 9#define ROWS ROW+2#define COLS COL+2#define EASY_COUNT 10// 初始化void Init_board(char arr[ROWS][COLS], int rows, int cols,char set);// 打印void show_board(char arr[ROWS][COLS], int row, int col);// 布置雷void set_mine(char mine[ROWS][COLS], int row, int col);// 排查雷void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
// 所在的文件 → game.c
#define _CRT_SECURE_NO_WARNINGS 1#include"game.h"// 初始化void Init_board(char arr[ROWS][COLS], int rows, int cols,char set)
{int i = 0;int j = 0;for (i = 0; i < rows; i++){for (j = 0; j < cols; j++){arr[i][j] = set;}}
}// 打印void show_board(char arr[ROWS][COLS], int row, int col)
{int i = 0;int j = 0;int a = 0;for (a = 0; a <= col; a++){printf("%d ", a);}printf("\n");for (i = 1; i <= row; i++){printf("%d ", i);for (j = 1; j <= col; j++){printf("%C ", arr[i][j]);}printf("\n");}
}// 布置雷void set_mine(char mine[ROWS][COLS], int row, int col)
{int count = EASY_COUNT;int x = 0;int y = 0;while (count){x = rand() % row + 1;y = rand() % col + 1;if (mine[x][y] == '0'){mine[x][y] = '1'; // 布置雷count--;}}
}int get_mine_count(char mine[ROWS][COLS], int x, int y) // 遍历坐标周围的8个位置
{returnmine[x - 1][y] +mine[x - 1][y - 1] +mine[x][y - 1] +mine[x + 1][y - 1] +mine[x + 1][y] +mine[x + 2][y + 1] +mine[x][y + 1] +mine[x - 1][y + 1] -8 * '0';
}// 排查雷
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{printf("请输入要排查的坐标");int x = 0;int y = 0;int win = 0;while (win<row*col-EASY_COUNT){scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (mine[x][y] == '1'){printf("游戏结束,被雷炸死\n");show_board(mine, ROW, COL);break;}else{int count = get_mine_count(mine, x, y);show[x][y] = count + '0';show_board(show, ROW, COL);win++;}}else{printf("输入坐标非法,请重新输入\n");}}// 判断是否成功if (win == row * col - EASY_COUNT){printf("恭喜你,扫雷成功!\n");show_board(mine, ROW, COL);}
}
总结
1:do while 结构方便玩完一盘继续,也方便打印简易的菜单
2:实现游戏,用了两个雷盘 , 并且用char数组来存储游戏的数据
3:为了防止数组越界访问, 雷盘2 比 雷盘1 大 2×2,一个存放布置好雷的信息,一个存放排查出雷的信息
4:初始化棋盘—打印棋盘—布置雷—排查雷
5:是雷被炸死,不是雷统计坐标周围有几个雷,返回到雷盘2
6:找到所有非雷的位置,游戏结束

















