前言:
在不涉及指针的情况下 ,我们可以通过函数和数组简单的实现一个扫雷游戏(9x9)。
以下我直接给出我们所需要的函数进一步讲解实现。
(同样,我们分成模块文件来完成:game.c main.c game .h)
代码分析:
1.实现交互界面,退出or开始游戏。我们直接上代码
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
int main()
{
int input = 1;
while (input)
{
menu();
printf("请输入—>: ");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("已退出游戏\n");
return;
default:
break;
}
}
return 0;
}
2.我们再来看看game.h中几个定义的宏常量
首先我们要定义一个棋盘的大小,但是我们为什么会有一个ROWS和COLS呢?其实这样做是为了方便我们后续在统计了地雷的数目时,因为我们在排查边界的地雷时,就会遇到数组越界的问题,因此我们让行和列大一些,这样我们就不用另外考虑边界的特殊情况,其次就是BOOM_CONUT用来设置地雷的数目
3.我们来看看game()函数的内部
首先我们创建两个数组,一个mine用来记录实际的布雷情况,一个用来展示棋盘给玩家进行游玩 。然后我们依次初始化他们,我们将初始化的内容也设置为参数,这样我们就不用再写一个函数来初始化两个不同要求的数组。初始化后我们可以打印棋盘展示,为了更好地展现棋盘,打印数组的同时,打印棋盘的行列序号
//打印棋盘
void display_board(char board[ROWS][COLS], int row, int col)
{
printf(" |-----Gaming-----|\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");
}
printf(" |-----Gaming-----|\n");
}
注意我给出的game()内部,我也打印了mine数组,这是因为方便我们后续调试 观察,实际情况不需要打印mine棋盘,后面可以注释掉该行,打印show即可。
然后就是设置地雷,使用rand()函数,为了让生成的数更加随机可靠,我们可以在game()中调用srand()函数(我们在进行下标操作时,在1到9进行操作即可,我们要求棋盘时是9x9,而我们的数组大小是11x11,这是用来防止数组越界的,上面的 打印棋盘也是同理,在1到9的下标操作即可),如下
然后关键来了:排雷操作
前面我们将mine初始化为‘0’(字符0)是有原因的,这样方便我们更好的计算排查坐标周围的地雷个数,直接上代码:
int get_boom_num(char mine[ROWS][COLS],int x,int y)
{
return
mine[x - 1][y] + mine[x + 1][y]
+ mine[x][y - 1] + mine[x][y + 1]
+ mine[x - 1][y + 1] + mine[x - 1][y - 1]
+ mine[x + 1][y + 1] + mine[x + 1][y - 1]
- 8 * 48;
}
这段代码是不是看起来很简单,但好像又不知道在干嘛 ?不急慢慢来看,其实我们就是将x,y坐标周围八个值加起来,然后减去8*48;为什么要这样操作呢?我们看看ascII表就知道了因为我们是将数组初始化为了字母‘0’,实际上ascii的值是48,而我们设置的雷是字符‘1’,因此当我们计算地雷的个数,就可以将他们直接相加然后减去48即可得到数字的值,而不是字符的值。然后我们再更新show中的字符
//排雷
void find_boom(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int win =COL*ROW- BOOM_COUNT;
while (win > 0)
{
printf("请输入排雷坐标-->: ");
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
if (show[x][y] == '*')
{
if (mine[x][y] != '1')
{
int n = get_boom_num(mine, x, y);
show[x][y] = n + 48;
display_board(show,ROW,COL);
win--;
}
else
{
printf("你踩雷了!");
break;
}
}
else
{
printf("该坐标已经被排查!\n");
}
}
if (win > 0)
printf("排雷失败,游戏结束!\n");
else
printf("排雷成功,游戏结束!\n");
}
因为我们get_boom_num()的返回类型是int,即为数字的值,而我们要打印的是字符,因此要再n的基础上加上48,得到字符数字,通过ascii表应该能够比较好的理解。然后我们设置一个int win(行x列-设置的地雷,即可得到无雷的坐标个数),用来判断游戏的进行状况 ,逻辑与设置地雷的判断条件类似,每当我们判断成功,win就会减小,知道排完地雷,或者踩雷。
总结
其中还要很多不足,还请给位大佬多多指正!
还请大家多多一键三连!
最后是所有代码汇总
//game.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
//菜单
void menu()
{
printf("-------扫雷游戏-------\n");
printf("----------------------\n");
printf("---- 1.play ----\n");
printf("----------------------\n");
printf("---- 0.exit ----\n");
printf("----------------------\n");
printf("----------------------\n");
}
//初始化棋盘
void init_board(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 display_board(char board[ROWS][COLS], int row, int col)
{
printf(" |-----Gaming-----|\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");
}
printf(" |-----Gaming-----|\n");
}
//设置地雷
void set_boom(char mine[ROWS][COLS],int row, int col)
{
int x = 0;
int y = 0;
int count = BOOM_COUNT;
while (count> 0)
{
x = rand() % row + 1;
y = rand() % col + 1;
if (mine[x][y] != '1')
{
mine[x][y] = '1';
count--;
}
}
}
//排雷
void find_boom(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int win =COL*ROW- BOOM_COUNT;
while (win > 0)
{
printf("请输入排雷坐标-->: ");
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
if (show[x][y] == '*')
{
if (mine[x][y] != '1')
{
int n = get_boom_num(mine, x, y);
show[x][y] = n + 48;
display_board(show,ROW,COL);
win--;
}
else
{
printf("你踩雷了!");
break;
}
}
else
{
printf("该坐标已经被排查!\n");
}
}
if (win > 0)
printf("排雷失败,游戏结束!\n");
else
printf("排雷成功,游戏结束!\n");
}
//判断坐标周围地雷个数
int get_boom_num(char mine[ROWS][COLS],int x,int y)
{
return
mine[x - 1][y] + mine[x + 1][y]
+ mine[x][y - 1] + mine[x][y + 1]
+ mine[x - 1][y + 1] + mine[x - 1][y - 1]
+ mine[x + 1][y + 1] + mine[x + 1][y - 1]
- 8 * 48;
}
void game()
{
char mine[ROWS][COLS] = { 0 };//用于记录雷
char show[ROWS][COLS] = { 0 };//用于展示棋盘
init_board(mine, ROWS, COLS, '0');
init_board(show, ROWS, COLS, '*');
//设置地雷
srand((unsigned int)time(NULL));
set_boom(mine, COL, ROW);
display_board(mine, ROW, COL);
display_board(show, ROW, COL);
find_boom(mine, show, ROW, COL);
}
//game.h
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define BOOM_COUNT 70
void menu();//菜单
void game();//游戏主流程
void init_board(char board[ROWS][COLS], int rows, int cols,char set);//初始化棋盘
void display_board(char board[ROWS][COLS], int row, int col);//打印棋盘
void set_boom(char mine[ROWS][COLS], int row, int col);//设置地雷
void find_boom(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);//排雷操作
int get_boom_num(char mine[ROWS][COLS],int x,int y);//获取坐标周围地雷个数
//main.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
int main()
{
int input = 1;
while (input)
{
menu();
printf("请输入—>: ");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("已退出游戏\n");
return;
default:
break;
}
}
return 0;
}