一.简单介绍:
在学完数组和函数,并知道两者是可以相互结合使用后,看了一些书籍,和一些视频讲解,得知扫雷游戏的实现,正好可以巩固一下自己对函数与数组之间混合使用的一些相关知识,因此写了本篇文章,来实现一个扫雷游戏。想必大家对扫雷游戏并不陌生,有兴趣的可以请去相关网站进行试玩,理解扫雷游戏规则更容易理解本篇文章。这里小编提供了一个比较好的网站可以试玩:扫雷游戏网页版 - Minesweeper
二.代码实现前提
1.打开编译器创建3个文件:
在这里小编创建3个文件的目的是因为:代码实现后会有接近200行,为了方便后期其他人更容易阅读,更容易看清小编的思路,当然你也可以在一个文件中实现。
说明:
test1.c :游戏整个逻辑运行
game.c :相关函数的调用
game.h :自创的一些头文件
2.扫雷游戏简单基础框架构建(应该适合所有游戏开发,前期的基础模板)
1.为了满足一些用户玩一遍不过瘾的需求这里我们采用循环玩游戏的方式这里使用do/while循环
2.打印一个菜单,并输入1 or 0 确定是否进入游戏
运行结果:
输入1:进入游戏
输入0:退出有游戏
输入其他数字:重新选择
输入1后可在此调用一个函数game():来实现扫雷游戏过程:
3.基础框架构建之后,就要来实现我们的扫雷游戏了,不过先不要着急,先来看一下扫雷游戏规则以及我们实现的思路(代码分析能力比较强的朋友可以跳过此部分)。
1.了解游戏规则
我们以最简单的9x9规格来分析:
当我们踩到雷的话程序直接结束显示游戏结束了
当我们没踩到雷的话,显示出来的数字代表他的周围8个位置显示几个雷。如下图:
以此类推,标记排除的所有雷,取得游戏胜利。
想必看到这的朋友们已经略微知道扫雷的基本规则了吧。
2.设置9x9盒子
针对扫雷游戏9x9排版的特殊方式,以及随机雷以坐标的方式随机存放在9x9版式中,想必很多朋友已经知道我们需要使用二维数组来存放每个随机雷,并生成9x9排版模式。现在我们来设置这个9x9的盒子
首先我们假设 1 是雷 0 不是雷 这样把‘1’假设成雷的好处是便于后期对雷个数的统计
但是不知道各位有没有想过这样做会出现一些歧义,如下图
当如果周围显示一个雷,就会出现数字‘1‘ 这个’1‘与表示雷的’1‘会有歧义因此,可以考率使用两个相同数组的方法,如下图,图一用来存放布置随机雷的信息,图二用来显示排查雷的信息。
这样来想是不是感觉方便了很多,先别急着激动,我们还需要在进一步完善该过程,结合下图我们可知当统计最外层雷的信息时会发生数组越界问题,因此我们需要通过扩大数组来解决这个问题。
扩大数组后最外层相当于全部为0,如图所示,
为了保持排雷的神秘感我们把排雷图全部填充满'*',由此可见我们需要设置一个字符型数组。
三.代码实现
1.定义两个可变(便于以后增加数组的长度,增加游戏的难度)数组。
特别注意在特使test.c文件引用game.h中的内容时不要忘了引用 game.h文件。
2.初始化两个数组(一个是布置雷的数组,一个是排雷的数组)
如图所示把布置雷的数组初始化为'0',把排雷得数组初始化为‘*’
目前为止你已经完成整个游戏的一半了,不妨先测试一下前面的过程是否是自己期望的那样,那我们就2打印一下
初始化布置雷打印结果
初始化排雷结果
以上是小编的打印结果,请参考。
3.随机布置雷
这里调用SetMine函数随机布置了10个雷,雷的数量我定义在了game.h头文件里面,这样定义是为了后期能修改雷的数量。
特别提醒:'0' '1'都是字符型的 count--要放在if条件语句里面,否则计算结果可能会减小。
设置随机数的时候需要用srand()函数;并引用头文件
先打印看一下结果:
4.扫雷
以上操作完成后雷的·布置也已经好了,现在就把这些类型的信息通过另一个数组表示出来显示给玩家
这里统计雷的个数时,只需让该坐标周围的数字相加,即为雷的个数。因为前面我们设置‘1’表示雷。
写到这里基本上整个扫雷游戏就可以运行了,下面让我们一起运行一下
被炸死程序结束
下面我们验证一下,排雷成功时的场景为了方便快速出结果,我们把雷的数量设置为80个
验证结果需要打印一下,布置雷的情况,进行验证。
验证结果符合我们预期。
四.该代码存在的问题
小编阿豪也是初学编程,对编程的理解也是不太深刻,只能简简单单的写一个不完美的程序,该程序还存较多的缺陷,阿豪也是知道的,但以阿豪现在的实力和想法是无法在对代码进行优化,望各位体谅。各位大神如果有新的想法或则认为代码需要改善,请在评论区或则私信给阿豪。
五.源码
//game.h文件内容//
#pragma once
//扫雷游戏
//游戏函数声明
#include<stdlib.h>
#include<stdio.h>
#include<time.h>
#define ROW 9 //行
#define COL 9 //列
#define ROWS ROW+2
#define COLS COL+2
#define COUNT 10
void InitBoard(char board[ROWS][COLS], int rows, int cols,char set);
void Print(char board[ROWS][COLS], int row, int col);
void SetMine(char board[ROWS][COLS], int row, int col);
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
//test.c 文件内容//
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//扫雷游戏
//该文见作用:游戏的整个逻辑运行
#include"game.h"
void game() {
char mine[ROWS][COLS] = { 0 }; //布置雷的数组
char show[ROWS][COLS] = { 0 }; //排雷的数组
InitBoard(mine, ROWS,COLS,'0'); //初始化布置雷的数组‘0’
InitBoard(show, ROWS,COLS,'*'); //初始化排雷的数组'*'
SetMine(mine, ROW, COL);
Print(mine, ROW, COL);
printf("\n");
Print(show, ROW, COL);
FindMine(mine, show, ROW, COL);
}
void menu() {
printf("*******************\n");
printf("***** 1. play ****\n");
printf("***** 0. exit ****\n");
printf("*******************\n");
}
int main() {
srand((unsigned int)time(NULL));
int input = 0;
do {
menu();
printf("请输入:>");
scanf("%d", &input); //输入 0 / 1
switch (input) {
case 1:
printf("扫雷开始\n");
game(); //调用函数
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请输入1/0\n");
break;
}
} while (input);
return 0;
}
//game.c文件内容
#define _CRT_SECURE_NO_WARNINGS 1
//扫雷游戏
//游戏相关的函数实现
#include"game.h"
void InitBoard(char board[ROWS][COLS], int rows, int cols,char set) {
int i = 0;
for (i = 0; i < ROWS; i++) {
int j = 0;
for (j = 0; j < COLS; j++) {
board[i][j] = set;
}
}
}
void Print(char board[ROWS][COLS], int row, int col) {
int i = 0;
for (i = 0; i <= row; i++) {
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++) {
printf("%d ", i);
int j = 0;
for (j = 1; j <= col; j++) {
printf("%c ", board[i][j]);
}
printf("\n");
}
}
void SetMine(char board[ROWS][COLS], int row, int col) {
int count = COUNT; //个数后期能修改
while (count) {
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0') {
board[x][y] = '1';
count--;
}
}
}
int GetMinecount(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 FindMine(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-COUNT) {
printf("请输入你要排查的坐标篇:>\n");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col) { //保证输入的坐标在范围内合法
if (mine[x][y] == '1') {
printf("您被炸死了\n");
Print(mine, ROW, COL);
break;
}
else {
int count=GetMinecount(mine,x,y); //调用函数计算输入坐标周围有几个雷
show[x][y] = count + '0'; //把计算结果存到扫雷数组中 加'0'的原因是数组是字符型
Print(show, ROW, COL);
win++; //计算排雷个数
}
}
else {
printf("输入错误\n");
break;
}
}
if (win == row * col - COUNT) {
printf("排雷成功\n");
Print(mine, ROW, COL); //排雷成功后查看该棋盘的诉所有布雷情况
}
}