扫雷
扫雷最早是一款1992年发布的小游戏,游戏的目标是在最短的时间内根据点击格子出现的数字找出所有非雷格子,同时避免踩雷,踩到一个雷即全盘皆输。
在这里使用C语言实现一下简单的扫雷游戏,不加入计时功能,仅通过玩家是否找到所有雷的位置判断输赢。
首先利用二维数据存储扫雷的格子,这里需要存储两个棋盘,一个是玩家点击后显示的棋盘,另一个则是布置完雷用来检查玩家选中的格子附近雷数以及判断玩家的输赢的棋盘。
游戏开局首先布置雷的位置,然后交由玩家选择想要点击的格子位置,这里通过玩家输入棋盘格子的坐标来实现,同时程序判断玩家的输赢,直到玩家胜利或是失败则游戏结束。
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
DisplayBoard(show, ROW, COL);
SetMine(mine, ROW, COL);
SafeFirst(mine, show, ROW, COL);
FindMine(mine, show, ROW, COL);
棋盘的初始化直接使用了库函数memset(board, set, rows*cols);
。
用于显示的棋盘初始化为全部是字符‘*’,便于打印,显示棋盘时字符‘*’的位置即为没有打开的位置,而用于布置雷的棋盘则初始化为全是字符‘0’,放置雷的格子更改为字符‘1’,这样便于计算某一个格子的表示周围雷数的数字,即计算该格子周围八个格子的字符表示的数字之和。
玩家每选择出一个格子后需要对棋盘当前的给玩家显示的棋盘进行打印。
int i = 0, j = 0;
printf("____________________________\n");
for (i = 0; i <= row; i++)
printf("%d ", i);
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
printf("%c ", board[i][j]);
printf("\n");
}
printf("----------------------------\n");
对于棋盘中雷的布置采用了随机数函数,随机生成数字作为二维数组的行和列,从而确定雷的位置。
int x = 0, y = 0;
int count = EASY_COUNT;
while (count)
{
x = rand() % 9 + 1;
y = rand() % 9 + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
这里通过读取玩家输入的二维数组的坐标得到玩家想要点击的格子,当玩家选中了一个格子之后,如果这个格子没有雷,则会显示出其周围八个格子的总雷数,而如果这个格子的附近八个位置也没有雷则会触发一个展开函数。
同时在玩家选择格子之后也需要对整个棋盘进行遍历访问,如果所有没有雷的格子均打开则玩家获胜,如果玩家选到了有雷的格子则游戏失败。
即通过计算未打开的格子数量与雷的总数进行比较判断玩家是否获胜。
int x = 0, y = 0;
if (IsWin(show, ROW, COL) == EASY_COUNT)
{
printf("恭喜您,游戏成功!\n");
goto end;
}
while (1)
{
printf("请输入你认为没有雷的坐标:");
scanf("%d%d", &x, &y);
if (x > 0 && x <= row && y > 0 && y <= col)
{
if (mine[x][y] == '1')
{
printf("很遗憾,该位置有雷,游戏失败。\n雷区标识如下(有雷为1,无则为0):\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
int minecount = GetMineCount(mine, x, y);
show[x][y] = minecount + '0';
OpenMine(mine, show, ROW, COL, x, y);
DisplayBoard(show, ROW, COL);
if (IsWin(show, ROW, COL) == EASY_COUNT)
{
printf("恭喜您,游戏成功!\n");
break;
}
}
}
else
printf("输入的坐标非法,请重新输入。\n");
}
end:
;
玩家选择格子的时候为了提高游戏体验设置了新手保护,保护玩家第一次选择不会直接由于选中雷区而游戏失败,这里如果玩家第一次恰好选到了有雷的格子,则将这个雷更换位置重新生成棋盘,从而保证玩家第一次不会直接失败。
int x = 0, y = 0;
int x1 = 0, y1 = 0;
printf("请输入你认为没有雷的坐标:");
scanf("%d%d", &x, &y);
if (x > 0 && x <= row && y > 0 && y <= col)
{
if (mine[x][y] == '1')
{
mine[x][y] = '0';
while (1) //在其余有空的地方设置这个雷
{
x1 = rand() % 9 + 1;
y1 = rand() % 9 + 1;
if (mine[x1][y1] == '0')
{
mine[x1][y1] = '1';
break;
}
}
int minecount = GetMineCount(mine, x, y);
show[x][y] = minecount + '0';
OpenMine(mine, show, ROW, COL, x, y);
DisplayBoard(show, ROW, COL);
if (IsWin(show, ROW, COL) == EASY_COUNT)
{
printf("恭喜您,游戏成功!\n");
}
}
else
{
int minecount = GetMineCount(mine, x, y);
show[x][y] = minecount + '0';
OpenMine(mine, show, ROW, COL, x, y);
DisplayBoard(show, ROW, COL);
if (IsWin(show, ROW, COL) == EASY_COUNT)
{
printf("恭喜您,游戏成功!\n");
}
}
}
else
printf("输入的坐标非法,请重新输入。\n");
展开函数的实现采用了递归的方式,依次检查选中的格子的周围八个格子,如果检查的格子周围的八个格子仍然没有雷,则继续递归进行检查,同时判断行列值是否在整个棋盘内以防止越界访问。
if (x > 0 && x <= row && y > 0 && y <= col)
{
if (mine[x][y] == '0')
{
int count = GetMineCount(mine, x, y);
if (count == 0)
{
board[x][y] = ' ';
if (board[x - 1][y - 1] == '*')
OpenMine(mine, board, ROW, COL, x - 1, y - 1);
if (board[x - 1][y] == '*')
OpenMine(mine, board, ROW, COL, x - 1, y);
if (board[x - 1][y + 1] == '*')
OpenMine(mine, board, ROW, COL, x - 1, y + 1);
if (board[x][y - 1] == '*')
OpenMine(mine, board, ROW, COL, x, y - 1);
if (board[x][y + 1] == '*')
OpenMine(mine, board, ROW, COL, x, y + 1);
if (board[x + 1][y - 1] == '*')
OpenMine(mine, board, ROW, COL, x + 1, y - 1);
if (board[x + 1][y] == '*')
OpenMine(mine, board, ROW, COL, x + 1, y);
if (board[x + 1][y + 1] == '*')
OpenMine(mine, board, ROW, COL, x + 1, y + 1);
}
else
board[x][y] = count + '0';
}
}
完整代码
主函数
#include "game.h"
void menu()
{
printf("****************************\n");
printf("****** 1. play ******\n");
printf("****** 0. exit ******\n");
printf("****************************\n");
}
void test()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请输入数字选择->");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
break;
default:
printf("输入有误,请重新输入\n");
break;
}
} while (input);
}
int main()
{
test();
system("pause");
return 0;
}
game.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define ROW 9
#define COL 9
#define ROWS 11
#define COLS 11
#define EASY_COUNT 10
void game();
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
void DisplayBoard(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);
void SafeFirst(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
void OpenMine(char mine[ROWS][COLS], char board[ROWS][COLS], int row, int col, int x, int y);
game.c
#include "game.h"
void game()
{
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
DisplayBoard(show, ROW, COL);
SetMine(mine, ROW, COL);
SafeFirst(mine, show, ROW, COL);
FindMinePlus(mine, show, ROW, COL);
}
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
memset(board, set, rows*cols);
}
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0, j = 0;
printf("____________________________\n");
for (i = 0; i <= row; i++)
printf("%d ", i);
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
printf("%c ", board[i][j]);
printf("\n");
}
printf("----------------------------\n");
}
void SetMine(char board[ROWS][COLS], int row, int col)
{
int x = 0, y = 0;
int count = EASY_COUNT;
while (count)
{
x = rand() % 9 + 1;
y = rand() % 9 + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
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';
}
static int IsWin(char show[ROWS][COLS], int row, int col)
{
int count = 0;
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (show[i][j] == '*')
{
count++;
}
}
}
return count;
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0, y = 0;
if (IsWin(show, ROW, COL) == EASY_COUNT)
{
printf("恭喜您,游戏成功!\n");
goto end;
}
while (1)
{
printf("请输入你认为没有雷的坐标:");
scanf("%d%d", &x, &y);
if (x > 0 && x <= row && y > 0 && y <= col)
{
if (mine[x][y] == '1')
{
printf("很遗憾,该位置有雷,游戏失败。\n雷区标识如下(有雷为1,无则为0):\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
int minecount = GetMineCount(mine, x, y);
show[x][y] = minecount + '0';
OpenMine(mine, show, ROW, COL, x, y);
DisplayBoard(show, ROW, COL);
if (IsWin(show, ROW, COL) == EASY_COUNT)
{
printf("恭喜您,游戏成功!\n");
break;
}
}
}
else
printf("输入的坐标非法,请重新输入。\n");
}
end:
;
}
void SafeFirst(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0, y = 0;
int x1 = 0, y1 = 0;
printf("请输入你认为没有雷的坐标:");
scanf("%d%d", &x, &y);
if (x > 0 && x <= row && y > 0 && y <= col)
{
if (mine[x][y] == '1')
{
mine[x][y] = '0';
while (1) //在其余有空的地方设置这个雷
{
x1 = rand() % 9 + 1;
y1 = rand() % 9 + 1;
if (mine[x1][y1] == '0')
{
mine[x1][y1] = '1';
break;
}
}
int minecount = GetMineCount(mine, x, y);
show[x][y] = minecount + '0';
OpenMine(mine, show, ROW, COL, x, y);
DisplayBoard(show, ROW, COL);
if (IsWin(show, ROW, COL) == EASY_COUNT)
{
printf("恭喜您,游戏成功!\n");
}
}
else
{
int minecount = GetMineCount(mine, x, y);
show[x][y] = minecount + '0';
OpenMine(mine, show, ROW, COL, x, y);
DisplayBoard(show, ROW, COL);
if (IsWin(show, ROW, COL) == EASY_COUNT)
{
printf("恭喜您,游戏成功!\n");
}
}
}
else
printf("输入的坐标非法,请重新输入。\n");
}
void OpenMine(char mine[ROWS][COLS], char board[ROWS][COLS], int row, int col, int x, int y)
{
if (x > 0 && x <= row && y > 0 && y <= col)
{
if (mine[x][y] == '0')
{
int count = GetMineCount(mine, x, y);
if (count == 0)
{
board[x][y] = ' ';
if (board[x - 1][y - 1] == '*')
{
OpenMine(mine, board, ROW, COL, x - 1, y - 1);
}
if (board[x - 1][y] == '*')
{
OpenMine(mine, board, ROW, COL, x - 1, y);
}
if (board[x - 1][y + 1] == '*')
{
OpenMine(mine, board, ROW, COL, x - 1, y + 1);
}
if (board[x][y - 1] == '*')
{
OpenMine(mine, board, ROW, COL, x, y - 1);
}
if (board[x][y + 1] == '*')
{
OpenMine(mine, board, ROW, COL, x, y + 1);
}
if (board[x + 1][y - 1] == '*')
{
OpenMine(mine, board, ROW, COL, x + 1, y - 1);
}
if (board[x + 1][y] == '*')
{
OpenMine(mine, board, ROW, COL, x + 1, y);
}
if (board[x + 1][y + 1] == '*')
{
OpenMine(mine, board, ROW, COL, x + 1, y + 1);
}
}
else
{
board[x][y] = count + '0';
}
}
}
}