在写代码之前,首先我们要了解清楚这个游戏的玩法,没玩过扫雷的朋友可以去扫雷游戏网页版 - Minesweeper试玩一下。
游戏玩法是这样的:在9*9格子上用鼠标随意点击一个位置,保证第一次不会是雷,并且会以点击的位置为中心,查找其周围格子是否有雷,没有雷的位置直接被触发,然后重复(以没有雷的位置为中心查找周围格子是否有雷的操作),这样就呈现出了上图(第一次点击)的效果。
作为入门学习我们这里只做一个简单的黑白简易游戏(实际效果见上图),相对原版游戏少了标记雷、自动查找并展开周围没有雷的区域以及不能保证第一次不踩雷的功能,下面介绍整体游戏设计思路。
1.打印菜单,询问是否开始游戏
2.初始化棋盘,游戏中的网格(以下称棋盘)其实就是二维数组,这是游戏的关键。
3.打印棋盘:初始化棋盘之后需要实现打印棋盘功能
4.布置雷并实现统计雷功能
5.排查雷并判断输赢
以下进行详细介绍。
首先我们新建两个.c文件,分别命名为game.c和test.c方便后续功能实现以及测试,并且创建game.h头文件
在test.c文件下存放着主函数,也就是游戏的主体框架,使用do while循环语句和switch语句实现游戏可以一直玩,除非玩家选择退出游戏。
int main()
{
int input = 0;
do {
menu();//打印菜单
printf("your chose:");
scanf("%d", &input);//用户输入选择
switch (input)
{
case 1://输入1,进入游戏
game();
break;
case 0://输入0,退出游戏
printf("exit");
break;
};
} while (input);
return 0;
}
进入游戏函数后,定义两个11*11的二维数组,分别用来存放雷和玩家排查雷之后的信息(用户选择的位置无雷即显示该位置周围八个坐标内雷的个数的总和(可为0-8),有雷则显示整个棋盘雷的布局)。从上图显示的游戏运行效果来看棋盘大小为9*9,但是这里为设置二维数组大小为11*11的原因是:对于一个9*9(共81个空)的棋盘而言,在玩家进行游戏时,可以选择棋盘上任意一个位置,如下图为第一种情况(先忽略外围蓝色格子),即在9*9棋盘内部选择的一个位置,如果该位置无雷,遍历该位置周围八个位置,统计这八个位置雷的个数并将数量保存在该位置。
第二种情况如下图所示,用户选择的是9*9边缘的位置,此时该位置若无雷仍要统计其周围雷的个数,若数组仅为9*9数组,则会造成越界访问,因此定义为11*11数组。
数组初始化这里使用简单的for循环,将两个数组的元素分别赋值为0和*。
//数组初始化
void InitBoard(char board[ROWS][COLS],int rows,int cols,int a)
{
int i = 0;
for (i = 0; i < ROWS; i++)
{
int j = 0;
for (j = 0; j < COLS; j++)
{
if (a ==1)
board[i][j] ='0';//放置雷的棋盘初始化为0
else
board[i][j] = '*';//排查之后的棋盘初始化为*
}
}
}
接着实现棋盘打印功能,为了让玩家有更好的游戏体验,这里我们在棋盘的第一行以及第一列打印坐标,其余位置全为*,如下图所示。
该部分具体代码如下
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
for (i = 0; i <= ROW; i++)
{
printf("%d ", i);//打印第一列
//打印第一行
if (i == 0)
{
int j = 0;
for (j = 1; j <= COL; j++)
{
printf("%d ", j);
}
}
else
{
int j = 0;
for (j = 1; j <= COL; j++)
{
printf("%c ", board[i][j]);
}
}
printf("\n");
}
printf("\n");
}
在原版的扫雷游戏中,9*9的棋盘中布置了10个雷(如下图所示),因此这里我们也仿照原版游戏在棋盘上布置10个雷(当然雷的个数可以根据自己喜好设置)。这里需要用到随机函数rand来随机生成雷的坐标,rand函数需要调用srand作为种子,我们常用系统时间作为种子以保证每次生成的随机数不一致,用法为:srand((unsigned int)time(NULL))。
具体代码如下
//布置雷
void Setmine(char mine[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = 0;
while (count < 10)
{
x = rand() % ROW + 1;/*生成随机数范围是0-9,但是在11*11的二维数组上棋盘的坐标是1-10*/
y = rand() % COL + 1;
if ('1' != mine[x][y])//判断该位置是否已经布置过雷
{
mine[x][y] = '1';
count++;
}
}
}
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <time.h>
#define ROW 9//定义二维数组的行数 方便后期修改
#define COL 9//定义二维数组的列数 方便后期修改
#define ROWS ROW+2
#define COLS COL+2
void menu();//实现游戏开头菜单功能
void game();
void InitBoard(char board[ROWS][COLS], int rows, int cols,int a);//初始化棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);//打印棋盘
void Setmine(char mine[ROWS][COLS], int row, int col);//布置雷
void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col);//找雷
布置完雷之后,需要实现对某个无雷的坐标周围八个坐标雷的个数的统计功能,这里对(x,y)周围的八个坐标进行排查,由于在布置雷阶段我们将雷赋值为字符1,字符在计算机中以转化成ASCII码储存,统计雷时我们需要的是雷的数量,数字0和字符0以及数字1和字符1都相差48,即一个字符0的大小,因此返回雷的数量时需要减去8个字符0的大小。
//统计雷
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 FindMine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col)
{
while (1)
{
int x = 0;
int y = 0;
int count = 0;//判断是否找完了71个非雷的格子
printf("Please enter the position coordinates to exclude:");
scanf("%d%d", &x, &y);//玩家输入坐标
//判断坐标合法性
if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
{
if ('1' == mine[x][y])
{
printf("sorry,you lose\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
show[x][y] = Get_Mine_count(mine,x,y)+'0';//还需要将数字转换为字符
count++;
if (71 == count)
{
printf("Congratuation! you win\n");
}
DisplayBoard(show, ROW, COL);
}
}
else
printf("Coordinates are invalid, please re-enter");
}
}
完整代码如下
game.h
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//打印菜单
void menu();
void game();
void InitBoard(char board[ROWS][COLS], int rows, int cols,int a);
void DisplayBoard(char board[ROWS][COLS], int row, int col);
void Setmine(char mine[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 menu()
{
printf("**************************************\n");
printf("*********welcome to this game*********\n");
printf("*****plesse give your chose:0/1*******\n");
printf("**************************************\n");
}
//数组初始化
void InitBoard(char board[ROWS][COLS],int rows,int cols,int a)
{
int i = 0;
for (i = 0; i < ROWS; i++)
{
int j = 0;
for (j = 0; j < COLS; j++)
{
if (a ==1)
board[i][j] ='0';
else
board[i][j] = '*';
}
}
}
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
for (i = 0; i <= ROW; i++)
{
printf("%d ", i);
if (i == 0)
{
int j = 0;
for (j = 1; j <= COL; j++)
{
printf("%d ", j);
}
}
else
{
int j = 0;
for (j = 1; j <= COL; j++)
{
printf("%c ", board[i][j]);
}
}
printf("\n");
}
printf("\n");
}
//布置雷
void Setmine(char mine[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = 0;
while (count < 10)
{
x = rand() % ROW + 1;
y = rand() % COL + 1;
if ('1' != mine[x][y])
{
mine[x][y] = '1';
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 FindMine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col)
{
while (1)
{
int x = 0;
int y = 0;
int count = 0;//判断是否找完了71个非雷的格子
printf("Please enter the position coordinates to exclude:");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
{
if ('1' == mine[x][y])
{
printf("sorry,you lose\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
show[x][y] = Get_Mine_count(mine,x,y)+'0';
count++;
if (71 == count)
{
printf("Congratuation! you win\n");
}
DisplayBoard(show, ROW, COL);
}
}
else
printf("Coordinates are invalid, please re-enter");
}
}
//判断玩家赢了
void game()
{
srand((unsigned int)time(NULL));
char Mine[ROWS][COLS] = {0};
char Show[ROWS][COLS] = {0};
InitBoard(Mine, ROWS, COLS,1);
InitBoard(Show, ROWS, COLS,0);
//DisplayBoard(Mine, ROW, COL);
DisplayBoard(Show, ROW, COL);
Setmine(Mine, ROW, COL);
/*DisplayBoard(Mine, ROW, COL);*/
FindMine(Mine,Show, ROW, COL);
}
test.c
#include "game.h"
int main()
{
int input = 0;
do {
menu();
printf("your chose:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("exit");
break;
};
} while (input);
return 0;
}