目录
扫雷类似于笔者发布的第一篇三子棋,不过还是有诸多细节需要注意。笔者技艺拙劣,仅能完成简易版扫雷,提前说明这个扫雷是没能实现递归(即类似于真正扫雷,点一个展开一片的功能)。
一.头文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define Rows 11
#define Cols 11
#define Col 9
#define Row 9
#define Easy_Count 10//设置十个雷
void InitBoard(char Board[Rows][Cols], int rows, int cols, char set);
void Disboard(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);
头文件主要是宏的定义和函数声明。
这里为什么要这样定义宏呢?因为笔者设置了两个表格,而真实的表格是11*11的表格,只打印出来了9*9的玩家操作表格。这样设置是方便后续的判断胜利与失败,要是诸君有兴趣的话,可以往后继续看,笔者会做解释。
二.函数实现
先上代码:
#include"GAME.h"
void InitBoard(char Board[Rows][Cols], int rows, int cols, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < Rows;i++)
{
for (j = 0; j < Cols;j++)
{
Board[i][j] = set;
}
}
}
void Disboard(char Board[Rows][Cols], int row, int col)
{
//首先需要一个行号和列号
int i = 0;
for (i = 0; i <=col; i++)
{
printf("%d ", i);
}
printf("\n");
int j = 0;
for (i = 1; i <= row; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", Board[i][j]);
}
printf("\n");
}
}
void SetMine(char Board[Rows][Cols], int row, int col)
{
//设置地雷
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 get_mine_count(char Mine[Rows][Cols], int x, int y)
{
return Mine[x - 1][y] + Mine[x - 1][y - 1] + Mine[x - 1][y + 1] + Mine[x][y - 1] +
Mine[x][y + 1] + Mine[x + 1][y] + Mine[x + 1][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)
{
//坐标合法
//1.踩雷
if (Mine[x][y] == '1')
{
printf("很遗憾,你被炸死了\n");
Disboard(Mine, row, col);
break;
}
else //不是雷
{
//计算x,y坐标周围有几个雷
int count = get_mine_count(Mine, x, y);
Show[x][y] = count + '0';
Disboard(Show, row, col);
win++;
}
}
else
{
printf("输入坐标非法,请重新输入\n");
}
}
if (win == row * col - Easy_Count)
{
printf("恭喜你,排雷成功\n");
Disboard(Mine, row, col);
}
}
1.雷包设置:
笔者在雷包设置时是取巧了,在初始化表格的时候,设置了两个表格,一个表格是给我们程序员看的,即Mine[][]='0',这是没有雷的地方,而给玩家看的那个表Show[][]='*'进行了遮蔽。把有雷的地方设置为字符'1'。这一步也是取巧,因为在显示所要位置处需要计算周遭8个格子(因为要计算8个格子所以如果只设置9*9的表格,那么边角的坐标在计算周遭的雷时是需要特殊处理的,会增加代码的负荷,故设置了11*11的表格而只显示9*9的表格)总共有几颗雷,而1和0无疑是极其好运算的。但是需要诸君注意的是,这里还是字符1和字符0.所以下一步
这一步,便是计算周围有几颗雷,需要注意字符'1'-字符'0'=1,所以便有了图中的-8*'0'也有了下图的+'0'.
三.主函数
#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 };
printf("扫雷\n");
//需要两个表格,一个表格负责展示,一个表格负责操作
InitBoard(Mine, Rows, Cols,'0');//由于两个一个负责自己看,但玩家不能看到
InitBoard(Show, Rows, Cols,'*');//初始化两个
//打印棋盘
//Disboard(Mine, Row, Col);
Disboard(Show, Row, Col);
SetMine(Mine, Row, Col);
//扫雷
//mine 数组里找信息,显示在show
FindMine(Mine, Show, Row, Col);//该数组问题是不能展开一片
}
void test()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出成功\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
四.函数问题
这个构造是比较取巧的,笔者认为是极其简易且失败的😂。
1.首先在设置雷包的时候便借助了字符'1'和字符'0',而非正统的雷。
2.无法实现输入一个坐标就展开一片的问题。就是说传统的扫雷游戏是输入一个坐标会对周遭8个坐标进行计算是否有雷,如果没有雷,那么会对周围8个坐标的周围8个坐标再次运算是否有雷,如此循环,便能看到传统扫雷的展开一片。而笔者所写的是简易的,坦白说是笔者技艺浅薄,无法实现这个递归。
3.不能简单只实现递归,递归后,判定条件就要发生改变。笔者的扫雷属实low,想要获胜需要输入71个坐标😂。所以这个递归的函数还是很能提升用户体验的。
如果有观者有兴趣实现这个递归,那么欢迎在评论区留言,或者私信笔者。让笔者也拜读一下。总之大家一同进步吧。🌹