您的位置:首页 > 编程语言 > C语言/C++

C语言实现简单扫雷

2018-02-04 23:20 525 查看
扫雷游戏需要完成的内容主要分以下几个:

1.使用二维数组初始化扫雷的游戏布局,通过改变数组的行列来改变,用ROW来规定数组行数,COL来规定数组列数,扫雷需要用到两个二维数组,一个数组用来存放雷的信息,一个数组用来存放显示界面信息;

2.使用二维数组显示扫雷游戏界面,除了显示数组信息外,还需要在第一行和第一列显示坐标便于玩家观察;

3.设置雷区,根据游戏难度来随机放置固定个数的雷,将信息放在一个存雷数组里;

4.排雷,玩家走第一步的时候不能踩雷,所以当玩家第一步踩到雷时,重新设置雷区直到玩家选择的这个坐标没雷为止,玩家走第二步开始踩到雷就会直接输。每当玩家选择的这个坐标没雷时,则计算这个坐标周围一圈八个格子的雷的个数,如果这个坐标周围雷的个数为0个,则继续计算这个坐标周围八个格子每个格子的周围的八个格子的雷的个数,遇到雷的个数为0则继续进行计雷,这个算法需要用到递归来完成,在显示数组里将计算的雷的个数显示出来,若为0个则用空格代替,显示更清晰;

5.判断输赢,如果玩家踩到雷,则直接游戏结束,若未排的区域个数等于雷的个数且玩家没被炸死,则玩家赢。

在头文件中放置的是功能函数的定义,文件名为 game2.h 内容如下:

#ifndef __GAME_H__
#define __GAME_H__

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

enum OPTION
{
EXIT,
PLAY
};

#define ROW 9   //ROW和COL用来设置扫雷游戏的长宽
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10     //EASY_COUNT用来设置雷的个数

void InitPlayBoard(char PlayBoard[ROWS][COLS], int rows, int cols,char set);   //初始化扫雷游戏布局
void Display(char PlayBoard[ROWS][COLS], int row, int col);                    //在界面上显示游戏界面
void SetMine(char mine[ROWS][COLS], int row, int col);                         //设置雷
void FirstMove(int flag[ROWS][COLS], char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);                  //第一步(不会中雷)
void FindMine(int flag[ROWS][COLS], char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);              //排雷
#endif // !__GAME_H__

第一个源文件 game.c 用来放函数的具体实现,内容如下:

#include "game2.h"

//初始化游戏布局
void InitPlayBoard(char PlayBoard[ROWS][COLS], int rows, int cols, char set)
{
int i = 0, j = 0;
for (i = 0;i < rows;i++)
{
for (j = 0;j < cols;j++)
PlayBoard[i][j] = set;
}
}

//打印游戏界面
void Display(char PlayBoard[ROWS][COLS], int row, int col)
{
int i = 0, j = 0;
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 ", PlayBoard[i][j]);
}
printf("\n");
}
}

//布雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int x, y;
int count = EASY_COUNT;
srand(time(0));
while (count)
{
x = rand() % ROW + 1;
y = rand() % COL + 1;
if (mine[x][y] != '1')
{
mine[x][y] = '1';
count--;
}
}
}

//计雷函数
int countmine(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] + mine[x][y - 1] + mine[x][y + 1] + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1]-8*'0';
}

//爆炸函数(显示一片没有雷的区域)
void expend(int flag[ROWS][COLS],char mine[ROWS][COLS],char show[ROWS][COLS], int x, int y)
{
if (mine[x - 1][y - 1] != '1'&&x - 1 >= 1 && y - 1 >= 1)
{
show[x - 1][y - 1] = countmine(mine, x - 1, y - 1) + '0';
if (show[x - 1][y - 1] == '0')
show[x - 1][y - 1] = ' ';
}
if (mine[x - 1][y] != '1'&&x - 1 >= 1)
{
show[x - 1][y] = countmine(mine, x - 1, y) + '0';
if (show[x - 1][y] == '0')
show[x - 1][y] = ' ';
}
if (mine[x - 1][y + 1] != '1'&&x - 1 >= 1 && y + 1 <= COL)
{
show[x - 1][y + 1] = countmine(mine, x - 1, y + 1) + '0';
if (show[x - 1][y + 1] == '0')
show[x - 1][y + 1] = ' ';
}
if (mine[x][y - 1] != '1'&&y - 1 >= 1)
{
show[x][y - 1] = countmine(mine, x, y - 1) + '0';
if (show[x][y - 1] == '0')
show[x][y - 1] = ' ';
}
if (mine[x][y + 1] != '1'&&y + 1 <= COL)
{
show[x][y + 1] = countmine(mine, x, y + 1) + '0';
if (show[x][y + 1] == '0')
show[x][y + 1] = ' ';
}
if (mine[x + 1][y - 1] != '1'&&x + 1 <= ROW && y - 1 >= 1)
{
show[x + 1][y - 1] = countmine(mine, x + 1, y - 1) + '0';
if (show[x + 1][y - 1] == '0')
show[x + 1][y - 1] = ' ';
}
if (mine[x + 1][y] != '1'&&x + 1 <= ROW)
{
show[x + 1][y] = countmine(mine, x + 1, y) + '0';
if (show[x + 1][y] == '0')
show[x + 1][y] = ' ';
}
if (mine[x + 1][y + 1] != '1'&&x + 1 <= ROW && y + 1 <= COL)
{
show[x + 1][y + 1] = countmine(mine, x + 1, y + 1) + '0';
if (show[x + 1][y + 1] == '0')
show[x + 1][y + 1] = ' ';
}
flag[x][y] = 1;
if (show[x - 1][y - 1] == ' '&&x - 1 >= 1 && y - 1 >= 1&&flag[x - 1][y - 1]==0)
expend(flag,mine, show, x - 1, y - 1);
if (show[x - 1][y] == ' '&&x - 1 >= 1&&flag[x - 1][y]==0)
expend(flag,mine, show, x - 1, y);
if (show[x - 1][y + 1] == ' '&&x - 1 >= 1 && y + 1 <= COL &&flag[x - 1][y + 1]==0)
expend(flag,mine, show, x - 1, y + 1);
if (show[x][y - 1] == ' '&&y - 1 >= 1&&flag[x][y - 1]==0)
expend(flag,mine, show, x, y - 1);
if (show[x][y + 1] == ' '&&y + 1 <= COL &&flag[x][y + 1]==0)
expend(flag,mine, show, x, y + 1);
if (show[x + 1][y - 1] == ' '&&x + 1 <= ROW && y - 1 >= 1&&flag[x + 1][y - 1]==0)
expend(flag,mine, show, x + 1, y - 1);
if (show[x + 1][y] == ' '&&x + 1 <= ROW &&flag[x + 1][y]==0)
expend(flag,mine, show, x + 1, y);
if (show[x + 1][y + 1] == ' '&&x + 1 <= ROW && y + 1 <= COL &&flag[x + 1][y + 1]==0)
expend(flag,mine, show, x + 1, y + 1);
}

//第一步
void FirstMove(int flag[ROWS][COLS], char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x, y;
printf("请输入坐标:>");
scanf_s("%d %d", &x, &y);
if (x >= 1 && x <= ROW&&y >= 1 && y <= COL)
{
while(mine[x][y] == '1')
{
InitPlayBoard(mine, ROWS, COLS, '0');
SetMine(mine, ROW, COL);
Display(mine, ROW, COL);               //每次重新布雷后显示雷便于测试,游戏正常进行时可删去
}
show[x][y] = countmine(mine, x, y) + '0';
if (show[x][y] == '0')
{
show[x][y] = ' ';
expend(flag, mine, show, x, y);
}
Display(show, ROW, COL);
}
else
printf("输入坐标有误!\n");
}

//判断是否赢
int judgement(char show[ROWS][COLS],int row,int col)
{
int i, j;
int count = 0;
for (i = 1;i <= row;i++)
for (j = 1;j <= col;j++)
if (show[i][j] == '*')
count++;
if (count == EASY_COUNT)
return 0;
else
return 1;
}

//排雷
void FindMine(int flag[ROWS][COLS],char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x, y;
int win = 1;
do
{
printf("请输入坐标:>");
scanf_s("%d %d", &x, &y);
if (x >= 1 && x <= ROW&&y >= 1 && y <= COL)
{
if (mine[x][y] == '1')
{
Display(mine, ROW, COL);
printf("GAME OVER !\n");
break;
}
else
{
show[x][y] = countmine(mine,x,y)+'0';
if (show[x][y] == '0')
{
show[x][y] = ' ';
expend(flag, mine, show, x, y);
}
Display(show, ROW, COL);
win = judgement(show,row,col);
}
}
else
printf("输入坐标有误!\n");

} while (win);
if(win==0)
printf("玩家赢!\n");
}


第二个源文件 test.c 用来放主函数,运行游戏,内容如下:

#include "game2.h"

//打印菜单
void menu()
{
printf("***********************************\n");
printf("*****   1.PLAY        0.EXIT  *****\n");
printf("***********************************\n");
}

//游戏主体
void game()
{
int flag[ROWS][COLS] = { 0 };       //flag数组用于在爆炸函数中标记已爆炸过的节点,防止无限递归导致错误
char mine[ROWS][COLS] = { 0 };      //mine是雷区数组,用来存放雷的分布
char show[ROWS][COLS] = { 0 };
InitPlayBoard(mine, ROWS, COLS, '0');
InitPlayBoard(show, ROWS, COLS, '*');
Display(show, ROW, COL);
SetMine(mine, ROW, COL);
Display(mine, ROW, COL);                 //布雷后先显示雷,便于测试
FirstMove(flag, mine, show, ROW, COL);
FindMine(flag,mine, show, ROW, COL);
}

//测试函数
void test()
{
int input=1;
do {
menu();
printf("请输入选择:>");
scanf_s("%d", &input);
switch (input)
{
case PLAY:
game();
case EXIT:
break;
default:
printf("选择错误!");
}
} while (input);

}

//主函数
int main()
{
test();
return 0;
}

在菜单界面按1开始游戏,显示如下:



任意输入一个坐标,如4 6,这个坐标周围都没雷,因此没雷区域会扩散开来,显示的结果如下:



当我们第一个输入的坐标有雷时,游戏会重新布雷,防止第一步玩家就被炸死,第二步开始再踩到雷时,游戏结束,玩家输。

输出结果如下:





测试时为了便于测试先将雷改成78个,只要正确扫三次就赢,玩家赢的游戏结果如下:



注:该程序是在VS2015上完成的,将scanf写成了scanf_s,正常情况下写scanf即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: