I have a dream today!
---Martin Luther King
无论是90后还是00后,相信大家都在xp系统上玩过扫雷游戏,我们初中电脑老师神采飞扬的炫耀过自己初级9x9棋盘扫雷成绩,只耗时2秒,问有没有来挑战的,现在想想给你80个雷,你要不猜一下试试吧~
我们设计一个9x9的扫雷棋盘,需要考虑一个问题,当边界区需要排查周围8个区域是否会越界?答案是显然的,因此我们需要在9x9的周围加一个护城河防止数组在判断周围雷区的时候越界,即初始化一个11x11的棋盘。见下图:
首先根据用户的选择进行do…while判断,用户根据菜单进行判断,其他符号都满足while的循环条件,重新进行选择。
接着对棋盘进行初始化:
如果此区域是雷 ---- 用字符‘0’表示
如果此区域非雷 ---- 用字符‘1’表示
但有个问题是我们如果在排雷的过程中发现,此区域周围的八个区域中只有一个雷,那程序如何区分这个‘1’是雷?还是排查后统计出来总的雷的个数呢?
为了解决这个问题我们用两个二维数组进行判断:
问题解决后就可以对数组进行初始化了:
mine棋盘用于存放雷的信息,全部为‘0’
show棋盘用于显示当前所选区域周围雷的个数,全部初始化为’1’
初始化后开始布置雷,这里我们9x9的棋盘,默认雷的个数为10个,随机产生x,y雷的坐标(范围是1~9),放入show棋盘。
我们可以打印出mine,和show棋盘看一下,当然玩家在玩的时候mine棋盘是不能显示的。
Mine棋盘:
Show棋盘:
最后玩家进行雷的排查,具体函数实现见game.c
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
DisplayBoard()函数,注意的棋盘并不是打印11x11的棋盘,玩家只需要看到9x9的,因此我们从第二行第二列开始打印,具体先打印列号,其次打印行号和初始化符号。
SetMine()函数,我们引用头文件#include
产生随机数srand((unsigned int)time(NULL));
, 雷的x,y坐标为int x=rand()%row+1 and int y=rand()%col+1
布置雷前判断一下此区域是否为字符’0’,是则设为’1’
getMineCount()函数,判断此坐标附近把个坐标的位置是否为雷,值得注意的是二维数组内都是用char类型来存储,那么如果是雷怎么转换成数字类型来进行相加呢? 我们知道 0+‘0’ = ‘0’,因为字符’0’被替换成了48,那么四周的八个区域字符进行相加得到的值减去8*'0’就可以得到有几个雷了。
no_mine_spread()函数,如果此区域是’0’,我们就分别去此区域周围的八个区域也进行一次相应的判断,看是否为雷区,如果不是雷,递归下去,直到周围是雷为止,并把当前周围雷的数量show[x][y] = mine进行记录。
game_win()函数,此函数为判断玩家是否胜利,遍历二维数组,判断标记符号或者剩余未踩的区域的数量,如果count和雷的数量相等,恭喜玩家,游戏结束,否则游戏结束
mark_Mine()函数,玩家如果想标记此区域可能是雷,将此区域标记为符号’!’
FIndMine()函数
//
// game.h
// MineSweeper_Game
//
// Created by henry on 2021/5/5.
//
#ifndef game_h
#define game_h
#include
#include
#include
#define MINE_NUM 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
void InitBoard(char board[ROWS][COLS], int row, int col, char set);
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);
#endif /* game_h */
//
// main.c
// MineSweeper_Game
//
// Created by henry on 2021/5/5.
//
#include "game.h"
void callMenu(){
printf("*****************************************\n");
printf("************ 1. Play ************\n");
printf("************ 0. Exit ************\n");
printf("*****************************************\n");
}
void enterGame(){
printf("MineSweeper\n");
char mine[ROWS][COLS] = {
0}; //存放布置好的雷的信息
char show[ROWS][COLS] = {
0}; //存放排查出的雷的信息
//初始化mine棋盘,全部放字符型的'0'
//初始化show棋盘,全部放字符型的'*'
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//开始布置雷
SetMine(mine, ROW,COL);
//打印棋盘
DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
//排查雷
FindMine(mine, show, ROW, COL);
}
int main(int argc, const char * argv[]) {
int input = 0;
srand((unsigned int)time(NULL));
do{
callMenu();
printf("Please Choose :> ");
scanf("%d", &input);
switch (input) {
case 0:
printf("Exit Game\n");
break;
case 1:
enterGame();
break;
default:
printf("Cannot recognise it, Please retry~ \n");
break;
}
}while(input);
return 0;
}
//
// game.c
// MineSweeper_Game
//
// Created by henry on 2021/5/5.
//
#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){
//这里是从第二行第二列开始打印棋盘的
printf("===========GAME==========\n");
//打印列号
for(int i=0; i<=col; ++i){
printf("%d ", i);
}
printf("\n");
for(int i=1; i<=row; ++i){
printf("%d ", i);
for(int j=1; j<=col; ++j){
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("===========GAME==========\n");
}
void SetMine(char mine[ROWS][COLS], int row, int col){
int count = MINE_NUM;
while(count){
//生成x,y坐标
int x = rand()%row+1;
int y = rand()%col+1;
//如果是非雷,布置雷
if(mine[x][y]=='0'){
mine[x][y] = '1';
count--;
}
}
}
/*
利用static只能在自己所在的源文件内使用
1. 修饰局部变量
2. 修饰全局变量
3. 修饰函数
*/
static 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'得到ASCII码字符的十进制
// for(int i=-1; i<=1; i++){
// for(int j=-1; j<=1; j++){
// count+=mine[x+i][y+i];
// }
// }
// count = count-8*0;
}
static void not_mine_spread(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y){
//如果不是雷,统计x,y周围有几个雷
int count = getMineCount(mine, x, y);
if(count == 0){
show[x][y] = '0';
if((x-1)>0 && (y>0) && show[x-1][y] == '*') not_mine_spread(mine, show, x-1, y);
if((x-1)>0 && (y-1)>0 && show[x-1][y-1] == '*') not_mine_spread(mine, show, x-1, y-1);
if((x>0) && (y-1)>0 && show[x][y-1] == '*') not_mine_spread(mine, show, x, y-1);
if((x+1>0) && (y-1)>0 && show[x+1][y-1] == '*') not_mine_spread(mine, show, x+1, y-1);
if((x+1)>0 && (y>0) && show[x+1][y] == '*') not_mine_spread(mine, show, x+1, y);
if((x+1)>0 && (y+1)>0 && show[x+1][y+1] == '*') not_mine_spread(mine, show, x+1, y+1);
if((x>0) && (y+1)>0 && show[x][y+1] == '*') not_mine_spread(mine, show, x, y+1);
if((x-1>0) && (y+1)>0 && show[x-1][y+1] == '*') not_mine_spread(mine, show, x-1, y+1);
}else{
show[x][y] = count + '0'; //转换成字符类型数字
}
}
int game_win(char show[ROWS][COLS], int row, int col){
int mine = 0;
for(int i=1; i<=row; ++i){
for(int j=1; j<=col; j++){
if(show[i][j] == '*' || show[i][j] == '!'){
mine++;
}
}
}
return mine;
}
static void mark_Mine(char show[ROWS][COLS], int row, int col){
int input = 0;
int x = 0, y = 0;
do{
printf("Give Mine mark ? Type 1 \n");
printf("Not Mine mark ? Type 0 \n");
scanf("%d",&input);
printf("\n");
switch (input) {
case 0:
break;
case 1:
printf("Select x y coordinate:>");
scanf("%d %d", &x, &y);
if(x>=1 && x<= row && y>=1 && y<=col){
show[x][y] = '!';
DisplayBoard(show, row, col);
}
default:
break;
}
}while(input);
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col){
/*
1. 输入即将排查雷的坐标
2. 检查坐标是不是雷
1. 如果是雷,游戏结束
2. 反之,统计此坐标周围雷的个数,并存储到show数组,游戏继续
*/
int x = 0, y = 0;
//判断是否非雷已排查完
int win = 0;
while(1){
printf("Please insert x,y coordinate:>");
scanf("%d%d", &x, &y); //x和y的取值范围为1~9
if( x >= 1 && x <= row && y >= 1 && y <= col ){
if(mine[x][y] == '1'){
printf("Sorry, this is mine you have been killed\n");
DisplayBoard(mine, row, col);
break;
}else{
//如果自身附近没有雷,进行递归
not_mine_spread(mine, show, x, y);
//显示排查出的信息
DisplayBoard(show, row, col);
win = game_win(show, row, col);
if(win == MINE_NUM){
printf("Congratulation!!, Mission Success !! \n");
DisplayBoard(mine, row, col);
break;
}
}
}else{
printf("x y coordinate is not validate, Please retry~\n");
}
mark_Mine(show, row, col);
}
如果此文章对你有帮助的话,给博主一键三连,Thank You ~