通过C语言实现简单的扫雷游戏,工程分为三个部分:main.c、game.c、game.h。
目录
前言
一、游戏设计思路
二、逐步实现
1.main.c
2.game()的实现
3.初始化和展示
4.布置雷、排查雷以及计算周围雷的数量
5. 判断是否排完雷以及坐标输入的判断
6.展开一片
三、游戏代码
1.main.c
2.game.h
3.game.c
各位读者老爷如果觉得博主写的不错,请诸位多多支持(点赞+收藏+关注)。如果有不对的地方,欢迎在评论区指出。
《扫雷》是一款大众类的益智小游戏,于1992年发行。 游戏目标是在最短的时间内根据点击格子出现的数字找出所有非雷格子,同时避免踩雷,踩到一个雷即全盘皆输。 那么如何用C语言实现简单的扫雷游戏呢?
上面图一是扫雷游戏的界面,我们可以看到这是一个简单模式的扫雷,由一个个方块组成9X9的一个方阵一共布置了10个雷;这就让我们想到了二维数组,我们可以用二维数组来实现一个9X9的方阵,并在方阵中布置好雷;但一个二维数组肯定是不够的,因为不仅要存放布置好的雷的信息,还要存放排查好雷的信息,所以需要两个二维数组,再设计一个雷和周围雷数量的计算和存储方式,这样就能实现一个简单的扫雷了。
main.c的作用就是打印菜单,说明游戏选择并接收玩家的输入,玩家输入1开始游戏,输入0结束游戏;游戏开始,程序就会进入game()函数让玩家可以进行游戏。
#define _CRT_SECURE_NO_WARNINGS 1
#include
//菜单
void menu()
{
printf("******************************\n");
printf("***** 1.play 0.exit *****\n");
printf("******************************\n");
}
//游戏进行
void game()
{
}
int main()
{
int input = 0; //玩家输入选择
do
{
printf("请输入->");
scanf("%d", &input);
switch (input)
{
case 1:
game(); //进入游戏
break;
case 0:
printf("游戏结束\n"); //游戏结束
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
game()函数是作为游戏的本体,游戏真正开始进行的地方。在游戏设计思路中讲到,我们需要两个二维数组,一个用于存放布置好雷的信息,另一个用于存放排查好雷的信息并展示出来;那么我们还缺少的就是如何设置雷并且如何计算一个雷的周围的雷的个数。首先想到用数字1,但有明显的缺陷,这个1表示1个雷还是说这个1是雷呢?这很难分辨。不妨在布置雷的数组中用字符‘1’表示雷,字符‘0’表示无雷;在排查雷的数组中用‘*’初始化并展示。
//游戏进行
void game()
{
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化
Initboard(mine, ROWS, COLS, '0');
Initboard(show, ROWS, COLS, '*');
//打印
Printboard(mine, ROWS, COLS);
Printboard(show, ROWS, COLS);
}
考虑到计算坐标周围雷的数量计算问题,把二维数组扩展为11X11,这样方便计算出边界上的坐标周围雷的个数。
//初始化
void Initboard(char board[ROWS][COLS], int rows, int cols, char a)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = a; //初识化数组元素为目标数组
}
}
}
//打印
void Printboard(char board[ROWS][COLS], int rows, int cols)
{
int i = 0;
int 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 SetMines(char mine[ROWS][COLS], int rows, int cols)
{
int count = NUMBER;
while (count)
{
int x = rand() % 9 + 1;
int y = rand() % 9 + 1;
if (mine[x][y] == '0') //判断该位置是否已布置雷
{
mine[x][y] = '1';
count--;
}
}
}
//计算坐标周围雷的数量
int number(char board[ROWS][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');
}
//排查雷
int PlayerRemove(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
if (x > 0 && x <= ROW && y > 0 && y <= COL) //判断输入是否合法
{
//判断输入坐标是否被占用
if (show[x][y] == '*' && mine[x][y] != '1')
{
show[x][y] = 48 + number(mine,x,y);
return 1;
}
else if (mine[x][y] != '1')
{
return -1;
}
else
{
printf("坐标已被占用,请重新输入\n");
return 0;
}
}
else
{
printf("输入错误,请重新输入\n");
return 0;
}
}
//判断是否排查出所有雷
int IsFull(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
int count = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
if (board[i][j] == '*')
count++;
}
}
if (count == NUMBER)
{
return 1; //排完返回1
}
else
{
return 0; //没排完返回0
}
}
//判断是否踩雷
int Judgement(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
if ((x > 0) && (x <= ROW) && (y > 0) && (y <= COL))
{
if (mine[x][y] == '1')
{
return 1; //踩雷返回1
}
else if (show[x][y] != '*')
{
return -1; //坐标被占用返回-1
}
else
{
return 0; //坐标正常返回0
}
}
else
{
return 2; //坐标不合法返回2
}
}
//展开
void UnfoldSlice(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
int i = 0;
int j = 0;
if (0 == number(mine,x,y)) //判断坐标(x,y)周围雷的数量是否为0
{
show[x][y] = ' ';
for (i = -1; i <= 1; i++)
{
for (j = -1; j <= 1; j++)
{
if('*' == show[x+i][y+j])
UnfoldSlice(mine, show, x + i, y + j); //递归展开
}
}
}
else //坐标(x,y)周围雷的数量不为0时
{
show[x][y] = number(mine, x, y) + '0';
}
}
测试代码:
#include "game.h"
//菜单
void menu()
{
printf("******************************\n");
printf("***** 1.play 0.exit *****\n");
printf("******************************\n");
}
//游戏进行
void game()
{
srand((unsigned int)time(NULL)); //设置随机数的起点
char mine[ROWS][COLS] = { 0 }; //存放布置雷的信息
char show[ROWS][COLS] = { 0 }; //存放排查好雷的信息并用于展示
//初始化
Initboard(mine, ROWS, COLS, '0');
Initboard(show, ROWS, COLS, '*');
//打印
//Printboard(mine, ROWS, COLS);
Printboard(show, ROWS, COLS);
//布置雷
SetMines(mine, ROWS, COLS);
Printboard(mine, ROWS, COLS);
int x = 0;
int y = 0;
while (1)
{
printf("请输入坐标->");
scanf("%d %d", &x, &y);
int ret = Judgement(mine, show, x, y);
if ((-1) == ret)
{
printf("坐标已被占用,请重新输入\n");
continue;
}
else if (1 == ret)
{
printf("很遗憾,你被炸死了\n");
break;
}
//排查雷
PlayerRemove(mine, show, x, y);
Printboard(show, ROWS, COLS);
//判断
int ret1 = IsFull(show, ROW, COL);
if (ret1)
{
printf("恭喜玩家,排雷成功\n");
break;
}
}
}
int main()
{
int input = 0; //玩家输入选择
do
{
menu();
printf("请输入->");
scanf("%d", &input);
switch (input)
{
case 1:
game(); //进入游戏
break;
case 0:
printf("游戏结束\n"); //游戏结束
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
#define ROW 9
#define COL 9
#define ROWS (ROW + 2) //行
#define COLS (COL + 2) //列
#define NUMBER 5 //布置雷的数量
//初始化
void Initboard(char board[ROWS][COLS],int rows,int cols,char a);
//打印
void Printboard(char board[ROWS][COLS], int rows, int cols);
//布置雷
void SetMines(char mine[ROWS][COLS], int rows, int cols);
//排查雷
void PlayerRemove(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols);
//判断是否踩雷
int Judgement(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y);
//判断是否排查出所有雷
int IsFull(char show[ROWS][COLS], int row, int col);
//展开
void UnfoldSlice(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y);
#include "game.h"
//初始化
void Initboard(char board[ROWS][COLS], int rows, int cols, char a)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = a;
}
}
}
//打印
void Printboard(char board[ROWS][COLS], int rows, int cols)
{
int i = 0;
int 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 SetMines(char mine[ROWS][COLS], int rows, int cols)
{
int count = NUMBER;
while (count)
{
int x = rand() % 9 + 1;
int y = rand() % 9 + 1;
if (mine[x][y] == '0') //判断该位置是否已布置雷
{
mine[x][y] = '1';
count--;
}
}
}
//计算坐标周围雷的数量
int number(char board[ROWS][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 PlayerRemove(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
if (x > 0 && x <= ROW && y > 0 && y <= COL) //判断输入是否合法
{
if (show[x][y] == '*' && mine[x][y] != '1') //判断输入坐标是否被占用
{
show[x][y] = 48 + number(mine,x,y);
UnfoldSlice(mine, show, x, y);
}
}
}
//判断是否踩雷
int Judgement(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
if ((x > 0) && (x <= ROW) && (y > 0) && (y <= COL))
{
if (mine[x][y] == '1')
{
return 1; //踩雷返回1
}
else if (show[x][y] != '*')
{
return -1; //坐标被占用返回-1
}
else
{
return 0; //坐标正常返回0
}
}
else
{
return 2; //坐标不合法返回2
}
}
//判断是否排查出所有雷
int IsFull(char show[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
int num = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
if (show[i][j] == '*')
num++;
}
}
if (num == NUMBER)
{
return 1;
}
else
{
return 0;
}
}
//展开
void UnfoldSlice(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
int i = 0;
int j = 0;
if (0 == number(mine,x,y)) //判断坐标(x,y)周围雷的数量是否为0
{
show[x][y] = ' ';
for (i = -1; i <= 1; i++)
{
for (j = -1; j <= 1; j++)
{
if('*' == show[x+i][y+j])
UnfoldSlice(mine, show, x + i, y + j); //递归展开
}
}
}
else //坐标(x,y)周围雷的数量不为0时
{
show[x][y] = number(mine, x, y) + '0';
}
}