一、游戏功能说明
- 使用控制台实现经典的扫雷游戏
- 游戏可以通过菜单实现继续玩或者退出游戏
- 扫雷的棋盘是9*9的格子
- 默认随机布置10个雷
- 如果位置不是雷,就显示周围有几个雷
- 如果位置是雷,就炸死游戏结束
- 把除10个雷之外的所有非雷都找出来
二、扫雷游戏的设计思路
1.前提
涉及打印方形矩阵以及布置雷和排查雷的信息储存,我们可以想到创建二维数组。
在9*9的棋盘上布置雷的信息和排查雷,我们⾸先想到的就是创建⼀个9*9的数组来存放
信息。但是位于四个边缘坐标相邻没有8个元素,因此我们要创建11*11的二维数组,但实际上使用以及打印在控制台只有9*9大小。
如果这个位置布置雷,我就存放字符‘1’,否则存放字符‘0’。另外我们需要将排查出的雷的数量信息记录 存储,并打印出来,作为排雷的重要参考信息,所以数组的类型应该使用字符型。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
1 | |||||||||||
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | ||
3 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | ||
4 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | ||
5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
6 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | ||
7 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | ||
8 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | ||
9 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | ||
10 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | ||
11 |
棋盘上有雷和⾮雷的信息,还有排查出的雷的个数信息
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
1 | |||||||||||
2 | * | * | * | * | * | * | * | * | 1 | ||
3 | * | * | 0 | 0 | * | 1 | * | * | * | ||
4 | * | * | 1 | 1 | * | * | * | * | * | ||
5 | * | * | * | * | * | * | * | * | * | ||
6 | * | 1 | * | * | * | 1 | * | * | * | ||
7 | * | * | 1 | * | * | * | * | * | * | ||
8 | 1 | * | * | * | * | * | 1 | * | * | ||
9 | * | * | 1 | * | * | * | * | * | * | ||
10 | * | * | * | * | * | 0 | 1 | * | * | ||
11 | 空 | 空 | 空 |
2.主函数的创建
我们可以使用多文件的形式实现扫雷游戏:
- saolei.c-----写游戏的逻辑
- game.c-----游戏中函数的实现等
- game.c-----写游戏需要的数据类型和函数声明等
saolei.c
#include "game.h"
void game()
{
char assign[11][11] = { 0 };//布置雷信息的数组
char show[11][11] = { 0 };//扫雷等游戏效果展示的数组Initboard(assign, 11,11,'0');//初始化棋盘
Initboard(show, 11, 11,'*');//初始化棋盘//Displayboard(assign, 9, 9);//查看布置的雷
Setboard(assign, 9, 9);//布置雷Displayboard(show, 9,9);//游戏开始展示界面
Findboard(assign,show, 9,9);//排查雷
}int main()
{
int input;do
{
menu();//菜单函数
printf("选择:");
scanf("%d", &input);
switch (input)
{
case 1:
game();//进入游戏具体功能实现
break;
case 0: //输入0退出游戏并跳出循环
printf("游戏结束。\n");
break;
default:
printf("打错啦。\n");
break;
}
} while (1);
return 0;
}
3.游戏功能实现代码
game.c
#include <stdlib.h>
#include <time.h>
void menu()
{
printf("***************************\n");
printf("********* 1.play ********\n");
printf("********* 0.exit ********\n");
printf("***************************\n");
}//判断坐标相邻的雷的个数
int count(char assign[11][11],int x,int y)
{
int a, b;
a = assign[x - 1][y - 1] + assign[x - 1][y] + assign[x - 1][y + 1] + assign[x][y - 1];
b = assign[x][y + 1] + assign[x + 1][y + 1] + assign[x + 1][y] + assign[x + 1][y + 1];
return a + b-8*'0';
}void Initboard(char board[11][11], int m, int n,char set)//初始化棋盘
{
int i = 0;
for (i = 0; i < 11; i++)
{
int j = 0;
for (j = 0; j < 11; j++)
{
board[i][j] = set;//初始化数组分别为‘0’和‘*'
}
}
}//将控制台输出界面行列化输出
void Displayboard(char board[11][11], int m, int n)
{
int i = 0;
printf("******** 扫雷 *******\n");
for (i = 0; i <= 9; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= 9; i++)
{
printf("%d ", i);
for (int j = 1;j <= 9; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}void Setboard(char assign[11][11], int m, int n)//随机布置雷
{
int num = 10;//雷的个数while (num)
{
int x = rand() % m + 1;
int y = rand() % n + 1;
srand((unsigned int)time(NULL));
if(assign[x][y] == '0')//排除该位置已布置过雷
{
assign[x][y] = '1';
num--;
}
}
}void Findboard(char assign[11][11], char show[11][11], int m, int n)//排查雷
{
int x, y;
int win = 0;//排除不是雷的坐标个数
while(1)
{
printf("请输入排查的坐标:");
scanf("%d %d", &x, &y);
if (x > 0 && x <= m && y > 0 && y <= n)//判断坐标是否越界
{
if (assign[x][y] == '1')
{
printf("你死了\n");
Displayboard(assign, 9, 9);//游戏结束打印全部雷的位置
break;
}
else//如果该位置不是雷,则显示周围雷的个数
{
int d = count(assign,x,y);
show[x][y] = d + '0';
Displayboard(show, 9, 9);//游戏开始展示界面
win++;}
}
else
{
printf("错误,重新输入");
}
}
int num = 10;
if ( win==m * n - num)//当排除了除雷外的坐标即胜利
{
printf("胜利");
Displayboard(assign, 9, 9);
}
}
4.游戏实现函数的声明
game.h
#include <stdio.h>
void menu();//菜单函数
void Initboard(char board[11][11], int m, int n,char set);//初始化棋盘
void Displayboard(char board[11][11],int m, int n);//打印棋盘
void Setboard(char assign[11][11], int m, int n);//布置雷
void Findboard(char assugn[11][11], char show[11][11], int m, int n);//排查雷
5.代码优化和提升
不难看出我们可以把头文件统一放在game.h函数声明的文件,避免game.c和saolei.c文件都得注明的冗杂。
如果我们想要自定义棋盘大小,可以使用#define给创建的数组定义行和列,如下:
#define ROW 9 //行#define COL 9 //列#define ROWS ROW+2#define COLS COL+2
还有几个游戏功能的扩展:
- 如果排查位置不是雷,周围也没有雷,可以展开周围的⼀⽚
- 是否可以标记雷
- 是否可以加上排雷的时间显示
6敲起来!
看到这里想必你的键盘和双手早已按耐不住,何不妨敲起来,在纯粹的游戏代码中,打开C语言游戏开发的大门。