🎯每日努力一点点,技术进步看得见
🏠专栏介绍:【C语言步行梯】专栏用于介绍C语言相关内容,每篇文章将通过图片+代码片段+网络相关题目的方式编写,欢迎订阅~~
文章目录
- 需求分析
- 具体实现
- 主函数体
- 菜单实现
- 游戏实现
- 计算雷数量
- 盘面设计
- 初始化盘面
- 显示盘面
- 布置雷
- 排雷函数
- 游戏函数主体
- 完整代码
- 分文件编写
需求分析
以前Windows都会自带一款有趣的游戏,叫做扫雷。今天我们就一起使用C语言来实现一下这个经典的游戏。
下图演示的是一个9×9的盘面,其中含有10个雷。我们可以看到部分方格中含有数字,以图中红色数字2为例,它所在的9宫格已被涂成黄色。在它所在9宫格范围内有2个雷,故该位置有雷。
在开始的时候棋盘上已经埋藏好了雷,但玩家不知道雷的具体位置。在玩家点击不是雷的位置后,该位置将显示9宫格范围内的雷的数量。在玩家找出所有不是雷的位置后,玩家获胜。如果不慎点击到雷所在位置,则游戏结束。
举个例子吧!如下图,没有数字的位置是我们还未点击,且不知道是否有雷的区域。有数字的方格是已经点击,并且没有雷的位置。由于有数字的已经点击了,且保证其中没有雷。而1所在9宫格内必定有1个雷,故绿色箭头所指区域一定是雷。我们不能点击这个区域,否则游戏结束。
具体实现
主函数体
在主函数体内,我们需要调用一个menu函数,用它提醒用户:输入1开始游戏,输入0退出游戏。接收用户输入后,通过switch语句,执行game()函数或者退出游戏。menu和game函数将在下文中讲解。
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");
}
}while(input);
return 0;
}
菜单实现
首先,我们需要一个菜单,提示用户:输入1可以开始游戏,输入0会退出游戏。我通过封装一个menu函数实现↓↓↓
void menu()
{
printf("**************************************************************\n");
printf("******************* 1.play 0.exit *********************\n");
printf("**************************************************************\n");
}
游戏实现
计算雷数量
由上面的需求可以知道,玩家在输入某个坐标后,如果该位置没有雷,则需要在该坐标位置显示其所在9宫格内雷的数量。
如下图所示,若用户输入(3,3)坐标时,我们需要统计该坐标所在9宫格内雷的数量。即将数组中的(mine[1][1]+mine[1][2]+mine[1][3]+mine[2][1]+mine[2][3]+mine[3][1]+mine[3][2]+mine[3][3])-'0'*8
的数值计算出来即可。
★ps:这里的mine数组存储的字符,所以在8个坐标相加后,需要减’0’*8。如果用户输入的坐标是雷,则游戏结束,不需要统计雷的数量,所以这里不需要统计用户输入的坐标内是否有雷。
但如果玩家输入的坐标是(1,1)时,此时数组将会越界。为了保证数组不越界,我们将原本为9×9的盘面,使用11×11的数组来存储。(下图中,红色字符0,表示的是多开辟的空间)。
经过上面的分析后,我们可以写出如下计算雷的函数↓↓↓
int getMindCount(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]) - '0' * 8;
}
盘面设计
我们需要一个mine数组记录我们买下的雷的位置(如下图左侧所示)。为了不让用户看到雷的位置,我们需要另个数组,用于显示用户已经点击的位置,并将其展示给用户。
关于show数组,这里需要额外说明一下。假如用户输入坐标(1,1),此时需要判断mine[1][1]处是否有雷,如果有雷,则游戏结束;如果没有雷,且用户还有将所有没有雷的区域点击完,则游戏继续。在该区域没有雷的情况下,需要调用getMineCount(mine,1,1),计算该位置的雷数量,并将show[1][1]改为雷的数量。
初始化盘面
show数组显示给用户看前,均初始化为’*‘(星号)。而mine数组用于存储雷,在布置雷之前,应全部初始化为’0’(字符0表示没有雷,字符1表示有雷)。因此,我们需要实现一个初始化盘面的函数↓↓↓
//初始化盘面
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 rows, int cols)
{
for (int i = 1; i < rows - 1; i++)
{
if (i == 1)
{
for (int j = 0; j < cols - 1; j++)
{
if (j == 1)
printf(" ");
printf("%2d", j);
}
printf("\n");
}
printf("%2d ", i);
for (int j = 1; j < cols - 1; j++)
{
printf( " %c", board[i][j]);
}
printf("\n");
}
}
其展示效果如下:
布置雷
在游戏前,我们需要给mine数组设置雷。需要使用到随机数函数rand()。其实现代码如下↓↓↓
void setMine(char board[ROWS][COLS], int rows, int cols)
{
int mine = MINE;
while (mine)
{
int x = rand() % rows + 1;
int y = rand() % cols + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
mine--;
}
}
}
排雷函数
我们需要一个函数,用于与玩家进行交互,接受玩家输入的坐标,检查该坐标是否有雷。如果该坐标没有雷,则检查所有非雷坐标是否均被点击,如果均被点击,则玩家获胜;如果未全部点击,则游戏继续。如果该坐标有雷,则玩家游戏失败。
void findMine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols)
{
int min = (rows - 2) * (cols - 2) - MINE;
int x = 0;
int y = 0;
do
{
displayBoard(show, ROWS, COLS);
printf("请输入排雷坐标>");
scanf("%d %d", &x, &y);
if (x >= 0 && x <= rows && y >= 0 && y <= cols)
{
if (mine[x][y] == '1')
{
printf("挑战失败,您被炸死了!\n");
break;
}
else
{
int count = getMindCount(mine, x, y);
show[x][y] = '0' + count;
min--;
}
}
else
{
printf("输入的坐标有误,请重新输入\n");
}
} while (min);
if (min == 0)
printf("恭喜你!排雷成功!\n");
}
游戏函数主体
在实现了上述各个函数后,我们只要稍加组织,就可以实现游戏了。
void game()
{
char mine[ROWS][COLS];//存储雷
char show[ROWS][COLS];//显示给用户看的
//初始化盘面
initBoard(mine, ROWS, COLS, '0');
initBoard(show, ROWS, COLS, '*');
//布置雷
setMine(mine, ROW, COL);
//开始排除雷
findMine(mine, show, ROWS, COLS);
}
完整代码
上面代码中主函数中没有加入随机数种子,在下面代码中加入了srand((unsigned int)time(NULL))
,同时对于上面出现ROW、COL的宏定义等也在下方代码整体给出。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 9
#define COL 9
#define MINE 10
#define ROWS (ROW+2)
#define COLS (COL+2)
void menu()
{
printf("**************************************************************\n");
printf("******************* 1.play 0.exit *********************\n");
printf("**************************************************************\n");
}
//初始化盘面
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 rows, int cols)
{
for (int i = 1; i < rows - 1; i++)
{
if (i == 1)
{
for (int j = 0; j < cols - 1; j++)
{
if (j == 1)
printf(" ");
printf("%2d", j);
}
printf("\n");
}
printf("%2d ", i);
for (int j = 1; j < cols - 1; j++)
{
printf( " %c", board[i][j]);
}
printf("\n");
}
}
//埋雷
void setMine(char board[ROWS][COLS], int rows, int cols)
{
int mine = MINE;
while (mine)
{
int x = rand() % rows + 1;
int y = rand() % cols + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
mine--;
}
}
}
//计算雷的数量
int getMindCount(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]) - '0' * 8;
}
//找雷
void findMine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols)
{
int min = (rows - 2) * (cols - 2) - MINE;
int x = 0;
int y = 0;
do
{
displayBoard(show, ROWS, COLS);
printf("请输入排雷坐标>");
scanf("%d %d", &x, &y);
if (x >= 0 && x <= rows && y >= 0 && y <= cols)
{
if (mine[x][y] == '1')
{
printf("挑战失败,您被炸死了!\n");
break;
}
else
{
int count = getMindCount(mine, x, y);
show[x][y] = '0' + count;
min--;
}
}
else
{
printf("输入的坐标有误,请重新输入\n");
}
} while (min);
if (min == 0)
printf("恭喜你!排雷成功!\n");
}
//游戏
void game()
{
char mine[ROWS][COLS];//存储雷
char show[ROWS][COLS];//显示给用户看的
//初始化盘面
initBoard(mine, ROWS, COLS, '0');
initBoard(show, ROWS, COLS, '*');
//布置雷
setMine(mine, ROW, COL);
//开始排除雷
findMine(mine, show, ROWS, COLS);
}
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");
}
} while (input);
return 0;
}
分文件编写
可以创建game.h保存头文件,及各函数的函数声明;game.c保存各个函数的具体实现;main.c中保存主函数。
game.h ↓↓↓
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 9
#define COL 9
#define MINE 10
#define ROWS (ROW+2)
#define COLS (COL+2)
//菜单
void menu();
//初始化盘面
void initBoard(char board[ROWS][COLS], int rows, int cols, char set);
//显示盘面
void displayBoard(char board[ROWS][COLS], int rows, int cols);
//埋雷
void setMine(char board[ROWS][COLS], int rows, int cols);
//计算雷的数量
int getMindCount(char board[ROWS][COLS], int x, int y);
//找雷
void findMine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols);
//游戏
void game();
game.c ↓↓↓
#include "game.h"
void menu()
{
printf("**************************************************************\n");
printf("******************* 1.play 0.exit *********************\n");
printf("**************************************************************\n");
}
//初始化盘面
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 rows, int cols)
{
for (int i = 1; i < rows - 1; i++)
{
if (i == 1)
{
for (int j = 0; j < cols - 1; j++)
{
if (j == 1)
printf(" ");
printf("%2d", j);
}
printf("\n");
}
printf("%2d ", i);
for (int j = 1; j < cols - 1; j++)
{
printf( " %c", board[i][j]);
}
printf("\n");
}
}
//埋雷
void setMine(char board[ROWS][COLS], int rows, int cols)
{
int mine = MINE;
while (mine)
{
int x = rand() % rows + 1;
int y = rand() % cols + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
mine--;
}
}
}
//计算雷的数量
int getMindCount(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]) - '0' * 8;
}
//找雷
void findMine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols)
{
int min = (rows - 2) * (cols - 2) - MINE;
int x = 0;
int y = 0;
do
{
displayBoard(show, ROWS, COLS);
printf("请输入排雷坐标>");
scanf("%d %d", &x, &y);
if (x >= 0 && x <= rows && y >= 0 && y <= cols)
{
if (mine[x][y] == '1')
{
printf("挑战失败,您被炸死了!\n");
break;
}
else
{
int count = getMindCount(mine, x, y);
show[x][y] = '0' + count;
min--;
}
}
else
{
printf("输入的坐标有误,请重新输入\n");
}
} while (min);
if (min == 0)
printf("恭喜你!排雷成功!\n");
}
//游戏
void game()
{
char mine[ROWS][COLS];//存储雷
char show[ROWS][COLS];//显示给用户看的
//初始化盘面
initBoard(mine, ROWS, COLS, '0');
initBoard(show, ROWS, COLS, '*');
//布置雷
setMine(mine, ROW, COL);
//开始排除雷
findMine(mine, show, ROWS, COLS);
}
main.c ↓↓↓
#include "game.h"
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;
}
🚩这篇文章结束了~~
如果文章中出现了错误,欢迎私信或留言。(๑•̀ㅂ•́)و✧
有任何疑问请评论或私信哦~~o( ̄▽ ̄)ブ