一:创建扫雷游戏的文件
创建结果
各个文件的作用
二:开始编写扫雷游戏
打印菜单是
分析game函数要实现的功能
初始化数组
打印棋盘
放置雷
玩家排雷
完整代码的展示
前言:
1、本文面对的读者主要是初学者
2、博主为大一新生写的难免有很多不足,欢迎大佬们指出。
3、博主的排版较粗糙,望读者谅解
一:创建结果
1、创建结果如下
![](https://i-blog.csdnimg.cn/blog_migrate/f4a4215c56c5c39b0cc1ff11bfb82356.png)
2、各个文件的作用
game.h是头文件,可以在头文件里用宏声明变量,或者声明我们需要实现的函数
game.c用来实现各个函数的功能
test.c编写游戏程序的框架
二:开始编写扫雷游戏
1、打印菜单
(1)、解释为何要这样打印菜单
目标: 在开始游戏之前,我们需要打印一个菜单,供玩家选择。具体要实现的操作有:
(1)、1表示玩游戏,0表示退出游戏,如果玩家输入错误,屏幕就会打印”输入错误,请重新输入“
(2)、菜单至少要打印一次,玩家选择后才能进行下一步。需要while循环语句实现
注:菜单功能在test.c源文件上实现这个功能
(2)、用代码实现打印菜单
#include"game.h"
void menu()
{
printf("#################################\n");
printf("####### 1. play 0. exit #######\n");
printf("#################################\n");
}
int main()
{
int input = 0;
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;
}
(3)、分析以上代码
do.......while循环是C语言三种循环语句的一种。
特点:与其他循环语句不同的是,do......while循环的执行次数1~n,也就是说该循环至少执行一次
注:C语言中可以用数字表示真假。0表示假,非0表示真
2、分析game函数要实现的功能
创建类型完全相同的数组,存放数组mine用来设置雷,show用来存放雷的信息
初始化数组
放置雷
打印棋盘
玩家排雷
判断输赢
3、初始化数组
1、原理分析
扫雷需要的棋盘是二维的,所以我们用的是二维数组。
在mine数组中,’0‘,表示非雷,’1‘表示雷。所以mine数组初始化时全部放置’0‘。
玩家在排雷时,看到的是show数组的内容,‘*’表示非雷,数字表示周边雷的个数,show数组初始化是全部放置‘*’。
2、用代码实现初始化
#include"game.h"
void game()
{
//需要两个类型相同的棋盘
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化棋盘
InitBoard(mine, ROWS, COLS,'0');
InitBoard(show, ROWS, COLS,'*');
解释:Initbord是我们定义的初始化函数ROWS COLS是我们在game.h头文件中用宏定义的变量。
是为了方便以后的修改。
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows,int cols,char set);
#include"game.h"
void InitBoard(char board[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++)
{
board[i][j] = set;
}
}
}
4、打印棋盘
(1)、ROWS COLS ROW COL设置的目的
为了方便理解,我将ROW COL都定义为3,ROWS为ROW+2,COLS为COL+2
![](https://i-blog.csdnimg.cn/blog_migrate/bd1ba2f29adf7795681852cbf42f34be.png)
![](https://i-blog.csdnimg.cn/blog_migrate/dcd460e93942080702f0eb841a4069f8.png)
解释:修改后的数组增加了两行两列为了方便之后修改行数和列数我们将行数设ROWS为ROW+2,COLS为COL+2.这样以后修改行列的时候只需修改ROW,COL。
(2)、确定数组中元素的坐标
1、为了更好的定位棋盘上元素的位置,我们在棋盘的上方和左边打印对应坐标。如下图:
![](https://i-blog.csdnimg.cn/blog_migrate/e9d1e4b7da88c14c8f162826c27510fd.png)
解释:行用ROW控制,列用COL控制。
(4)、用代码实现打印棋盘
void PrintBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("###### 扫雷 ########\n");
for (j = 0; j <= col; j++)
{
printf("%d ", j);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
5、布置雷
#include”game.h“
#define EASY_COUNT 10
void game()
{
//需要两个类型相同的棋盘
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化棋盘
InitBoard(mine, ROWS, COLS,'0');
InitBoard(show, ROWS, COLS,'*');
//打印棋盘
//PrintBoard(mine, ROW, COL);
PrintBoard(show, ROW, COL);
//布置雷
Setmine(mine, ROW, COL);
//PrintBoard(mine, ROW, COL);
(1)、随机雷的实现
为了实现随机,我们引入了rand函数
rand函数位于stdlib.h的头文件里,作用是随机产生一范围为0~32767的随机数。
如果要产生雷的范围为:1~ROW:列:1~COL
可以记作rand()%ROW+1;rand()%COL+1
注:1、srand函数在头文件stdlib.h里time在time.h里
2、srand((unsigned int)time(NULL))这句话只需要执行一,不需要在循环语句中反复执行
于是,代码可以写为:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
srand((unsigned int)time(NULL));
int a=rand()%10+1;
int b=rand()%10+1;
return 0;
}
(2)、用代码实现布置雷
void Setmine(char mine[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
6、玩家排雷
void game()
{
//需要两个类型相同的棋盘
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化棋盘
InitBoard(mine, ROWS, COLS,'0');
InitBoard(show, ROWS, COLS,'*');
//打印棋盘
//PrintBoard(mine, ROW, COL);
PrintBoard(show, ROW, COL);
//布置雷
Setmine(mine, ROW, COL);
//PrintBoard(mine, ROW, COL);
//排雷
Finemine(mine, show, ROW, COL);
}
(1)、分析这个函数的具体要求
打印”排查雷,请输入坐标“,后用键盘输入数字+空格+数字,分别代表x轴和y轴。
如果输入的数字不在数组的范围里,就打印”输入坐标非法,请重新输入“。
如果输入的坐标的字符为”*“,就打印”该坐标已被排查过“
如果查找的坐标正好是雷,打印”很遗憾,你被炸死了“。
如果查找的坐标不是雷,对应坐标的元素就要改为周围一周的炸弹个数
定义一个变量win=0,由于查找坐标需要重复进行,所以要用一个循环包括这个过程。每次排查一个非雷的作标,win+1.直到win==ROW*COL-EASY_COUNT
(2)、用代码实现玩家排雷
void Finemine(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- EASY_COUNT)
{
printf("排查雷,请输入坐标:>");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] == '*')
{
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了!\n");
PrintBoard(mine, ROW, COL);
break;
}
else
{
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
PrintBoard(show, ROW, COL);
win++;
}
}
else
{
printf("该位置已经被排查过\n");
}
}
else
{
printf("输入坐标非法,请重新输入:>");
}
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,排雷成功!\n");
}
}
完整代码的展示
#include"game.h"
void menu()
{
printf("#################################\n");
printf("####### 1. play 0. exit #######\n");
printf("#################################\n");
}
void game()
{
//需要两个类型相同的棋盘
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化棋盘
InitBoard(mine, ROWS, COLS,'0');
InitBoard(show, ROWS, COLS,'*');
//打印棋盘
//PrintBoard(mine, ROW, COL);
PrintBoard(show, ROW, COL);
//布置雷
Setmine(mine, ROW, COL);
//PrintBoard(mine, ROW, COL);
//排雷
Finemine(mine, show, ROW, COL);
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
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;
}
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows,int cols,char set);
//打印棋盘
void PrintBoard(char board[ROWS][COLS],int row, int col);
//布置雷
void Setmine(char mine[ROWS][COLS],int row,int col);
//排查雷
void Finemine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col);
#include"game.h"
void InitBoard(char board[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++)
{
board[i][j] = set;
}
}
}
void PrintBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("###### 扫雷 ########\n");
for (j = 0; j <= col; j++)
{
printf("%d ", j);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
void Setmine(char mine[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] == '0')
{
mine[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 + 1][y + 1] +
mine[x + 1][y] +
mine[x + 1][y - 1] +
mine[x][y - 1])-8*'0';
}
void Finemine(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- EASY_COUNT)
{
printf("排查雷,请输入坐标:>");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] == '*')
{
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了!\n");
PrintBoard(mine, ROW, COL);
break;
}
else
{
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
PrintBoard(show, ROW, COL);
win++;
}
}
else
{
printf("该位置已经被排查过\n");
}
}
else
{
printf("输入坐标非法,请重新输入:>");
}
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,排雷成功!\n");
}
}