代码主体由两个字符数组支撑,一个是布置雷区的数组,‘1’代表有雷,‘0’代表无雷。另一个是给玩家显示的游戏界面,初始全为‘*’,如果没有排到雷并且周围有雷,可以显示周围8个位置雷的总数,如果周围也没有雷,可以展开到周围有雷为止(递归实现)。
注意:我们要玩9*9的扫雷,就应该创建11*11的数组,因为分析得知,9*9数组计算周围雷的总数会有数组越界问题。
功能
#pragma once
#include
#include
#include
#include
#define MINECOUNT 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set);//扫雷界面初始化
void DisplayBoard(char arr[ROWS][COLS], int row, int col);//打印界面
void SetMine(char arr[ROWS][COLS], int row, int col);//布置雷
void FindMine(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int row, int col);//排除雷
int AroundMineCount(char arr[ROWS][COLS], int x, int y);//计算坐标周围地雷数
void UnFold(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int row, int col, int x, int y, int* pwin);//展开该坐标周围没有地雷的地方
雷区数组全部设置成‘0’,表示一个雷也没有
游戏界面数组全部设置成‘*’;
void InitBoard(char arr[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++)
{
arr[i][j] = set;
}
}
}
这里设置个行列标号,方便玩家进行游戏。
void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("----扫雷游戏----\n");
printf(" |");
for (i = 1; i <= col; i++)//打印列标号
{
printf("%d ", i);
}
printf("\n");
printf(" |------------------\n");
for (i = 1; i <= row; i++)
{
printf("%d|", i);//打印行标号
for (j = 1; j <= col; j++)
{
printf("%c ", arr[i][j]);
}
printf("\n");
}
}
设置随机数即可
void SetMine(char arr[ROWS][COLS], int row, int col)
{
int count = MINECOUNT;
int x = 0, y = 0;
while (count)
{
x = rand() % col + 1;
y = rand() % row + 1;
if (arr[x][y] == '0')
{
arr[x][y] = '1';
count--;
}
}
}
(1)计算周围8个位置雷的数量
这里有个小技巧,我们数组存放的是字符,那么雷的数量也是字符,只需数字+‘0’即可实现int到char的转换。
计算周围8个位置雷的数量,只需所有8个位置相加-8*‘0’,这也是为什么雷设置成‘1’,无雷设置成‘0’的原因。
int AroundMineCount(char arr[ROWS][COLS], int x, int y)
{
return arr[x - 1][y - 1] + arr[x][y - 1] + arr[x + 1][y - 1] +
arr[x - 1][y + 1] + arr[x][y + 1] + arr[x + 1][y + 1] +
arr[x - 1][y] + arr[x + 1][y] - 8 * '0';
}
(2)排查雷
排查雷阶段如何判断玩家扫雷成功呢?
即除了雷的所有位置都被排查,设置有个计数变量win,每次没有排查到雷就++,一直加到ROW*COL-MINECOUNT即是扫雷成功。
void FindMine(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int row, int col)
{
int x = 0, y = 0;
int win = 0;
while (win < ROW * COL - MINECOUNT)
{
printf("请输入你要排查的位置:\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= COL && y >= 1 && y <= ROW)
{
if (arr2[x][y] == '*')
{
if (arr1[x][y] == '1')
{
printf("很遗憾,你被炸死了!\n");
DisplayBoard(arr1, ROW, COL);
break;
}
else
{
UnFold(arr1, arr2, row, col, x, y, &win);
DisplayBoard(arr2, ROW, COL);
}
}
else
{
printf("这个地方已经被排查了\n");
}
}
else
{
printf("输入坐标越界,请重新输入:\n");
}
}
if (win == ROW * COL - MINECOUNT)
{
printf("恭喜你,扫雷成功!\n");
}
}
这个地方要用到递归,相对困难,其中也有一些小细节需要处理。
void UnFold(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int row,int col, int x, int y, int* pwin)
//这里的win必须传指针,不然每次递归回来,原来的win被销毁,就不是++后的win了
{
if (x >= 1 && x <= col && y >= 1 && y <= row)//防止数组越界访问
{
int count = AroundMineCount(arr1, x, y);//计算该坐标周围八个位置的雷的总数
if (count == 0)//周围一个雷都没,向四周展开
{
arr2[x][y] = ' ';//自己不是雷,周围没有雷,把自己置成空
(* pwin)++;
int i = 0, j = 0;
for (i = x - 1; i <= x + 1; i++)//向四周八个位置递归展开
{
for (j = y - 1; j <= y + 1; j++)
{
if (arr2[i][j] == '*')//为‘*’说明该点没有被访问,递归展开
{
UnFold(arr1, arr2, row, col, i, j, pwin);
}
}
}
}
else
{
arr2[x][y] = count + '0';
(* pwin)++;
}
}
}
有以下几点需要注意:
#pragma once
#include
#include
#include
#include
#define MINECOUNT 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set);//扫雷界面初始化
void DisplayBoard(char arr[ROWS][COLS], int row, int col);//打印界面
void SetMine(char arr[ROWS][COLS], int row, int col);//布置雷
void FindMine(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int row, int col);//排除雷
int AroundMineCount(char arr[ROWS][COLS], int x, int y);//计算坐标周围地雷数
void UnFold(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int row, int col, int x, int y, int* pwin);//展开该坐标周围没有地雷的地方
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void InitBoard(char arr[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++)
{
arr[i][j] = set;
}
}
}
void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("----扫雷游戏----\n");
printf(" |");
for (i = 1; i <= col; i++)//打印列标号
{
printf("%d ", i);
}
printf("\n");
printf(" |------------------\n");
for (i = 1; i <= row; i++)
{
printf("%d|", i);//打印行标号
for (j = 1; j <= col; j++)
{
printf("%c ", arr[i][j]);
}
printf("\n");
}
}
void SetMine(char arr[ROWS][COLS], int row, int col)
{
int count = MINECOUNT;
int x = 0, y = 0;
while (count)
{
x = rand() % col + 1;
y = rand() % row + 1;
if (arr[x][y] == '0')
{
arr[x][y] = '1';
count--;
}
}
}
int AroundMineCount(char arr[ROWS][COLS], int x, int y)
{
return arr[x - 1][y - 1] + arr[x][y - 1] + arr[x + 1][y - 1] +
arr[x - 1][y + 1] + arr[x][y + 1] + arr[x + 1][y + 1] +
arr[x - 1][y] + arr[x + 1][y] - 8 * '0';
}
void UnFold(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int row,int col, int x, int y, int* pwin)
//这里的win必须传指针,不然每次递归回来,原来的win被销毁,就不是++后的win了
{
if (x >= 1 && x <= col && y >= 1 && y <= row)//防止数组越界访问
{
int count = AroundMineCount(arr1, x, y);//计算该坐标周围八个位置的雷的总数
if (count == 0)//周围一个雷都没,向四周展开
{
arr2[x][y] = ' ';//自己不是雷,周围没有雷,把自己置成空
(* pwin)++;
int i = 0, j = 0;
for (i = x - 1; i <= x + 1; i++)//向四周八个位置递归展开
{
for (j = y - 1; j <= y + 1; j++)
{
if (arr2[i][j] == '*')//为‘*’说明该点没有被访问,递归展开
{
UnFold(arr1, arr2, row, col, i, j, pwin);
}
}
}
}
else
{
arr2[x][y] = count + '0';
(* pwin)++;
}
}
}
void FindMine(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int row, int col)
{
int x = 0, y = 0;
int win = 0;
while (win < ROW * COL - MINECOUNT)
{
printf("请输入你要排查的位置:\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= COL && y >= 1 && y <= ROW)
{
if (arr2[x][y] == '*')
{
if (arr1[x][y] == '1')
{
printf("很遗憾,你被炸死了!\n");
DisplayBoard(arr1, ROW, COL);
break;
}
else
{
UnFold(arr1, arr2, row, col, x, y, &win);
DisplayBoard(arr2, ROW, COL);
}
}
else
{
printf("这个地方已经被排查了\n");
}
}
else
{
printf("输入坐标越界,请重新输入:\n");
}
}
if (win == ROW * COL - MINECOUNT)
{
printf("恭喜你,扫雷成功!\n");
}
}
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void Menu()
{
printf("**************************************\n");
printf("*************1.开始游戏***************\n");
printf("*************0.退出游戏***************\n");
printf("**************************************\n");
}
void Game()
{
char mine[ROWS][COLS];//保存雷区的数组,‘0’是无雷。‘1’是有雷
char show[ROWS][COLS];//保存玩家的游戏界面
srand((unsigned int)time(NULL));
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
DisplayBoard(show, ROW, COL);//打印玩家游戏界面
//1.布置雷
SetMine(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL);
//2.排雷
FindMine(mine, show, ROW, COL);
}
int main()
{
int input = 0;
do
{
Menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 0:
break;
case 1:
Game();
break;
default:
printf("输入错误,请重新选择:\n");
break;
}
} while (input);
return 0;
}