#define定义变量; 函数的声明与定义; 分支语句if(){}...else...,switch; 循环语句while(),for(;;),do...while(); for的嵌套; 头文件的创建和使用 ; 自定义函数; return语句的用法;操作符的用法;随机数的生成(rand)与(srand);时间戳time;二维数组的用法以及字符到数字的转换
使用控制台实现经典的扫雷游戏
• 游戏可以通过菜单实现继续玩或者退出游戏
• 扫雷的棋盘是9*9的格⼦
• 默认随机布置10个雷
• 可以排查雷。如果位置不是雷,就显示周围有几个雷
◦ 如果位置是雷,就炸死游戏结束
◦ 把除10个雷之外的所有雷都找出来,排雷成功,游戏结束
首先我们创建两个源文件game.c与test.c分别用来写功能函数的实现和主函数。
因为我们需要代码量对初学的人来说有点大所以我们创建一个头文件game.h。把函数的声明放入里面,方便阅读和维护,头文件的包含都放在game.c中。
首先,我们需要先做一个页面让玩家选择玩游戏(1)还是退出游戏(0),我们就用到了自定义函数menu(),do-while()循环和switch选择,代码如下:
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");
}
} while (input);
return 0;
}
我们定义了一个int型的变量input并给它初始化为0,然后用scanf函数接收它这时玩家就可以通过输入1或0来选择玩游戏还是退出游戏。这样最开始的界面就完成了。
game()函数中需要我们去//创建棋盘//初始化棋盘//打印棋盘//设置雷//排查雷。
扫雷的过程中,布置的雷和排查出的雷的信息都需要存储,而且扫雷是在一个正方形的棋盘里面进行的,所以我们需要用二维数组(行和列)来存储这些信息。
我们需要在9*9的棋盘上布置雷的信息和排查雷,我们⾸先想到的就是创建⼀个9*9的数组来存放 信息。但是如果是9*9的棋盘上布置雷的话后面排查就会造成数组越界的问题,所以我们就在它旁边再加上一圈变成11*11的棋盘来帮助我们进行排雷操作。如果这个位置布置雷,我们就存放1,没有布置就存放0。
如果我们只创建一个棋盘,在我们设置雷时需要设置的是'1',在排查雷的时候我们所要排查的也是'1',这会使得冲突所以我们需要俩个棋盘,一个用来显示,一个用来埋雷。
game()函数代码如下:
void game()
{
char mine[ROWS][COLS];//存放布置好的雷
char show[ROWS][COLS];//存放排查出的雷的信息
//初始化棋盘
//1. mine数组最开始是全'0'
//2. show数组最开始是全'*'
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//打印棋盘
//DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
//1. 布置雷
SetMine(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL);
//2. 排查雷
FindMine(mine, show, ROW, COL);
}
我们也需要在game.h头文件中声明这些功能函数,所以在game.h中我们编写的代码如下:
#pragma once
#include
#define EASY_COUNT 10
#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 board[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
这时我们是不是思路很清晰了,只需要再在game.c中实现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;
}
}
}
在这里我们设置的字符变量set是为了方便我们用"*"或"0"来传入初始化函数中,主函数中初始化代码是:
//初始化棋盘
//1. mine数组最开始是全'0'
//2. show数组最开始是全'*'
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
这样设置还可以帮助我们后期调试和维护代码。
为方便我们玩游戏时能够看出在哪一行哪一列,我们在棋盘的上面和左边用for循环输出行和列的数字。具体代码如下:
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]);
}
printf("\n");
}
printf("--------适度娱乐-------\n");
页面实现:
我们将要在9*9的mine数组棋盘里设置雷,字符'1'表示雷,字符'0'不是雷,那我们该如何实现。首先我们需要一个随机的坐标[x][y]埋雷,想要做到随机那我们就需要用到随机数,接下来我们介绍如何产生随机数。我们需要用到一个函数rand();同时需要时间戳time与srand来使得rand是随机的。如下:
srand、rand需要
#include
#include
#include
srand((unsigned int)time(NULL));
int x = rand();
int y = rand();
虽然我们产生了随机数,但是这个随机数不能超出范围。所以我们给它取模(就是除以一个数后它的余数)% 将它限定到1-9范围内
int x = rand()%9+1;//因为任意的一个正整数它取模后都是0-8;则加1就是1-9;
int y = rand()%9+1;
有些同学可能理解不了所以我为大家准备了关于随机数方便记忆的万能公式:
a到b的随机数公式:a+rand()%(b-a+1);
这样就简单多了,直接套用。
设置雷的具体代码如下:
void SetMine(char board[ROWS][COLS], int row, int col)
{
//布置10个雷
//⽣成随机的坐标,布置雷
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
排查雷我们需要排查玩家输入位置的一圈8个位置,所以我们定义了一个函数GetMineCount()来返回周围8个位置的雷的个数。具体代码如下:
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
return (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] + mine[x - 1][y + 1] - 8 * '0');
}
需要注意的是:我们定义的二位数组是字符型,所以需要把字符型转变成整型来显示周围雷的个数,这时我们就用到了"0",用字符减去'0'(因为大于'0'的ASCⅡ值减去'0'的差值刚好等于相差的数字)就得到了周围的雷数。
我们用while和if-else的循环嵌套来实现排查雷的操作,需要注意的是如果找了71次还没有选到雷,就意味着剩下的10个都是雷,所以"恭喜你,排雷成功"。
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 - EASY_COUNT)
{
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 - EASY_COUNT)
{
printf("恭喜你,排雷成功\n");
DisplayBoard(mine, ROW, COL);
}
}
game.h:
#pragma once
#include
#include
#include
#define EASY_COUNT 10
#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 board[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
game.c:
#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)
{
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]);
}
printf("\n");
}
printf("--------适度娱乐-------\n");
}
void SetMine(char board[ROWS][COLS], int row, int col)
{
//布置10个雷
//⽣成随机的坐标,布置雷
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
return (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] + mine[x - 1][y + 1] - 8 * '0');
}
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 - EASY_COUNT)
{
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 - EASY_COUNT)
{
printf("恭喜你,排雷成功\n");
DisplayBoard(mine, ROW, COL);
}
}
test.c:
#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];//存放排查出的雷的信息
//初始化棋盘
//1. mine数组最开始是全'0'
//2. show数组最开始是全'*'
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//打印棋盘
//DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
//1. 布置雷
SetMine(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL);
//2. 排查雷
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");
}
} while (input);
return 0;
}
大家可以愉快的玩耍了,在快乐的同时体会编程的思想,这样你对编程的热爱会让你走的更远。如果大家有不理解的地方可以收藏这篇文章反复观看,希望对未来编程界的大佬有所帮助,一起加油