扫雷这个经典的游戏大家都应该玩过,今天我们就将用C语言来实现扫雷这个游戏,我的这个扫雷游戏主要有三个功能:
- 第一次扫雷,一定不会点到雷
- 第一次扫雷,可以大片的展开
- 会显示所选位置周围的雷数
下面讲述一下我这个扫雷的思想:
- 我们需要两个棋盘,一个用来给用户展示,一个用来自己内部使用
- 布雷:在自己使用的棋盘随机布雷
- 保证第一步不会踩到雷。首先判断所选位置是否为雷,如果是,将其改掉,并在其他随机不为雷的位置设置雷
- 计算所选位置周围雷的个数
- 将第一步所选位置周围展开
- 判断输赢
但你会发现,在计算周围雷个数的时候,在边边的和在中间位置的计算还不一样,我们可以让数组周围都在加一行或者一列,比如,需要打印出来的是9*9的表格,我们在设置的时候,可以弄成11*11的,只要我们知道就行了,方便计算。
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
话不多说,上代码:
头文件:
这段代码是放在game.h中,函数声明
#ifndef __GAME_H__
#define __GAME_H__
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10 //设置雷数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
void InitBoard(char board[ROWS][COLS], int row, int col, char c);//初始化棋盘
void SetBoard(char board[ROWS][COLS], int row, int col);//布雷
void PrintBoard(char board[ROWS][COLS], int row, int col);//打印棋盘
int AroundCount(char board[ROWS][COLS], int x, int y);//计算周围雷数
int IfWin(char board[ROWS][COLS], int row, int col);//判断输赢
void Minesweeper(char MineBoard[ROWS][COLS], char PlayBoard[ROWS][COLS], int row, int col);//扫雷过程
void FirstStep(char MineBoard[ROWS][COLS], char PlayBoard[ROWS][COLS], int row, int col, int x, int y);//第一步
void OpenBoard(char MineBoard[ROWS][COLS], char PlayBoard[ROWS][COLS], int x, int y);//第一步展开
#endif
下面的代码是放在game.c中的:
初始化棋盘:
我们有两个棋盘,自己使用的全部初始化为‘0’(不是雷),用户使用的,全部初始化为‘*’
void InitBoard(char board[ROWS][COLS], int row, int col, char c)
{
memset(board, c, sizeof(board[0][0]) * row * col);
}
打印棋盘:
void PrintBoard(char board[ROWS][COLS], int row, int col)
{
for (int i = 1; i < row - 1; i++)
{
if (i == 1)
{
printf(" %d", i);
}
else
{
printf(" %d", i);
}
}
printf("\n");
for (int i = 1; i < row - 1; i++)
{
printf("%d ", i);
for (int j = 1; j < col - 1; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("\n");
}
布雷:
void SetBoard(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int i = 0;
while (i < EASY_COUNT)
{
while (1)
{
x = rand() % 9 + 1;
y = rand() % 9 + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
break;
}
}
i++;
}
}
计算周围雷的个数:
int AroundCount(char board[ROWS][COLS], int x, int y)
{
return board[x - 1][y] + board[x - 1][y - 1] +
board[x][y - 1] + board[x + 1][y - 1] +
board[x + 1][y] + board[x + 1][y + 1] +
board[x][y + 1] + board[x - 1][y + 1] - 8 * '0';
}
判断输赢:
当最后所剩余棋盘上的 * 就是雷时,则胜利
int IfWin(char board[ROWS][COLS], int row, int col)
{
int count = 0;
for (int i = 1; i <= row; i++)
{
for (int j = 1; j <= col; j++)
{
if (board[i][j] == '*')
{
count++;
}
}
}
return count;
}
第一步为雷时:
void FirstStep(char MineBoard[ROWS][COLS], char PlayBoard[ROWS][COLS], int row, int col, int x, int y)
{
MineBoard[x][y] = '0';
int i = 0;
int j = 0;
while (1)
{
i = rand() % 9 + 1;
j = rand() % 9 + 1;
if (MineBoard[i][j] == '0' && i != x && j != y)
{
MineBoard[i][j] = '1';
break;
}
}
int ret = AroundCount(MineBoard, x, y);
PlayBoard[x][y] = ret + '0';
OpenBoard(MineBoard, PlayBoard, x, y);
PrintBoard(PlayBoard, ROWS, COLS);
PrintBoard(MineBoard, ROWS, COLS);
}
扫雷过程:
当第一步所选位置不是雷时,正常走,如若是雷,就将其改变
void Minesweeper(char MineBoard[ROWS][COLS], char PlayBoard[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int step = 1;
while (1)
{
printf("请输入坐标:\n");
scanf("%d%d", &x, &y);
if (MineBoard[x][y] == '1' && step == 1)
{
FirstStep(MineBoard, PlayBoard, ROW, COL, x, y);
step++;
if (IfWin(PlayBoard, ROW, COL) == EASY_COUNT)
{
printf("恭喜你,YOU WIN!\n");
PrintBoard(MineBoard, ROWS, COLS);
break;
}
continue;
}
if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
{
if (MineBoard[x][y] == '1')
{
printf("BOOM!你被炸飞了\n");
PrintBoard(MineBoard, ROWS, COLS);
break;
}
else
{
int ret = AroundCount(MineBoard, x, y);
PlayBoard[x][y] = ret + '0';
OpenBoard(MineBoard, PlayBoard, x, y);
PrintBoard(PlayBoard, ROWS, COLS);
}
}
else
{
printf("输入坐标非法,请重新输入\n");
}
if (IfWin(PlayBoard, ROW, COL) == EASY_COUNT)
{
printf("恭喜你,YOU WIN!\n");
PrintBoard(MineBoard, ROWS, COLS);
break;
}
}
}
展开:
该过程使用的是递归,如若周围一直没有雷,就会一直扩展下去
void OpenBoard(char MineBoard[ROWS][COLS], char PlayBoard[ROWS][COLS], int x, int y)
{
if (MineBoard[x][y] == '0' && PlayBoard[x][y] == '*')
{
PlayBoard[x][y] = AroundCount(MineBoard, x, y) + '0';
}
if (MineBoard[x - 1][y] == '0' && PlayBoard[x - 1][y] == '*')
{
PlayBoard[x - 1][y] = AroundCount(MineBoard, x - 1, y) + '0';
if (AroundCount(MineBoard, x - 1, y) == 0)
{
OpenBoard(MineBoard, PlayBoard, x - 1, y);
}
}
if (MineBoard[x - 1][y - 1] == '0' && PlayBoard[x - 1][y - 1] == '*')
{
PlayBoard[x - 1][y - 1] = AroundCount(MineBoard, x - 1, y - 1) + '0';
if (AroundCount(MineBoard, x - 1, y - 1) == 0)
{
OpenBoard(MineBoard, PlayBoard, x - 1, y - 1);
}
}
if (MineBoard[x][y - 1] == '0' && PlayBoard[x][y - 1] == '*')
{
PlayBoard[x][y - 1] = AroundCount(MineBoard, x, y - 1) + '0';
if (AroundCount(MineBoard, x, y - 1) == 0)
{
OpenBoard(MineBoard, PlayBoard, x, y - 1);
}
}
if (MineBoard[x + 1][y - 1] == '0' && PlayBoard[x + 1][y - 1] == '*')
{
PlayBoard[x + 1][y - 1] = AroundCount(MineBoard, x + 1, y - 1) + '0';
if (AroundCount(MineBoard, x + 1, y - 1) == 0)
{
OpenBoard(MineBoard, PlayBoard, x + 1, y - 1);
}
}
if (MineBoard[x + 1][y] == '0' && PlayBoard[x + 1][y] == '*')
{
PlayBoard[x + 1][y] = AroundCount(MineBoard, x + 1, y) + '0';
if (AroundCount(MineBoard, x + 1, y) == 0)
{
OpenBoard(MineBoard, PlayBoard, x + 1, y);
}
}
if (MineBoard[x + 1][y + 1] == '0' && PlayBoard[x + 1][y + 1] == '*')
{
PlayBoard[x + 1][y + 1] = AroundCount(MineBoard, x + 1, y + 1) + '0';
if (AroundCount(MineBoard, x + 1, y + 1) == 0)
{
OpenBoard(MineBoard, PlayBoard, x + 1, y + 1);
}
}
if (MineBoard[x][y + 1] == '0' && PlayBoard[x][y + 1] == '*')
{
PlayBoard[x][y + 1] = AroundCount(MineBoard, x, y + 1) + '0';
if (AroundCount(MineBoard, x, y + 1) == 0)
{
OpenBoard(MineBoard, PlayBoard, x, y + 1);
}
}
if (MineBoard[x - 1][y + 1] == '0' && PlayBoard[x - 1][y + 1] == '*')
{
PlayBoard[x - 1][y + 1] = AroundCount(MineBoard, x - 1, y + 1) + '0';
if (AroundCount(MineBoard, x - 1, y + 1) == 0)
{
OpenBoard(MineBoard, PlayBoard, x - 1, y + 1);
}
}
}
下面的代码是放在test.c中的:
游戏模块:
#pragma warning(disable:4996)
#include "game.h"
void menu()
{
printf("*********************************\n");
printf("**** 1.play ****\n");
printf("**** 0.exit ****\n");
printf("*********************************\n");
}
void game()
{
char MineBoard[ROWS][COLS];
char PlayBoard[ROWS][COLS];
InitBoard(MineBoard, ROWS, COLS, '0');
InitBoard(PlayBoard, ROWS, COLS, '*');
SetBoard(MineBoard, ROWS, COLS);
//PrintBoard(MineBoard, ROWS, COLS);
PrintBoard(PlayBoard, ROWS, COLS);
Minesweeper(MineBoard, PlayBoard, ROW, COL);
}
void test()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("请重新选择:\n");
break;
}
} while (input);
}
int main()
{
test();
system("pause");
return 0;
}
当选到雷时:
最终排除所有雷时: