扫雷是一个非常经典的游戏,相信大家应该都玩过,今天我们就来实现一个简单的扫雷游戏,它可以实现如下几个简单的功能:
- 显示该点周围雷的个数
- 第一步不炸死
- 如果坐标周围没雷,可以实现展开
要完成一个扫雷游戏,我们应该一个雷盘,存放雷的真实排布,另外还有一个显示盘,用于玩家操作和显示结果。
接下来用二维数组来构建雷盘和显示盘,要在屏幕上打印一个9X9的雷盘,因为在之后排雷的过程中需要统计坐标周围8个方位的雷的个数,为了避免数组越界的问题,需要在9X9的边界多一圈元素,即定义成11X11的二维数组。
另外为了使游戏更具有可玩性,雷盘的规格应该做到可以自定义,在头文件中定义宏即可。
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
1、初始化
创建两个二维数组,board表示设计者棋盘,show表示玩家棋盘,最开始要对这两个数组初始化,board数组所有元素初始化为字符0,在board中字符0代表不是雷,将show数组所有元素初始化为 * 。
代码如下:
void TnitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
memset(board, set, rows*cols*sizeof(board[0][0]));
}
2、打印
代码如下:
void PrintBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
for (i=0; i<=row; 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 ",board[i][j]);
}
printf("\n");
printf("---\n");
}
}
3、布置雷
雷的个数也通过定义宏使其可以自定义,在这里我设置的雷数是10个
代码如下:
{
int count = EASY_COUNT;
while(count)
{
//布置雷
int x = rand()%row+1;
int y = rand()%col+1;
if(board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
4、玩家选择排雷位置
代码如下:
int Player(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int count)
{
int x = 0;
int y = 0;
printf("请输入要排查的坐标:>");
scanf("%d%d", &x, &y);
while(1)//坐标有效性判断
{
if (x>ROW || x<1 || y>COL || y<1)
{
printf("输入越界\n");
}
else
{
if ((count == 1)&&(mine[x][y]=='1'))//第一步为雷的话要挪动这个雷去其他位置
{
int i = 0;
int j = 0;
while (mine[x][y] == '1')
{
i = rand()%ROW+1;
j = rand()%COL+1;
mine[x][y] = mine[i][j];
}
mine[i][j] = '1';
}
}
break;
}
//判断是否为雷
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了,游戏结束\n");
return 1;
}
else //不是雷的地方统计周围雷的个数
{
Fun(mine,show,x,y);
//PrintBoard(show, ROW, COL);
return IsWin(show);
}
}
5、判断周围雷的个数
这个部分是我们这个程序的核心内容,想了很久还是用递归的方法写起来比较简单,理解了扫雷的原理这个问题还是很简单的。
如果所选位置不是雷且周围无雷,那么我们将这个位置赋为空格,继续判断它的四周其他八个位置的四周是否有雷,无雷则赋为空格并继续判断下去,如果有雷则停止蔓延,并返回周围雷的个数。
代码如下:
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'));
}
void Fun(char mine[ROWS][COLS], char show[ROWS][COLS],int x, int y)
{
if (x>=1 && x<=ROW && y>=1 && y<=COL)
{
int count = 0;
count = GetMineCount(mine,x,y);
if (count == 0)
{
show[x][y] = ' ';
if (show[x-1][y] == '*')
{
Fun(mine,show,x-1,y);
}
if (show[x-1][y-1] == '*')
{
Fun(mine,show,x-1,y-1);
}
if (show[x][y-1] == '*')
{
Fun(mine,show,x,y-1);
}
if (show[x+1][y-1] == '*')
{
Fun(mine,show,x+1,y-1);
}
if (show[x+1][y] == '*')
{
Fun(mine,show,x+1,y);
}
if (show[x+1][y+1] == '*')
{
Fun(mine,show,x+1,y+1);
}
if (show[x][y+1] == '*')
{
Fun(mine,show,x,y+1);
}
if (show[x-1][y+1] == '*')
{
Fun(mine,show,x-1,y+1);
}
}
else
{
show[x][y] = count+'0';
}
}
}
6、判断输赢
如果显示区剩下的 * 的个数等于雷的个数,则排雷成功。
代码如下:
//判断输赢,根据剩余的*的个数
int IsWin(char show[ROWS][COLS])
{
int i = 0;
int j = 0;
int count = 0;
for (i=1; i<=ROW; i++)
{
for (j=1; j<=COL; j++)
{
if (show[i][j] =='*')
{
count++;
}
}
}
return count;
}
下面给出本次定义的头文件
game.h
#ifndef __GAME_H__
#define __GAME_H__
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10
void TnitBoard(char board[ROWS][COLS], int rows, int cols, char set);
void SetMine(char board[ROWS][COLS], int row, int col);
void PrintBoard(char board[ROWS][COLS], int row, int col);
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
int Player(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int count);
#endif //__GAME_H__
通过主函数的合理调用,搭建合理的游戏过程
test.c
#define _CRT_SECURE_NO_WARNINGS 0
#include "game.h"
void menu ()
{
printf("**** 欢迎进入扫雷游戏 ****\n");
printf("**************************\n");
printf("******** 1.play **********\n");
printf("******** 0.exit **********\n");
printf("**************************\n");
}
void game()
{
int ret = 0;
int count = 1;
//布置雷的数组
char mine[ROWS][COLS] = {0};
//存放排查的坐标信息
char show[ROWS][COLS] = {0};
TnitBoard(mine, ROWS, COLS, '0');
TnitBoard(show, ROWS, COLS, '*');
//布置雷
SetMine(mine, ROW, COL);
//PrintBoard(mine, ROW, COL);
PrintBoard(show, ROW, COL);
//玩家走
//排查雷
while (1)
{
ret = Player(mine, show, ROW, COL, count);
PrintBoard(show, ROW, COL);
count++;
if (ret == EASY_COUNT)
{
printf("恭喜你,排雷成功,游戏结束\n");
PrintBoard(mine, ROW, COL);
break;
}
if (ret == 1)
{
PrintBoard(mine, ROW, COL);
break;
}
}
}
void test()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
//玩游戏
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择:>");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}