首先介绍扫雷是一个咋样的游戏
我们可以看到,扫雷是由9*9的棋盘,在其中放了十个随机雷;注意雷的放置一定是随机值。
根据游戏难度的不同,也有不同大小的棋盘,这个主要是看你输入的值来确定,后面会细说。
当我们点击一个空格的时候,这时候大家仔细看,电脑会判断这个格子的周边有没有雷;而这个格子是一个3*3的规则图形;也就是说,我们判断点到的格子周边一圈3*3的范围里面有没有雷;有几个雷那么我们就在这个格子上面写上几个。
当我们运气不好点到雷的时候,是不是就显示游戏结束了。
这时候就可以选择再来一把或者退出游戏。
整体游戏过程就是这样,下面再讲一下,如何实现这些代码;
扫雷游戏的实现基础原理
因为游戏里面要实现的东西太多,这时候就可以把扫雷游戏,细分一下,分成不同的代码,最后再结合起来,这样就可以看的不是太乱。
首先我们需要创建如图所示的几个文件;
可以看到,我们在头文件上面又创建了一个扫雷的头文件game.h,跟一个源文件game.c;
这两个文件有什么用呢?
首先我们了解一一下,头文件
像我们平时写代码加的库函数头文件一样;自己定义的头文件也可以如库函数头文件一样使用;那么就我们是不是就可以把自己写的函数的声明放在头文件里面,这样只要在代码里面加上这个头文件,那么就可以用我们自己定义的函数。
所以我们把自己写的函数,声明放在头文件,然后把函数如何实现放在 game.c文件,这样一来,我们主文件tast1.c 就只需要包含一个头文件,就可以使用我们创建的函数。这样是不是代码就看起来很简洁,也不会太乱。《记笔记》。
切记,自己定义的头文件,如果需要调用的时候那么就跟库函数的头文件不一样了,自己定义的头文件调用方法为 #include"文件名" 。
用双引号来代表,自己定义的头文件。
接着再了解一下,源文件 game.c
我们这里为了实现扫雷这个游戏,写了两个源文件,首先是主函数的taxt1.c的源文件;还有一个就是自定义函数的game.c源文件。
这样做有什么好处呢?主要就是可以实现分模块写;就好比一个计算器,我想实现 加法 减法 乘法 除法 ;这时候我就可以让好几个人来写这个代码,每个人都在头文件里面声明了这个函数,然后再整合到主函数里面,这样一来是不是不光大大提高了效率,而且还容易看代码。
这就是我们多个源文件的意义。
扫雷的实现过程
一、游戏思路
一、扫雷的边界大小
我在9*9的大小中创建一个二维数组,然后又因为我们要排查这个位置的周围一圈有没有雷;那么当这个位置是9*9的边缘位置的时候那么,这是再排查是不是就越界了,所以这里我们需要创建一个比9*9大一圈的数组,即11*11的数组。
这时候我们排查才不会跃出范围。
二、扫雷的数组框架
我们已经知道了数组的大小,那么我们这时候就需要创建两个数组用来实现扫雷的棋盘构造。
这时候我们要设置两个2个数组,一个数组(min)用来存放布置好的雷的信息,另一个数租(mix)存放排查出来雷的信息。min数组初始化为‘0’,布置雷的时候,改为‘1’ 。mix数组初始化为‘*’,排查雷后,具体位置改为数字字符,有几个雷就变成几。(注意这里为了方便后面计算位置的周边有几个雷,我们初始化的0是字符0)。
三、打印游戏菜单
任何游戏都离不开一个菜单,只有先打印菜单了,别人才能知道这是个什么游戏,应该怎么玩。
游戏菜单的选择,无非就是开始游戏和退出游戏,这样我们就把游戏的选择放在switch的分支语句中来进行实现,如果我们选择1就是开始玩游戏,选择0就是退出游戏。
注意,这里我们选择 do while 循环,让这个代码可以先运行一次再循环。
四、游戏步骤的实现
1、初始化游戏棋盘
我们在主函数(taxt1.c)里面定义好数组的变量
再在头文件(game.h)里面声明函数。
这里我们ROWS的意义就是把9*9变成11*11空间变大了,但是雷的生成与排查还是在ROW 9*9里面
然后下面声明了 bord 函数(函数的意义就是初始化11*11的棋盘)
在 game.c 的文件里面呢,我们就可以来实现这个bord函数是怎样的一个代码。
当 形参 enr 为‘0’时,就把函数初始化为‘0’,同理初始化‘*’。主要看你带入进来的值。
2.打印棋盘
这时候数组初始化函数也写好了,就可以开始打印棋盘了,我们已经知道了,数组是11*11。但是切记我们扫雷游戏的大小只需要9*9,这里不要带错值了,防止出现报错。
还是一样的同理,在game.h 头文件里面声明这个打印函数,然后在game.c源文件里面实现这个打印函数。
写到这里,我们可以运行一下代码看看,是不是按照我们的要求打印了9*9的数组
可以看到,完美的实现了两个数组的初始化。
3.布置雷
棋盘打印了之后,那么就可以开始生成雷了,这里需要用到 rand 函数,而要想使用 rand 函数那么需要一个前提条件,srand 函数,
srand((unsigned int )time(NULL)); //生成一个随机数。unsigned int 是指返回一个整形。
而这些函数需要包含头文件
#include"game.h" 这是time函数需要包含的 头文件。
#include <stdLib.h> 这是srand函数的头文件。
这些头文件可以统一放到 game.h 的头文件中,到时候需要使用时,只需要写上一个game.h的头文件即可。
这里我用 setma 自定义函数来布置雷。还是一样的先在头文件中声明这个函数,然后再去game.c文件中实现。
到这里我们就已经完成了随机生成雷的函数了,我们这时候如果想知道,它到底有没有随机生成呢?这时候我们可以用前面刚写出来的打印函数,来打印出来看一下,是不是严格按照我们的思路来进行的。
通过这两次的打印,可以明显看到,已经是随机生成了十个雷。到了此刻我们的代码就已经完成了一半了。
4.排查雷
在写排查雷的函数前面,我们是不是应该先把判断周边有几个雷的函数写了,然后再套用到排雷函数里面,这样是不是更加简洁。
4.1判断周边3*3有没有雷
还是一样的,我们先在game.h里面声明一下这个函数,我就把这个函数写成demain ,然后再去库函数game.c里面实现这个代码。我把函数的接受值定义一个x,y这样是不是就能更加方便的计算有几个雷。
这样是不是很清晰,如果有雷就是‘1’,没雷就是‘0’,我们只需要把这所有的加起来,再减掉八个字符0,那么结果是不是就是数字几了。
这时候,我们就完成了,判断周边有没有雷的全部过程。
4.2排查数组里面的雷
还是如出一辙,在头文件里面声明这个代码,在源文件里面实现这个代码。
请注意看,我们在这个排查雷的函数里面我又套用了两个函数,一个是判断周边雷的函数,一个是打印数组函数。
当我不小心踩到雷的时候,我们被炸死了,这时候打印出所有的雷。
我来把效果演示一下。
大家可以把这个代码跑起来,玩一下。还是蛮有意思的。
下面是源代码,以供参考。
五、源代码
1. game.h 函数声明 头文件
#pragma once
#include <stdio.h>
#include <stdLib.h>
#include <time.h>
#define ROW 9//行
#define DOP 9 //列
#define ROWS ROW+2
#define DOPS DOP +2
#define COUT 10//雷的数量
#include<stdLib.h>//随机一个值
#include<time.h>//时间
//函数声明
//初始化棋盘
void bord(char boad[ROWS][DOPS], int rows,int dops, int enr);
//打印棋盘
void prin(char boad[ROWS][DOPS], int rows, int dops);
//布置雷
void setma(char min[ROWS][DOPS], int row, int dop);
//排雷
void faidmain(char min[ROWS][DOPS],char mix[ROWS][DOPS],int row,int dop);
//判断周边有几个雷
int demai
2. game.c 函数实现 源文件
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include"game.h"
//棋盘
void bord(char boad[ROWS][DOPS], int rows, int dops,int enr)
{
for (int i = 0; i < rows; i++)//打印棋盘数组
{
for (int j = 0; j < dops; j++)
{
boad[i][j] = enr;
}
}
}
//打印棋盘
void prin(char boad[ROWS][DOPS], int rows, int dops)
{
printf("---------扫雷游戏---------\n");
for (int i = 0; i <= rows; i++)//打印第一排列号
{
printf("%d ", i);
}
printf("\n");
for (int i = 1; i <= rows; i++)//打印棋盘数组
{
printf("%d ", i);//打印行号
for (int j = 1; j <= dops; j++)
{
printf("%c ", boad[i][j]);
}
printf("\n");
}
printf("---------扫雷游戏---------\n");
}
//生成雷
void setma(char min[ROWS][DOPS], int row, int dop)
{
int come = COUT;//接受雷的数目
while (come)
{
int x = rand() % row + 1;//随机生成x坐标
int y = rand() % dop + 1;//随机y坐标
if (min[x][y] == '0')
{
min[x][y] = '1';
come--;
}
}
}
//判断周边有没有雷
int demain(char mine[ROWS][DOPS], int x, int y)
{
return (mine[x - 1][y] +
mine[x - 1][y - 1] +
mine[x][y - 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] +
mine[x][y + 1] +
mine[x - 1][y + 1] - 8 * '0');
}
//排查雷
void faidmain(char min[ROWS][DOPS], char mix[ROWS][DOPS], int row, int dop)
{
int x = 0;
int y = 0;
int win = 0;
while (win< row * dop - COUT)
{
printf("请输入你的坐标:>");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= dop)
{
if (min[x][y] == '1')
{
printf("很遗憾你被炸死了\n");
prin(min, ROW, DOP);
break;
}
else
{
int counsr = demain(min, x, y);
mix[x][y] = counsr + '0';
prin(mix, ROW, DOP);
win++;
}
}
else
{
printf("输入错误,请重新输入\n");
}
if (win == row * dop - COUT)
{
printf("恭喜你,排雷成功\n");
prin(min, ROW, DOP);
}
}
}
3. taxt1.c 主函数 源文件
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include"game.h"
void plays()
{
printf("************************\n");
printf("******* 1. play ******\n");
printf("******* 2. over ******\n");
printf("************************\n");
printf("************************\n");
}
void game()
{
char min[ROWS][DOPS];
char mix[ROWS][DOPS];
bord(min, ROWS, DOPS,'0');
bord(mix, ROWS, DOPS,'*');
//棋盘打印
//prin(min, ROW, DOP);
prin(mix, ROW, DOP);
//布置雷
setma(min, ROW, DOP);
//prin(min, ROW, DOP);
//排雷
faidmain(min,mix,ROW,DOP);
}
int main()
{
int m = 0;
srand((unsigned int )time(NULL));//生成一个随机数
do
{
plays();//打印菜单
printf("请选择\n");
scanf("%d", &m);
switch (m)
{
case 1:
printf("开始扫雷游戏\n");
game();
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("输入错误\n");
break;
}
} while (m);
return 0;
}