✅作者简介:大家好我是zoroxs
📃个人主页:c/c++学习之路
🔥💖如果觉得博主的文章还不错的话,请👍三连支持一下博主哦
扫雷小游戏
C语言能写很多的小游戏,可以很好地加深我们对学过知识的印象,更可以增加我们对学习的兴趣。
上次带大家写了一个三子棋,今天带大家再来写一个人人皆知的扫雷,这游戏,反正从小到大我是一局都没赢过,今天我们就用C语言来实现小时候特别爱玩的游戏
📕1.游戏整体思路
- 打印雷盘
- 往雷盘中放置雷
- 接受用户输入坐标,扫雷
- _判断是否踩到雷,踩到雷---->恭喜他被炸死, _
- 没踩雷,在对应位置显示周围有几颗雷
- 直到踩雷或者所有非雷位置都被走过,游戏结束
📗2.扫雷双雷盘设计
很关键的地方在于雷盘的设计,我们假设要99的雷盘,那我们要存储雷还有用户是否排过,周围又有几个雷,用一个99的二维数组可以实现。
给大家提供一个崭新的思路,
我们这里使用两个同样的二维数组来存储:
一个存储雷的位置,有雷是1,无雷是0,
_另一个当成展示雷盘,没扫过就是*,扫过就显示周围有几颗雷的数字_**
像这种靠墙壁的,计算它周围有几颗雷比较复杂,我们这里有一个妙手。
_我们如果要用9*9的雷盘,就弄成11*11的数组,我们展示的时候只展示9*9就可以了,这样每一个墙壁周围都有一层格子,极大方便了我们的计算。_
我们需要两个函数来帮我们实现一下棋盘,大家看之前的三子棋就知道,初始化,打印,必备
我们来看一下声明,这里需要注意的是,我们要初始化两个雷盘,初始化的字符不一样,所以参数需要把初始化的字符传进去
//初始化雷盘
void init_board(char board[ROWS][COLS], int row, int col, char ch);
//打印雷盘
void display_board(char board[ROWS][COLS], int row, int col);
我们来看一下代码实现
//初始化雷盘
void init_board(char board[ROWS][COLS], int row, int col, char ch)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ch;
}
}
}
void display_board(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
//打印行号
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 ", board[i][j]);
}
printf("\n");
}
}
来看一下展示出来的雷盘
📘3.往棋盘中放雷
雷盘已经好了,我们来往雷盘中放雷,我们可以在外边宏定义好需要放入的雷的数量
然后我们来定义一个放置雷的函数:
void set_board(char board[ROWS][COLS], int row, int col ,int mine_count);
void set_board(char board[ROWS][COLS], int row, int col, int mine_count)
{
while (mine_count > 0)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if ('0' == board[x][y])
{
board[x][y] = '1';
mine_count--;
}
}
}
这里用到了随机数,如果对随机数的使用没啥概念的朋友,可以去看一下前边的三子棋小游戏,对随机数的生成做了简单介绍 三子棋,还不明白的,可以私信我交流
📙4.扫雷
棋盘中雷已经放置成功,我们就可以开始扫雷了,按照用户输入的坐标进行判断,如果是雷就结束游戏,如果不是雷就展示坐标周围有几颗雷,继续扫雷
我们实现一个扫雷函数
void clean_mine(char mine_board[ROWS][COLS], char show_board[ROWS][COLS], int row, int col)
判断坐标周围有几颗雷的函数
int get_mine_count(char board[ROWS][COLS], int x, int y)
我们来实现一下代码,坐标合法并且此位置没有被扫过,我们才判断
//获取坐标周围有几颗雷
int get_mine_count(char board[ROWS][COLS], int x, int y)
{
return (board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + board[x][y - 1] +
board[x][y + 1] + board[x + 1][y - 1] +
board[x + 1][y] + board[x + 1][y + 1]) - 8 * '0';
}
//扫雷
void clean_mine(char mine_board[ROWS][COLS], char show_board[ROWS][COLS], int row, int col)
{
int count = 0;
while (count < row * col - MINE_COUNT)
{
printf("请输入坐标:>\n");
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
//判断坐标是否合法
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//判断是否被扫过
if (show_board[x][y] == '*')
{
if ('1' == mine_board[x][y])
{
printf("恭喜您,被雷炸死了\n");
break;
}
else if ('0' == mine_board[x][y])
{
int count = get_mine_count(mine_board, row, col);
show_board[x][y] = count + '0';
display_board(show_board, row, col);
count++;
}
}
}
}
if (count == row * col - MINE_COUNT)
{
printf("恭喜您,成功通关\n");
}
}
这里有一个注意事项就是返回周围有几颗雷时,因为我们用的是字符数组,周围有8个位置,所以需要减去 8乘以字符0
📓5.判断成败
雷盘的总位置–雷的个数就是无雷区,如果用户走过所有无雷区,则就赢得胜利
📔6.测试函数编写
以上基本就是我们的所有游戏代码了,差的是使用的头文件,以及函数声明和宏定义,
我们用测试函数来测试一下我们的游戏是否可以正常运行
直接给大家放代码了,有了三子棋的经验,基本很类似
//打印菜单
void menu()
{
printf("**********************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("**********************\n");
}
void game()
{
//定义两个雷盘,一个展示,一个放雷
char mine_board[ROWS][COLS];
char show_board[ROWS][COLS];
//初始化雷盘
init_board(mine_board, ROWS, COLS, '0');
init_board(show_board, ROWS, COLS, '*');
//打印雷盘
display_board(show_board, ROW, COL);
//放雷
set_board(mine_board, ROW, COL, MINE_COUNT);
//排雷
clean_mine(mine_board, show_board, ROW, COL);
}
int main(void)
{
int input = 0;
srand(time(NULL));
do
{
menu();
printf("请输入:>\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default :
printf("输入有误,请重新输入\n");
break;
}
} while (input);
return 0;
}
📒7.代码拼接
代码总共分成了3个文件
- game.h-----引头文件,定义宏,函数声明
- game.c----游戏核心代码实现
- test.c ----测试函数核心代码实现
把这三个文件一起编译就可以跑起来游戏了,给大家把三个代码都放出来
7.1📄game.h
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROWS 11
#define COLS 11
#define COL 9
#define ROW 9
//雷数
#define MINE_COUNT 10
//初始化雷盘
void init_board(char board[ROWS][COLS], int row, int col, char ch);
//打印雷盘
void display_board(char board[ROWS][COLS], int row, int col);
//放雷
void set_board(char board[ROWS][COLS], int row, int col ,int mine_count);
//扫雷
void clean_mine(char mine_board[ROWS][COLS], char show_board[ROWS][COLS], int row, int col);
7.2📃game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//初始化雷盘
void init_board(char board[ROWS][COLS], int row, int col, char ch)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ch;
}
}
}
void display_board(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
//打印行号
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 ", board[i][j]);
}
printf("\n");
}
}
void set_board(char board[ROWS][COLS], int row, int col, int mine_count)
{
while (mine_count > 0)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if ('0' == board[x][y])
{
board[x][y] = '1';
mine_count--;
}
}
}
//获取坐标周围有几颗雷
int get_mine_count(char board[ROWS][COLS], int x, int y)
{
return (board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + board[x][y - 1] +
board[x][y + 1] + board[x + 1][y - 1] +
board[x + 1][y] + board[x + 1][y + 1]) - 8 * '0';
}
//扫雷
void clean_mine(char mine_board[ROWS][COLS], char show_board[ROWS][COLS], int row, int col)
{
int count = 0;
while (count < row * col - MINE_COUNT)
{
printf("请输入坐标:>\n");
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
//判断坐标是否合法
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//判断是否被扫过
if (show_board[x][y] == '*')
{
if ('1' == mine_board[x][y])
{
printf("恭喜您,被雷炸死了\n");
break;
}
else if ('0' == mine_board[x][y])
{
int count = get_mine_count(mine_board, row, col);
show_board[x][y] = count + '0';
display_board(show_board, row, col);
count++;
}
}
}
}
if (count == row * col - MINE_COUNT)
{
printf("恭喜您,成功通关\n");
}
}
7.3📑test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//打印菜单
void menu()
{
printf("**********************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("**********************\n");
}
void game()
{
//定义两个雷盘,一个展示,一个放雷
char mine_board[ROWS][COLS];
char show_board[ROWS][COLS];
//初始化雷盘
init_board(mine_board, ROWS, COLS, '0');
init_board(show_board, ROWS, COLS, '*');
//打印雷盘
display_board(show_board, ROW, COL);
//放雷
set_board(mine_board, ROW, COL, MINE_COUNT);
//排雷
clean_mine(mine_board, show_board, ROW, COL);
}
int main(void)
{
int input = 0;
srand(time(NULL));
do
{
menu();
printf("请输入:>\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default :
printf("输入有误,请重新输入\n");
break;
}
} while (input);
return 0;
}
这就是三个文件的所有代码,可以实现最基本的扫雷,虽然没有平时玩的只能,但毕竟自己写,还是很有成就感的。
📚8.总结
不管是三子棋还是扫雷,都离不开我们之前学到过的知识,函数 、数组、分支、循环…把很多都串联起来使用,让大家的逻辑思维得到很好地锻炼
大家一定要多多练习,后边比如贪吃蛇、俄罗斯方块等等,有需要的大家可以评论区留言,我拿命更新
这里有一个缺陷,可以实现,但是我没有写, 就是使用递归,让扫的坐标,周围不是雷的全部自动散开,大家可以尝试尝试,有问题可以找我。
🔥💖如果觉得博主的文章还不错的话,请👍三连支持一下博主哦