目录
前言
在1992年4月6日,扫雷搭载在Windows 3.1系统中与用户见面。这个游戏的玩法很简单,有初级、中级、高级和自定义等模式,雷区中随机布置一定数量的地雷,玩家需要尽快找出所有不是地雷的方块,但不许踩到地雷。今天我们就用代码来实现初阶扫雷游戏吧
1. 游戏设计和分析
1.1 游戏基本功能
- 我们需要一个菜单让玩家选择开始或退出游戏
- 初阶版扫雷是 9 * 9 的棋盘
- 默认布置 10 颗雷
1.2 游戏界面
(初始界面) (排雷失败界面)
1.3 游戏功能分析
1.3.1 棋盘格子问题
因为我们想要的是 9 * 9 的棋盘,所以需要使用到二维数组。我们可以把二维数组设置为 arr[9][9],在格子内用 1 来表示雷,用 0 来表示非雷,如下:
这样看是不是没有什么问题,我们可以试着来选择一个坐标来排雷 —— [4][3],它是非雷,所以选择它后应该统计周围一圈的八个格子来计算雷的数量并显示在 [4][3] 上,统计个数为 0;那当我们选择的是四边上的坐标呢,比如 [8][5],它也是非雷,但当我们想要排查它周围的八个格子时,我们发现数组越界访问了,此时就会出现bug。为了防止越界,我们可以四边都扩大一圈,变成 11 * 11 的二维数组,这样在排雷过程中就十分流畅啦
(9 * 9 二维数组) (11 * 11 二维数组)
我们接着分析:关于初始界面,为了保持神秘感,我们可以用 “*” 先掩盖雷和非雷。对于雷和非雷,我们使用的是整数 1 和 0;但这样的话,当在玩家排雷过程中,遇到周围有一个雷的情况,用 1 来表示数量雷不就和雷 1 冲突了吗?因此我们可以用字符 ‘1’ 和字符 ‘0’ 来表示雷和非雷,这样就能很好地把数字雷和埋雷两种情况分开
2. 代码实现
2.1 文件类别
我们可以将代码分为三个文件,一个是 minesweeper.c 文件,是存放 main 主函数、menu 菜单函数以及 game 游戏函数;一个是 game.c 文件,存放的函数是与游戏功能相关的,如:初始化棋盘,打印棋盘,布置雷,排雷等功能;最后一个是 game.h 文件,游戏中需要的数据类型和函数都在里面声明
2.2 游戏代码
game.h
#pragma once
#include <stdio.h>
//为了生成随机数
#include <stdlib.h>
#include <time.h>
//定义内圈行数为9,内圈列数为9
#define ROW 9
#define COL 9
//定义外圈行数为11,外圈列数为11
#define ROWS ROW+9
#define COLS COL+9
//雷的个数
#define Mine 1080
//初始化棋盘
void InitBoard(char arr[ROWS][COLS], int row, int col, char set);
//打印棋盘
void PrintBoard(char arr[ROWS][COLS], int row, int col);
//布置雷
void SetMine(char arr[ROWS][COLS], int row, int col);
//排雷
void ClearMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
game.c
#include "game.h"
//初始化棋盘
//遍历数组,并把 set 字符变量传进去
void InitBoard(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 PrintBoard(char arr[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("=======扫 雷=======\n");
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");
}
printf("=======扫 雷=======\n");
}
//布置雷
void SetMine(char arr[ROWS][COLS], int row, int col)
{
int count = Mine;
while (count)
{
//生成随机数 1~9
int x = rand() % row + 1;
int y = rand() % col + 1;
//防止重复布雷
if (arr[x][y] == '0')
{
arr[x][y] = '1';
count--;
}
}
}
//查找周围的雷
//把玩家输入的 (x,y) 周围的八个格子都加起来然后减去 8 * '0'
int FindMine(char mine[ROWS][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]) - 8 * '0';
}
//排雷
void ClearMine(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 - Mine)//设定赢的条件
{
printf("请输入你想排除的坐标:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//先判断玩家输入的坐标是否正确
{
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了\n");
PrintBoard(mine, ROW, COL);
break;
}
else
{
//在定义一个 FindMine 函数来计算周围雷的个数
int count = FindMine(mine, x, y);
//玩家排雷后打印棋盘
show[x][y] = count + '0';
PrintBoard(show, ROW, COL);
win++;
}
}
else
{
printf("输入错误坐标,请重新输入!");
}
}
//玩家排雷成功,并打印棋盘
if (win == row * col - Mine)
{
printf("恭喜你,排雷成功\n");
PrintBoard(mine, ROW, COL);
}
}
minesweeper.c
#include "game.h"
void menu()
{
printf("====================\n");
printf("==== 1.play ====\n");
printf("==== 0.exit ====\n");
printf("====================\n");
}
void game()
{
char mine[ROWS][COLS];
char show[ROWS][COLS];
//初始化棋盘
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//打印棋盘
PrintBoard(show, ROW, COL);
//布置雷
SetMine(mine, ROW, COL);
//排雷
ClearMine(mine, show, ROW, COL);
}
int main()
{
int input = 0;
//生成随机数
srand((unsigned int)time(NULL));
//使用 do-while 语句来循环打印菜单
//供玩家自由选择
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;
}
结语
上面的扫雷代码比较简约,功能较少,设计思路也很简单(博主还比较菜,写不出更复杂的扫雷游戏),比较适合初学者。不知到大家觉得如何,欢迎各位在评论区友好讨论。如果觉得不错的话,麻烦您点个赞吧,十分感谢!