前置知识
1 扫雷游戏的功能说明
- 使用控制台实现
- 可以通过菜单实现继续玩或者退出游戏
- 扫雷的棋盘是9*9的格子
- 默认随机布置10个雷
- 可以排查雷
- 如果该位置不是雷,就显示周围有几个雷
- 如果该位置是雷,就炸死,游戏结束
- 把10个雷之外的所有非雷位置找出,排雷成功,游戏结束
游戏实现界面如图:
2 棋盘的设计思路
首先我们可以准备两个二维数组,mine数组用来存放雷的位置的信息,show数组用来存放给玩家看的信息。
- 在mine数组中存放0和1,1表示该位置是雷,0表示该位置没有雷。
- 在show数组中存放*,表示该位置没有被排查,用户排查过程中,若该位置没有雷,则显示一个数字代表该位置周围有几个雷。
如果我们将棋盘设计成9*9,那么我们在排查雷的过程中,会访问该位置的八个方向的数据,当我们排查周围一圈的位置时,总会有一个或两个方向的几个位置会越界,例如我们排查位置(9,5)时,我们在统计位置(10,4)、(10,5)、(10,6)时会越界。
因此为了解决这个问题,我们可以将数组扩大一圈,这样我们便可以解决越界访问的问题了。即将9 * 9 改为11 * 11。
3 游戏的API的设计
//开始游戏
void game();
//菜单
void Meum();
//初始化棋盘
void initBord(char arr[][COLS], char f);
//打印棋盘
void diaPlay(char arr[][COLS], int row, int col);
//布置雷
void setMine(char arr[][COLS], int row, int col);
//查找雷
void findMine(char mine[][COLS], char show[][COLS]);
//获取该坐标周围雷的数量
int getMineCount(char mine[][COLS], int x, int y);
- game()函数:负责调用其他函数实现游戏的开始
- Meum()函数:负责打印菜单方便用户选择操作
- initBord()函数:负责将数组初始化为0或*
- diaPlay()函数:负责将数组打印到控制台
- findMine()函数:负责排查玩家输入的位置是否为雷,如不是雷则将show上的该位置显示该位置周围有几个雷
- getMineCount()函数:负责统计玩家输入的位置周围有几个雷
- 统计位置(x,y)时,需要统计(x-1,y-1)、(x-1,y)、(x-1,y+1)、(x,y-1)、(x,y+1)、(x+1,y-1)、(x+1,y)、(x+1,y+1)八个方向
- setMine()函数:负责将初始化的mine数组的9个随机位置设置成1
- 利用随机数生成9个坐标
4 代码实现
mine头文件的实现:
头文件存放整个文件所需的数据类型和函数声明
ROW和COL代表mine和show数组的行和列,这里使用宏定义,方便后期的维护和修改
ROWS和COLS分别+2表示在数组的周围扩大一圈
#pragma once
#pragma once
#include <stdio.h>
//棋盘行列数
#define ROW 9
#define COL 9
//真实棋盘行列数
#define ROWS ROW+2
#define COLS COL+2
//雷的数量
#define MINE_COUNT 9
//开始游戏
void game();
//菜单
void Meum();
//初始化棋盘
void initBord(char arr[][COLS], char f);
//打印棋盘
void diaPlay(char arr[][COLS], int row, int col);
//布置雷
void setMine(char arr[][COLS], int row, int col);
//查找雷
void findMine(char mine[][COLS], char show[][COLS]);
//获取该坐标周围雷的数量
int getMineCount(char mine[][COLS], int x, int y);
mine源文件的实现
存放mine头文件中声明的函数的实现代码
#include "mine.h"
#include <stdlib.h>
void Meum() {
printf("********************************\n");
printf("******* 选择 1.开始游戏 ********\n");
printf("******* 选择 0. 退出游戏 *******\n");
printf("********************************\n");
}
void game() {
//存放雷的数组
char mine[ROWS][COLS];
//展示排雷信息的数组
char show[ROWS][COLS];
//初始化棋盘
initBord(mine, '0');
initBord(show, '*');
//布置雷
setMine(mine, ROW, COL);
diaPlay(show, ROW, COL);
//查找雷
findMine(mine, show);
//diaPlay(show, ROW, COL);
}
//初始化棋盘
void initBord(char arr[][COLS], char f) {
int i, j;
for (i = 0; i < ROWS; i++) {
for (j = 0; j < COLS; j++) {
arr[i][j] = f;
}
}
}
//打印棋盘
void diaPlay(char arr[][COLS], int row, int col) {
printf("-------------扫雷游戏-----------------\n");
int i, j;
for (i = 0; i <= row; i++) {
printf("%d ", i);
}
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 setMine(char arr[][COLS], int row, int col) {
int count = MINE_COUNT;
while (count) {
int x = rand() % row + 1;
int y = rand() % col + 1;
if (arr[x][y] == '0') {
arr[x][y] = '1';
count--;
}
}
}
//查找雷
void findMine(char mine[][COLS], char show[][COLS]) {
int x, y;
//需要排查位置的个数
int findCount = ROW * COL - MINE_COUNT;
while (findCount) {
printf("请输入你要排除的坐标:\n");
scanf_s("%d%d", &x, &y);
if (x >= 1 && y >= 1 && x <= ROW && y <= COL) {
if (mine[x][y] == '1') {
printf("你被炸死了!\n");
diaPlay(mine, ROW, COL);
break;
}
else {
show[x][y] = getMineCount(mine, x, y) + '0';
//system("cls");
diaPlay(show, ROW, COL);
findCount--;
}
}
else {
printf("坐标不合法,请重新输入!");
}
}
if (findCount == 0)
printf("恭喜你排雷成功!\n");
}
//获取该坐标周围雷的数量
int getMineCount(char mine[][COLS], int x, int y) {
int i, j;
int count = 0;
for (i = -1; i <= 1; i++)
{
for (j = -1; j <= 1; j++) {
if (mine[x + i][j + y] == '1') {
count++;
}
}
}
return count;
}
Main源文件的实现
整个项目的入口文件
#include "mine.h"
#include <stdlib.h>
#include <time.h>
int main() {
srand((unsigned int)time(NULL));
int input;
do {
Meum();
printf("请输入你的选择:\n");
scanf_s("%d", &input);
switch (input) {
case 1:
game();
break;
case 0:
printf("退出游戏!\n");
break;
default:
printf("输入错误请重新输入!\n");
break;
}
} while (input);
return 0;
}
小结:
通过扫雷游戏的案例实现,我们可以更好的了解和使用二维数组,并熟悉c语言中的分文件编写。当然这篇文章所实现的扫雷游戏中还有一些功能并未实现。我将这些功能的实现放到了C语言实现扫雷游戏(进阶版)。