目录
一、游戏介绍
今天我们讲解扫雷游戏的制作,这是一个简易的扫雷游戏。
扫雷游戏怎么玩:
格子上的数字代表其周围八个格子中含有的雷的个数。
数字1代表我们点击格子以后显示周围八个格子中含有雷的个数。
我们知道玩法以后,那么我们就开始自己制作一款扫雷游戏吧。
首先如果把代码放入到一个.c文件中的话,不方便阅读,同时逻辑思维能力也会低,我们创建三个文件,test.c、game.c、game.h文件。
test.c文件,包含main函数,负责程序的入口和游戏的整体控制。
game.c:实现扫雷游戏的核心逻辑,如初始化棋盘、布置雷、检查输赢等。
game.h:头文件,包含函数声明和宏定义,用于被其他文件包含。
二、程序分析
在开始写程序时,我们需要分析书写代码的步骤
我们写的扫雷程序是一个简单模式,只需要有9*9的格子。
- 设计一个11x11的二维数组来表示棋盘,其中边缘的格子用于避免数组越界的问题。最终打印的话,我们只需要打印9x9的棋盘
- 初始化两个二维数组:mine数组用于存储雷的信息,show数组用于显示给玩家看。
- 实现一个打印棋盘的函数,用于显示show数组的内容给玩家。
- 在mine数组中随机布置雷。
- 实现排雷的逻辑,当玩家点击一个格子时,根据mine数组更新show数组,并显示给玩家。
三、游戏实现
一、打印程序主界面
game.h
#pragma once
#include <stdio.h>
test.c
#include "game.h"
void menu()
{
printf("***************************\n");
printf("********* 1、play *********\n");
printf("********* 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;
}
二、创建数组
我们需要创建数组的大小,为了方便修改数组的大小,我们把控制数组的行与宽定义在game.h文件里面,后续也方便我们修改。
game.h
#pragma once
#include <stdio.h>
#define ROW 9 //9行
#define COL 9 //9列
#define ROWS ROW+2 //11行
#define COLS COL+2 //11列
test,c
void game()
{
char mine[ROWS][COLS]; //设置mine的二维数组
char show[ROWS][COLS]; //设置show的二维数组
}
三、初始化
我们要把show给里面的元素给换成” * “,mine里面的元素换成” 0 “。
game.h
#pragma once
#include <stdio.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); //mine与show函数声明
//打印
//埋雷
//排雷
test.c
void game()
{
...............
//初始化
InitBoard(mine, ROWS, COLS, '0'); //mine的传参
InitBoard(show, ROWS, COLS, '*'); //show的传参
//打印
//埋雷
//排雷
}
我们需要设置数组是由字符打印出来的,所以我们把" 0 "跟” * “给传入到InitBoard里面。
我们一次性初始化两行代码,提高了代码编写的效率,无需重复编写代码。
game.c
#define _CRT_SECURE_NO_WARNINGS
#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; //二维数组等于set设置的字符
}
}
}
//打印
//埋雷
//排雷
四、打印数组
game.h
#pragma once
#include <stdio.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//初始化
...............
//打印
void DisplayBoard(char Board[ROWS][COLS], int row, int col); //函数声明
//埋雷
//排雷
test.c
void game()
{
...............
//初始化
...............
//打印
DisplayBoard(mine, ROW, COL); // 把mine二维数组进行函数传参
DisplayBoard(show, ROW, COL); // 把show二维数组进行函数传参
//埋雷
//排雷
}
game.c
void DisplayBoard(char Board[ROWS][COLS], int row, int col)
{
int i = 0;
printf("--------扫雷游戏-------\n");
for (i = 0; i <= col; 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]); //打印出9*9的二维数组
}
printf("\n");
}
}
输出为:
我们看见在mine数组输出的都是0 0 0 0 ,而show数组输出的是* * * * * *
在我们游戏过程中,我们只打印出show数组,mine数组是不打印的
如果把 mine数组也打印出来,就是偷看答案了
五、随机值创建
埋雷的话我我们需要使用随机值,把雷给放进到1-9的行列之中。
使用随机值的话,就要使用srand与time。
我们需要创建一个为正数的随机数,就需要使用unsigned类型,srand
函数用于初始化随机数生成器,而time
函数用于获取当前的时间(以秒为单位),这个时间值可以作为srand
函数的种子,从而使得每次运行程序时生成的随机数序列都不同。
所需要包含的头文件如下:game.h
#include <stdlib.h>
#include <time.h>
test,c
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
........
........
}
六、埋雷
game.h
//埋雷
void SetMine(char mine[ROWS][COLS],int row,int col);
我们只需要在mine数组中去放雷,所以只需要传送mine数组到函数里面,无需传show数组
test.c
void game()
{
//初始化
...............
//打印
...............
//埋雷
SetMine(mine, ROW, COL); // 传参,在mine二维数组中随机生成炸弹
//排雷
}
因为数组中字符’1‘是随机生成,有几率生成到同一个位置,所以才使用!=’1‘。
为什么需要使用字符’1‘,而不是整数1,因为我们先前初始化的是字符,而不是整数
game.c
//埋雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int count = 10;
while (count)
{
int x = rand() % row + 1;
int y = rand() % row + 1;
if (mine[x][y] !='1')
{
mine[x][y] = '1';
count--;
}
}
}
七、排雷
game.h
//排雷
void FindMine(char mine[ROWS][COLS], char show [ROWS][COLS], int row, int col);
int GetMineCount(char mine[ROWS][COLS], int x, int y);
FindMine函数是用来检查输入的坐标是雷还是安全的坐标
FindMine函数是用来检查输入坐标的周围八个字符有几个雷
test.c
void game()
{
...............
//初始化
...............
//打印
...............
//埋雷
...............
//排雷
FindMine(mine, show, ROW, COL); //把mine跟show都传入进去,我们需要使用两个数组
int GetMineCount(char mine[ROWS][COLS], int x, int y); //计算我们输入坐标点周围8个格子中有几个炸弹
}
game.h
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 - 10)
{
printf("请输入:");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y]=='1')
{
printf("很遗憾,你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
int count = GetMineCount(mine, x, y); //GetMineCount计算输入坐标周围8个格子炸弹个数。
show[x][y] = count + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("坐标非法\n");
}
}
if (win == row * col - 10)
{
printf("恭喜你,排雷成功\n");
DisplayBoard(mine, ROW, COL);
}
}
四、完整扫雷代码
test.c
#define _CRT_SECURE_NO_WARNINGS
#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, '*'); // 初始化显示棋盘
// 打印棋盘
DisplayBoard(mine, ROW, COL); // 打印雷区棋盘(调试用)
DisplayBoard(show, ROW, COL); // 打印显示棋盘
// 设置雷区
SetMine(mine, ROW, COL);
// 查找雷区
FindMine(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); // 输入0时退出循环
return 0;
}
game.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.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);
// 打印棋盘
void DisplayBoard(char Board[ROWS][COLS], int row, int col);
// 设置雷区
void SetMine(char mine[ROWS][COLS], int row, int col);
// 查找雷区
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
// 获取雷数
int GetMineCount(char mine[ROWS][COLS], int x, int y);
game.c
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
// 初始化棋盘
void InitBoard(char Board[ROWS][COLS], int rows, int cols, char set)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
Board[i][j] = set; // 设置每个格子的初始值
}
}
}
// 打印棋盘
void DisplayBoard(char Board[ROWS][COLS], int row, int col)
{
printf("--------扫雷游戏-------\n");
for (int i = 0; i <= col; i++)
{
printf("%d ", i); // 打印列号
}
printf("\n");
for (int i = 1; i <= row; i++)
{
printf("%d ", i); // 打印行号
for (int j = 1; j <= col; j++)
{
printf("%c ", Board[i][j]); // 打印每个格子的内容
}
printf("\n");
}
}
// 设置雷区
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int count = 10; // 设置雷的数量
while (count)
{
int x = rand() % row + 1;
int y = rand() % row + 1;
if (mine[x][y] != '1') // 确保不会重复设置雷
{
mine[x][y] = '1'; // 设置雷
count--;
}
}
}
// 获取指定位置周围的雷数
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
int count = 0;
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
if (mine[x + i][y + j] == '1') // 检查周围8个格子
{
count++; // 如果有雷,计数器加1
}
}
}
return count;
}
// 查找雷区
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 - 10) // 没有排完所有雷前循环
{
printf("请输入:");
scanf("%d%d", &x, &y); // 输入排雷坐标
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1') // 如果踩到雷
{
printf("很遗憾,你被炸死了\n");
DisplayBoard(mine, ROW, COL); // 显示所有雷区
break;
}
else
{
int count = GetMineCount(mine, x, y); // 获取周围雷数
show[x][y] = count + '0'; // 显示周围雷数
DisplayBoard(show, ROW, COL); // 打印当前棋盘
win++;
}
}
else
{
printf("坐标非法\n"); // 输入非法坐标提示
}
}
if (win == row * col - 10) // 如果赢得游戏
{
printf("恭喜你,排雷成功\n");
DisplayBoard(mine, ROW, COL); // 显示所有雷区
}
}