扫雷游戏很多人都玩过吧,今天就为大家介绍我用c语言制作的简单扫雷程序。
这个游戏的主要功能就是Game()函数的实现,用一个类型为char 的show_map二维数组进行标记一定数量的地雷,不打印给玩家和另一个同类型的名为mine_map的二维数组,用于记录坐标周围的地雷数。玩游戏的功能都是围绕这两个函数操作开展的。
Game()函数思路:
- 首先对两个数组定义并初始化,
- 然后再植入地雷,
- 再输入坐标并判断该坐标下是否触雷,若触雷, 则直接游戏结束。否则继续
- 统计该坐标周围的地雷数,并将该坐标元素改为该坐标周围的地雷数,
- 打印所有格子(翻开的坐标,打印该坐标周围的地雷数)
- 当排除所有地雷时,并且未触雷,游戏成功!
接下来看一下代码:
//game.h
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define MAX_ROW 9
#define MAX_COL 9
#define MAX_COUNT 10
int Menu();//打印菜单并返回选择函数
void Init(char show_map[][MAX_COL], char mine_map[][MAX_COL]);//初始化数组,将show_map全部初始化为*,mine_map全部初始化为0
void ProLand(char mine_map[][MAX_COL],int r ,int c);//初始化地雷函数,在mine_map[][]上随机产生MAX_COUNT个地雷,并将产生地雷的地方修改为1
void Print(char show_map[][MAX_COL]);//打印函数,将传入的数组按格式打印出来
int MineNum(const char mine_map[][MAX_COL], int row, int col);//返回mine_map[row][col]周围的地雷数
int LeapMine(char show_map[][MAX_COL]);//返回未排掉的格子数(包括未排出的地雷)
void Game();//游戏函数
void PrintOver(char mine_map[][MAX_COL]);//踩雷后打印所有雷的位置
//main.c
#include"game.h"
int Menu()
{
printf("=================================================\n");
printf("************ 1.开始游戏 ***********\n");
printf("************ 0.结束游戏 ***********\n");
printf("=================================================\n");
printf("请输入你的选择:");
int choice = 0;
scanf("%d", &choice);
return choice;
}
void Init(char show_map[][MAX_COL], char mine_map[][MAX_COL])
{
int row = 0;
int col = 0;
for (row = 0; row < MAX_ROW; ++row)
{
for (col = 0; col < MAX_COL; ++col)
{
show_map[row][col] = '*';//初始化show_map[][],即翻开的结果
mine_map[row][col] = '0';//初始化mine_map[][],初始化地雷
}
}
}
void ProLand(char mine_map[][MAX_COL],int r,int c)//在mine_map[][]上随机产生MAX_COUNT个地雷,并将产生地雷的地方修改为1
{
int count = MAX_COUNT;
while (count)
{
int row = rand() % MAX_ROW;
int col = rand() % MAX_COL;
if ((mine_map[row][col] == '0')//初始化雷的分布,但不能在第一次输入的坐标下出现雷
&& ((row<r-1)
|| (row>r+1)
|| (col<c - 1)
|| (col>c + 1))
)
{
mine_map[row][col] = '1';
--count;
}
}
}
void Print(char show_map[][MAX_COL])//打印
{
int row = 0;
int col = 0;
printf(" |");
for (int i = 0; i < MAX_COL; ++i)
{
printf("%d ", i);
}
printf("\n----------------------");
for (row = 0; row < MAX_ROW; ++row)
{
printf("\n%d|", row);
for (col = 0; col < MAX_COL; ++col)
{
printf("%c ", show_map[row][col]);
}
}
printf("\n");
}
void PrintOver(char mine_map[][MAX_COL])
{
int i, j;
printf(" |");
for (i = 0; i < MAX_COL; ++i)
{
printf(" %d ", i);
}
printf("\n------------------------------");
for (i = 0; i < MAX_ROW; ++i)
{
printf("\n%d |", i);
for (j = 0; j < MAX_COL; ++j)
{
if (mine_map[i][j] == '1')
{
printf(" !");
}
else
{
printf(" O ");
}
}
printf("\n");
}
}
int MineNum(const char mine_map[][MAX_COL], int row, int col)//返回mine_map[row][col]周围的地雷数
{
int count = 0;
if ((row - 1 >= 0) && (col - 1 >= 0) && (mine_map[row - 1][col - 1] == '1'))//坐标左上角
{
++count;
}
if ((row - 1 >= 0) && (mine_map[row - 1][col] == '1'))//坐标正上方
{
++count;
}
if ((row - 1 >= 0) && (col + 1 <= MAX_COL) && (mine_map[row - 1][col + 1] == '1'))//坐标右上方
{
++count;
}
if ((col - 1 >= 0) && (mine_map[row][col - 1] == '1'))//坐标左边
{
++count;
}
if ((col + 1 <= MAX_COL) && (mine_map[row][col + 1] == '1'))//坐标右边
{
++count;
}
if ((row + 1<=MAX_ROW) && (col - 1 >= 0) && (mine_map[row + 1][col - 1] == '1'))//坐标左下
{
++count;
}
if ((row + 1 <= MAX_ROW) && (mine_map[row + 1][col] == '1'))//坐标正下
{
++count;
}
if ((row + 1 <= MAX_ROW) && (col + 1 <= MAX_COL) && (mine_map[row + 1][col + 1] == '1'))//坐标右下
{
++count;
}
return count;
}
int LeapMine(char show_map[][MAX_COL])//返回未排掉的格子数(包括未排出的地雷)
{
int count = 0;
int row, col;
for (row = 0; row < MAX_ROW; ++row)
{
for (col = 0; col < MAX_COL; ++col)
{
if (show_map[row][col] == '*')
{
++count;
}
}
}
return count;
}
void Game()
{
int row, col;
srand((unsigned)time(NULL));
char show_map[MAX_ROW][MAX_COL];//翻开后显示地雷数,翻开前全初始化为*
char mine_map[MAX_ROW][MAX_COL];//产生地雷的地方修改为‘1’.没有地雷的地方全部初始化为'0'
Init(show_map, mine_map);
printf("请输入你要翻开的坐标:");
while (1)
{
scanf("%d%d", &row, &col);
if (row < 0 || row >= MAX_ROW || col < 0 || col >= MAX_COL)
{
printf("输入的坐标非法,请重新输入:");
continue;
}
else
{
break;
}
}
ProLand(mine_map,row,col);
show_map[row][col] = MineNum(mine_map, row, col) + '0';
while (1)
{
system("cls");
Print(show_map);
printf("\n\n");
//Print(mine_map);//该行代码用于测试
printf("请输入你要翻开的坐标:");
while (1)
{
scanf("%d%d", &row, &col);
if (row < 0 || row >= MAX_ROW || col < 0 || col >= MAX_COL)
{
printf("输入的坐标非法,请重新输入:");
continue;
}
else if (show_map[row][col] != '*')
{
printf("您输入的坐标已被翻开,请重新输入:");
continue;
}
else
{
break;
}
}
if (mine_map[row][col] == '1')
{
printf("踩雷了,game over!\n");
PrintOver(mine_map);
break;
}
else
{
show_map[row][col] = MineNum(mine_map, row, col) + '0';
}
if (LeapMine(show_map) == MAX_COUNT)
{
printf("恭喜勇士,成功排掉所有地雷!\n");
break;
}
}
}
int main()
{
while (1)
{
int choice = Menu();
if (choice == 1)
{
Game();
}
else if (choice == 0)
{
printf("goodbye!\n");
break;
}
else
{
printf("您输入有误!\n");
}
}
system("pause");
return 0;
}
这里需要注意的几点:
- 为了不让玩家在第一次踩雷,ProLand函数是在输入第一次坐标后开始植入地雷的,并且植入的地雷避开了第一次输入坐标周围的格子。
- PrintOver函数是在玩家触雷后退出游戏前打印地雷的分布,目的是为了接近真实的扫雷游戏
- MineNum函数实现返回输入坐标周围的地雷个数,返回值为数值,将该数加上‘0’并赋给该坐标上的字符型元素。
- LeapMine返回未排掉的格子,当剩余的各自等于植入的格子数时,说明除地雷外所有的格子都已被排完。此时结束游戏。