一、前言:
? ? ? ? 所谓“扫雷',就是根据当前已经排雷的情况,经过逻辑推理来排光所有雷的简单小游戏,触雷即失败,排完则成功。一般会以一个表格的形式出现,点击一个格子,就会得知该位置周围的雷数,依此排雷。
二、重要思想:
? ? ? ?要想实现这样一个表格,我们可以用到二维数组,那么就要对其进行初始化。
? ? ? ?但是我们要初始化两个表盘,一个表盘用于用户展示,另一个表盘用于计算某位置雷数。
? ? ? ?有了表盘之后,我们还要随机初始化雷区。
? ? ? ?对用户的输入进行判断:踩雷,游戏结束,失败;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?没有踩雷,计算当前位置附近的雷书并展示;
? ? ? ? 为用户展示游戏展示表盘。
? ? ? ?我们本次实现一个9*9的表盘,那么我们要初始化怎样的二维数组呢?是9行9列吗?
? ? ? ? ? 我们来看上图,如果初始化一个九行九列的二维数组,那么就上图这个例子来看,用字符”1“表示埋雷的位置,用字符”0“表示没有埋雷(图中并未标出),那么如果考虑到对这些位置周围雷数的计算,就会有很多情况,上面圈出的是三种情况都不同,计算附近雷数会变得复杂。
? ? ? ? ?那么我们使用11行11列的二维数组会怎样呢?
? ? ? 所以:
? ? ? ?我们初始化一个11*11的用于我们计算雷数的二维数组,先全部初始化为”0“,也不影响真正表盘的雷数,红色部分是表盘,这样,就方便的实现了不同位置雷数计算方法的统一。
? ? ? 同样初始化一个11*11的用于展示给用户表盘的二维数组,全部初始化为”?”,
? ? ? 有了这样的二维数组,我们只需控制行列,来打印用户展示表盘和随机设置雷区,为了方便用户观看,我们要打印的用户展示表盘如下图:
?
?三、函数:
? ? ? ? 宏定义:
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define count_mine 10
? ? ? ?1.InitBoard():
? ? ? ? ? ?初始化二维数组,参数为定义的二维数组,行列值参数为11而不是9,以及初始化的值。我们之后要用这个函数初始化两个11*11的二维数组。很简单,不赘述。
void InitBoard(char board[][COLS], int row, int col, char c)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = c;
}
}
}
? 2.SetMine():
? ? ? ? 设置雷区。
? ? ? ? 这里的参数需要注意,在传参时,行列值参数一定传的是用户展示棋盘的行列值即9而不是11,因为一定要在表盘内部完成设置雷区,即在11行11列的中间9*9部分设置雷区,所以用户输入的坐标x ,y一定在1-9之间。
? ? ? ? ?宏定义count_mine为10,即埋下10颗雷。在埋下一颗雷前判断此处是否已经有雷,如果有雷则需要重新放置。如果没有雷,则置“1”。
void SetMine(char board[][COLS], int row, int col)
{
int count = count_mine;
while (count>0)//保证随机雷时的位置不重叠
{
int x = rand() % (row + 1);
int y = rand() % (col + 1);
if (board[x][y] == '0'&& x!=0 && y!=0)
{
board[x][y] = '1';
count--;
}
}
}
3.ShowBoard():
? ? ?展示表盘。
? ? ? ?注意此函数的行列值传参的参数也为9而不是11。参数二维数组即为11*11的用于用户展示的数组。此函数可以理解为从11*11的用户展示二维数组给用户展示表盘赋值。
? ? ?要展示表盘,从上面提到的展示表盘可以看出,需要先打印0-9作为第一行,换行。
? ? ?剩下的部分,通过一个嵌套循环实现即可,注意内层循环每进行一次后换行。
void ShowBoard(char board[][COLS], int row, int col)
{
printf("---------------------------------\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("\n");
printf("----------------------------------\n");
}
?4.JudgeMine():
? ? 对用户的输入进行判断。
? ? 该函数的行列值传参依然为9而不是11.
? ? 用户继续进行游戏的条件是当前执行的步数小于行列相乘减去雷数,当当前执行步数以及等于行列数相乘减去雷数时,说明扫雷成功。
? ? 首先判断用户输入坐标的合法性(1-9)
? ? ? ? ? ? 若合法,如果当前位置为”1“,则表示踩到了雷,游戏结束,为用户打印带有雷区的表盘,跳出整个循环;如果当前位置不为”1",则说明没踩到雷,通过MineSround函数(下面介绍)计算当前位置附近的雷数,因为该函数返回值(雷数)为整形,所以需要把雷数强制类型转换为字符型之后赋值给当前位置的用于展示表盘的二维数组的对应位置x,y。然后为用户展示输入后的棋盘。每次成功排雷,都要对用户的扫雷步数进行计数一次。
? ? ? ? ? ? 若不合法,提示用户输入错误,重新输入即重新进入循环判断合法性。
? ? ? ? ? ?循环结束有两种可能性:
? ? ? ? ? ? 1.踩到雷,游戏结束
? ? ? ? ? ? 2.扫雷成功导致的循环结束。
? ? ? ? ? ? 所以在循环结束后判断当前步数是否等于行列数相乘减去雷数,如果相等,游戏胜利。
void JudgeMine(char user_display[][COLS], char mine_board[][COLS], int row, int col)
{
int x, y;
int step_count = 0;
while (step_count < row*col - count_mine)//继续扫雷
{
printf("Please enter x,y: ");
fflush(stdout);
scanf("%d %d", &x, &y);
if (x>=1 && x<= row && y>=1 && y<=col)
{
if (mine_board[x][y] == '1')//踩雷
{
printf("Game over!\n");
ShowBoard(mine_board, ROW, COL);
break;
}
else
{
int count_sroundmine = MineSround(mine_board, x, y);
user_display[x][y] = count_sroundmine + '0';
ShowBoard(user_display, ROW, COL);
step_count++;
}
}
else
{
printf("enter error,please enter again\n");
}
}
if (step_count == ROW*COL - count_mine)
{
printf("Congratulations,you win!\n");
}
}
5.MineSround():
? 计算当前位置附近雷的个数。
? 雷的个数即当前位置周围一周的雷的个数,分别用数组表示相加即可。
? 但是注意我们定义的二维数组为字符型,所以当前位置周围一周的值相加为字符相加,由于周围共8个格子,所以雷数即为周围字符相加所得减去8个字符“0”(内部为ascall码值相加减,”1“比”0“ascall码值大1)
int MineSround(char board[][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';
}
? ?6.Game():
? ? ? ? 定义用于用户展示的二位数组和设置雷区计算雷数的二维数组。
? ? ? ? 初始化用户展示表盘,初始化为“?”;初始花内部雷区表盘,,初始化为”0"。
? ? ? ? 随机设置雷区。
? ? ? ? 判断用户输入。
void game()
{
char user_display[ROWS][COLS];
char mine_board[ROWS][COLS];
InitBoard(user_display, ROWS, COLS,'?');
InitBoard(mine_board, ROWS, COLS, '0');
ShowBoard(user_display, ROW, COL);
SetMine(mine_board, ROW ,COL);
JudgeMine(user_display, mine_board, ROW, COL);
}
? ?7.主函数:
int main()
{
srand((unsigned int)time(NULL));
game();
system("pause");
return 0;
}
?四.完整代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<string.h>
#include<Windows.h>
#include<time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define count_mine 10
void InitBoard(char board[][COLS], int row, int col, char c)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = c;
}
}
}
void SetMine(char board[][COLS], int row, int col)
{
int count = count_mine;
while (count>0)//保证随机雷时的位置不重叠
{
int x = rand() % (row + 1);
int y = rand() % (col + 1);
if (board[x][y] == '0'&& x!=0 && y!=0)
{
board[x][y] = '1';
count--;
}
}
}
void ShowBoard(char board[][COLS], int row, int col)
{
printf("---------------------------------\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("\n");
printf("----------------------------------\n");
}
int MineSround(char board[][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 JudgeMine(char user_display[][COLS], char mine_board[][COLS], int row, int col)
{
int x, y;
int step_count = 0;
while (step_count < row*col - count_mine)//继续扫雷
{
printf("Please enter x,y: ");
fflush(stdout);
scanf("%d %d", &x, &y);
if (x>=1 && x<= row && y>=1 && y<=col)
{
if (mine_board[x][y] == '1')//踩雷
{
printf("Game over!\n");
ShowBoard(mine_board, ROW, COL);
break;
}
else
{
int count_sroundmine = MineSround(mine_board, x, y);
user_display[x][y] = count_sroundmine + '0';
ShowBoard(user_display, ROW, COL);
step_count++;
}
}
else
{
printf("enter error,please enter again\n");
}
}
if (step_count == ROW*COL - count_mine)
{
printf("Congratulations,you win!\n");
}
}
void game()
{
char user_display[ROWS][COLS];
char mine_board[ROWS][COLS];
InitBoard(user_display, ROWS, COLS,'?');
InitBoard(mine_board, ROWS, COLS, '0');
ShowBoard(user_display, ROW, COL);
SetMine(mine_board, ROW ,COL);
JudgeMine(user_display, mine_board, ROW, COL);
}
int main()
{
srand((unsigned int)time(NULL));
game();
system("pause");
return 0;
}
五。运行结果:
?
扫雷游戏实现到此结束!!!
?
?
|