前言
- 🚄 输入是学习的本质,输出是学习的手段。
- 🔖 分享每一次的学习,期待你我都有收获。
- 🎇 欢迎🔎关注👍点赞??收藏?评论,共同进步!
- 🌊 “要足够优秀,才能接住上天给的惊喜和机会”
- 💬 博主水平有限,如若有误,请多指正,万分感谢!
主要讲一下思想和一些注意点。 扫雷是什么,相信大家没玩过也听过,我就不过多赘述了。 这是一个扫雷界面。
要实现扫雷,需要分为以下步骤:
??1. 创造棋盘,假设我们需要的是9*9的棋盘。
当我们选中一个位置时,如果这个位置不是雷,那么游戏就应该给我们一个反馈,告诉我们周围一圈8个位置有几个雷。 就像这样:
这就表明周围这一圈里有3个雷。如果恰好我们选的位置就是雷,那么我们就被炸死了,游戏就直接结束。
这里就面临一个问题了,如果我选的是中间的位置,那周围有8个位置可以反馈,如果我选的是边缘呢? 显然这已经超出数组范围,越界了。因此,我们不妨再创造这样一个棋盘时,就将范围扩大些。
比如我们要的是一个9*9的棋盘,那么我们就将范围扩大到11 * 11(上下、左右各增加一行一列。绿色为扩大后的范围),只要不在扩大的那部分中埋雷,那么显示出来的数字也只会是9 * 9 这个区间中雷的个数,如图所示: (假设 * 表示雷)
#define ROW 9
#define COL 9
#define ROWS 11
#define COLS 11
??2.如何设置雷,如何设置反馈?
有些老铁觉得可以在一个棋盘里 用1和0分别表示雷和非雷 就像这样:(1表示雷 ,0表示非雷) 但是这样做会和反馈周围雷数的1产生二义性,因此不合适。
又有些老铁认为可以用*表示雷,#表示非雷,但是这样不够方便,没有用0和1表示来得方便。为什么不够方便一会儿就知道了,当然如果非要这样实现也是可以的。只是判断的时候会比较复杂一点。
既然我们既要用1和0表示雷和非雷,又不能与反馈的数字产生二义性,那么我们不妨再开一个等大的棋盘,这样,一个棋盘用来布置雷,但是不展示给玩家,另一个棋盘则作为反馈信息的棋盘,展示给玩家。
一开始我们先把布置雷的棋盘初始化,全置为0(非雷),以后再随机埋雷。 将反馈展示给玩家的棋盘全置为 * ,就是一个没有动过的棋盘
void InitBoard(char board[ROWS][COLS], int row, int col, char set)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = set;
}
}
}
char mine[ROWS][COLS];
char show[ROWS][COLS];
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
效果如下(对比):
然后是布置雷:
#define Count 10
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int count = Count;
while (count)
{
int x = rand() % 9 + 1;
int y = rand() % 9 + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
布置完雷后,我们可以看一下效果:
??3. 扫雷,何时结束,如何反馈。
int Show(char mine[ROW][COL], int x, int y)
{
return mine[x - 1][y - 1] +
mine[x - 1][y] +
mine[x - 1][y + 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] +
mine[x][y - 1] +
mine[x][y + 1];
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS])
{
int x, y;
int endcount = ROW * COL - Count;
int count = Count;
do
{
if (endcount == 0)
{
printf("已无雷区\n");
break;
}
printf("请输入坐标:\n");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
{
{
if (mine[x][y] == '1')
{
printf("你被炸死了\n");
PrintBoard(mine, ROW, COL);
break;
}
else
{
int showcount = Show(mine, x, y);
show[x][y] = showcount + '0';
PrintBoard(show, ROW, COL);
}
}
}
else
{
printf("坐标错误,请重新输入");
continue;
}
} while (1);
}
解释一下Show函数: 在ASCII表中,我们可以观察到, ‘0’-‘0’=0 ( 字符0-字符0等于 数字0 ) 而其他任意数字字符减去字符0可以得到该数,比如 ‘5’-‘0’= 5 因此 Show函数将周围八个字符(不是0就是1) 全加起来,再减去8个‘0’。就能得到一个数字, 该数字就表明周围有几个1。
这也就解释了为什么说用1和0表示雷和非雷方便。
最后再解释一下这行代码:
show[x][y] = showcount + '0';
因为show数组保存的是字符,无法完全接收这个返回来的整型数字。
字符数 - ‘0’ = 数字 ——> 字符数 = 数字 + ‘0’
完整代码:
game.h
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define ROW 9
#define COL 9
#define ROWS 11
#define COLS 11
#define Count 10;
void InitBoard(char board[ROWS][COLS], int row, int col, char set);
void PrintBoard(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]);
game.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
void InitBoard(char board[ROWS][COLS], int row, int col, char set)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = set;
}
}
}
void PrintBoard(char board[ROWS][COLS], int row, int col)
{
for (int i = 0; i <= row; 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");
}
}
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int count = Count;
while (count)
{
int x = rand() % 9 + 1;
int y = rand() % 9 + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
int Show(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y - 1] +
mine[x - 1][y] +
mine[x - 1][y + 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] +
mine[x][y - 1] +
mine[x][y + 1] - 8 * '0';
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS])
{
int x, y;
int endcount = ROW * COL - Count;
int count = Count;
do
{
if (endcount == 0)
{
printf("已无雷区\n");
break;
}
printf("请输入坐标:\n");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
{
{
if (mine[x][y] == '1')
{
printf("你被炸死了\n");
PrintBoard(mine, ROW, COL);
break;
}
else
{
endcount--;
int showcount = Show(mine, x, y);
show[x][y] = showcount + '0';
PrintBoard(show, ROW, COL);
}
}
}
else
{
printf("坐标错误,请重新输入");
continue;
}
} while (1);
}
test.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
#include<time.h>
void game()
{
srand((unsigned int)time(NULL));
char mine[ROWS][COLS];
char show[ROWS][COLS];
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
SetMine(mine, ROW, COL);
PrintBoard(show, ROW, COL);
int x, y;
FindMine(mine, show);
}
int main()
{
game();
}
|