标准的扫雷游戏规则如下:第一次点击不会是雷。格子里的数字表示它周围有几个雷。游戏目标是找出所有雷。"触雷"则输。点击表情重新开始。二选一留到最后,可任选,需先清完其他方块。第一次点击不会是雷。格子里的数字表示它周围有几个雷。游戏目标是找出所有雷。"触雷"则输。点击表情重新开始。二选一留到最后,可任选,需先清完其他方块。
这里仅仅利用C语言数组与函数结合制作简易版扫雷游戏这里并没有考虑扫雷游戏的扩展:是否可以选择游戏难度,如果排查位置不是雷,周围也没有雷,可以展开周围的一片,是否可以标记雷,是否可以加上排雷的时间显示,
扫雷游戏的功能说明:
1、使用控制台实现经典的扫雷游戏时,游戏可以通过菜单实现继续玩或者退出游戏
2、扫雷的棋盘是9*9的格⼦
3、默认随机布置10个雷
4、可以排查雷,如果位置不是雷,就显示周围有几个雷,如果位置是雷,就炸死游戏结束。
5、 把除10个雷之外的所有非雷都找出来,排雷成功,游戏结束
扫雷游戏的思路说明,和上述功能匹配:
使用test.c即main函数来测试游戏的逻辑,(game.h函数声明,game.c函数的实现)来完成游戏实现
1、使用do-while循环及switch分支选择制作菜单选择,菜单界面放入函数menu()
//test.c
#include<stdio.h>
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");
break;
}
} while (input);
return 0;
}
2、使用9*9的棋盘布置雷和排查雷,需要使用9*9的二维数组来存放数据,可以设置为0不是雷,1是雷,但是这和排雷的时候当前位置显示的雷的个数产生歧义,不能确定是雷还是1个雷
因此有两种方法:
①在一个棋盘布置雷时,可以用不同符号代表雷非雷还是类的个数,这种方法很凌乱。
②再创建一个数组,即搞两个棋盘,一个是布置雷的信息mine,另一个是排查出的雷的信息show,分离出来。
这里采用方法②
第一步,设置两个棋盘,布置雷mine,排查雷,show。
第二步,确定棋盘大小并布局:为了防止在排查雷的时候,某个坐标周围的8个坐标有越界的可能性(因为需要统计周围8个坐标,最外边不够,部分没在数组内),并考虑到协同,需将两个棋盘棋盘扩大一圈11*11的棋盘,因此创建char[11][11]类型数组,同时设置初始化函数InitBoard(),分别导入字符0和字符*,令一开始布置雷的棋盘全是字符0,排查雷的棋盘全是*(未排查出)。后续布置及排查出的雷是字符1,非雷字符0。
test.c
void game()
{
char mine[11][11] = { 0 };
char show[11][11] = { 0 };
//初始化棋盘
InitBoard(mine, 11, 11, '0');//用来存放布置好的雷的信息 '0'
InitBoard(show, 11, 11, '*');//用来存放排查出的雷的信息 '*'
}
game.c
void InitBoard(char board[11][11], int rows, int cols, char set)
{
int i = 0;
for (i = 0; i <= rows; i++)
{
int j = 0;
for (j = 0; j <= cols; j++)
{
board[i][j]= set;
}
}
}
game.h
void InitBoard(char board[11][11], int rows, int cols, char set);//初始化棋盘
第三步,设置打印棋盘函数DisplayBoard(),可以使每次排查之后都看一下显示效果,但要显示9*9的,因为游戏界面就是9*9,可以加入行号和列号
这里考虑到棋盘的扩大,棋盘的行列采用宏定义,规定原棋盘行ROW,列COL,并且扩大后的棋盘ROWS,COLS是(ROW及COL)+2
test.c
void game()
{
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化棋盘
InitBoard(mine, ROWS, COLS, '0');//用来存放布置好的雷的信息 '0'
InitBoard(show, ROWS, COLS, '*');//用来存放排查出的雷的信息 '*'
//打印棋盘
DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
}
game.c
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("--------扫雷--------\n");
for (i = 0; i <= col; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);
for(j = 1;j <= col;j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("--------扫雷--------\n");
}
game.h
#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);
3、随机布置雷,布置及排查出的雷是字符1,非雷字符0。需设置新函数SetMine(),采用rand函数,并用srand和time函数返回时间戳生成随机值,设置雷的个数为10,在mine棋盘中设置行列都是1到9处生成随机的下标,共10个雷(字符1),1+模9即可,如果坐标不是1则放一个雷即1进去,然后雷的数减一即可,同时用打印棋盘查看雷怎么布置
test.c
//完成扫雷游戏的测试
void game()
{
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化棋盘
InitBoard(mine, ROWS, COLS, '0');//用来存放布置好的雷的信息 '0'
InitBoard(show, ROWS, COLS, '*');//用来存放排查出的雷的信息 '*'
//布置雷
SetMine(mine, ROW, COL);
//打印棋盘
DisplayBoard(mine, 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");
break;
}
} while (input);
return 0;
}
game.h
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#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 SetMine(char board[ROWS][COLS], int row, int col);
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);
game.c
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int count = 10;
while (10)
{
//生成随机的下标,x:1~9,y:1~9
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] != '1')
{
mine[x][y] = '1';
count--;
}
}
}
4、设置排查雷,需设置新函数FindMine(),在棋盘mine里排查把结果放到show里去,每次输入坐标,判断坐标是否合理,(在设置的9*9棋盘内,合理的情况下,如果是字符1,是雷的情况下,提示被炸死了,告知雷的信息,如果不是雷,告知还要排查几个雷,并统计该坐标周围8个坐标中雷的个数,此时需要再设置新函数GetMineCount,返回值即是该坐标周围雷的个数, 令中间的数坐标为x,y并表示周围的8个坐标,每个坐标减去字符0再加起来,也就是8个坐标加起来-8个字符0,也可以两次for循环使得9个坐标位置都-字符0再相加, 返回后在令show数组的这个位置加上字符0,变成了字符的几个雷,并打印出来显示该位置几个雷,很巧妙。)如果坐标不合理,则告知输入错误,请重新输入。
5、再设置约束条件,如果是字符数小于了9*9-10=71则继续排雷,否则就排雷成功,打印雷的位置图,此时若要快速验证可以宏定义雷的个数为COUNT,此时约束条件可变为字符数小于ROW*COL-COUNT并设置80来简单验证功能是否实现。
game.h
#pragma once
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 9//宏定义
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define COUNT 10
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
//布置雷
void SetMine(char board[ROWS][COLS], int row, int col);
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int 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] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化棋盘
InitBoard(mine, ROWS, COLS, '0');//用来存放布置好的雷的信息 '0'
InitBoard(show, ROWS, COLS, '*');//用来存放排查出的雷的信息 '*'
//打印棋盘
/*DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);*/
//布置雷
SetMine(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
//排查雷
FindMine(mine, show, ROW, COL);
//DisplayBoard(mine, 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");
break;
}
} while (input);
return 0;
}
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
for (i = 0; i <= rows; i++)
{
int j = 0;
for (j = 0; j <= cols; j++)
{
board[i][j]= set;
}
}
}
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("--------扫雷--------\n");
for (i = 0; i <= col; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);
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 count = COUNT;
while (count)
{
//生成随机的下标,x:1~9,y:1~9
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] != '1')
{
mine[x][y] = '1';
count--;
}
}
}
//获取附近8格雷的数量
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
int i = 0;
int r = 0;
for (i = -1; i <= 1; i++)
{
int j = 0;
for (j = -1; j <= 1; j++)
{
r = r + mine[x + i][y + j] - '0';
}
}
return r;
}
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = 0;
while (count<ROW*COL-COUNT)
{
printf("请输入要排查的坐标");
scanf("%d %d", &x, &y);
if (x <= row && x > 0 && y <= col && y>0)
{
if (mine[x][y] == '1')
{
printf("你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
count++;
printf("你还要排查%d个坐标\n", ROW * COL - COUNT - count);
int r = GetMineCount(mine, x, y);//统计x,y坐标周围8个坐标中雷的个数
show[x][y] = r + '0';
DisplayBoard(show, ROW, COL);
}
}
else
{
printf("输入的坐标有误,请重新输入\n");
}
}
if (count == row * col - COUNT)
{
printf("恭喜你,排雷成功\n");
DisplayBoard(mine, ROW, COL);
}
}
注:运行时若显示此类报错
项目-属性-配置属性-C/C++ -代码生成 -基本运行时检查,选择默认值就不会报错