扫雷(C语言)
思路:
进行扫雷游戏,每次点击,若该位置有雷,则游戏结束,若无雷,则显示周围雷的数量,一直进行循环直至游戏结束(胜利或失败);
但一般情况下,第一次点到雷不会显示游戏结束,而是会把雷移到别的位置,不会让用户第一次落子就游戏结束;
另外,若用户点击,该位置及周围都没有雷就将附近没有雷的地方都展开。
在设计过程中,设计者和用户看到的是两个不同的棋盘,但是大小都是12 x 12的,设计者布雷的区域和用户排雷的区域都是中间10 x 10的部分;
用到的函数:
void Menu();//菜单
void Setmine(char show[][COL], int row, int col);//布雷
void Show(char show[][COL], int row, int col);//显示游戏过程
int Getmine(char mine[][COL], int row, int col);//获取雷的数量
void Openmine(char mine[ROW][COL], char show[ROW][COL], int row, int col, int x, int y);//展开没有雷的区域
void Game();//游戏逻辑
各部分代码及作用:
Menu()函数:
这一部分就是用简单的printf语句来显示菜单的;
void Menu()
{
printf("\t\t\t*******************************************************\n\n\n");
printf("\t\t\t******************** 欢迎来到扫雷游戏 *******************\n\n\n");
printf("\t\t\t****************** 1、Play 2、Exit ******************\n\n\n");
printf("\t\t\t*******************************************************\n\n");
}
Setmine(char mine[][COL], int row, int col)函数:
这一部分是用来布雷的,在这里用了随机数,随机的布雷,通过对10取余,再加1的操作,控制雷落下的坐标在1和10之间;
void Setmine(char mine[][COL], int row, int col)
{
int count = NUM;
while (count > 0){
int x = rand() % (row - 2) + 1;
int y = rand() % (col - 2) + 1;
if (mine[x][y] == '0'){
mine[x][y] = '1';
count--;
}
}
}
Show(char show[][COL], int row, int col)函数:
这一部分是用于显示用户看到的扫雷界面(一个10*10的界面),通过不断使用for循环实现扫雷界面的输出;
void Show(char show[][COL], int row, int col)
{
int i = 0;
int j = 0;
printf(" ");
for (i = 1; i <= 10; i++){
printf(" %d ", i);
}
printf("\n");
for (i = 1; i <= 10; i++){
printf("----");
}
printf("----\n");
for (i = 1; i <= 10; i++){
printf(" %2d |", i);
for (j = 1; j <= 10; j++){
printf(" %c |", show[i][j]);
}
printf("\n");
int k = 0;
for (k = 1; k <= 10; k++){
printf("----");
}
printf("----\n");
}
}
Getmine(char mine[][COL], int x, int y)函数:
这一部分是用于表示用户排雷坐标周围的类的数量的,这里只是简单地将用户排雷坐标周围的八个位置相加再减去字符’0’的个数即可;
int Getmine(char mine[][COL], 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';
}
Openmine(char mine[ROW][COL], char show[ROW][COL], int row, int col, int x, int y)函数:
这一部分用于展开用户排雷坐标周围没有雷的情况,在这里用到了递归函数;首先,对用户排雷坐标进行判断,若确定在此坐标周围没有雷,那么就将该坐标的’*‘换成’0’,然后继续判断,若该坐标周围的坐标,坐标合法且没有被排过,则继续调用该函数,进行如上操作,若该坐标周围有雷,则将雷的个数显示在界面上该坐标处
void Openmine(char mine[ROW][COL], char show[ROW][COL], int row, int col, int x, int y)
{
int m = 0;
m = Getmine(mine, x, y);
if (m == 0){
show[x][y] = '0';
if (x - 1 > 0 && y - 1 > 0 && show[x - 1][y - 1] == '*'){
Openmine(mine, show, row, col, x - 1, y - 1);
}
if (x - 1 > 0 && y > 0 && show[x - 1][y] == '*'){
Openmine(mine, show, row, col, x - 1, y );
}
if (x - 1 > 0 && y + 1 > 0 && show[x - 1][y + 1] == '*'){
Openmine(mine, show, row, col, x - 1, y + 1);
}
if (x > 0 && y - 1 > 0 && show[x][y - 1] == '*'){
Openmine(mine, show, row, col, x , y - 1);
}
if (x > 0 && y + 1 > 0 && show[x ][y + 1] == '*'){
Openmine(mine, show, row, col, x , y + 1);
}
if (x + 1 > 0 && y - 1 > 0 && show[x + 1][y - 1] == '*'){
Openmine(mine, show, row, col, x + 1, y - 1);
}
if (x + 1 > 0 && y > 0 && show[x + 1][y ] == '*'){
Openmine(mine, show, row, col, x + 1, y );
}
if (x + 1 > 0 && y + 1 > 0 && show[x + 1][y + 1] == '*'){
Openmine(mine, show, row, col, x + 1, y + 1);
}
}
else{
show[x][y] = Getmine(mine, x, y)+'0';
}
}
Game()函数:
在这个函数中,首先,对用于布雷和用于显示的数组进行初始化(在这里用了memset()函数,或者用for循环也可以),将布雷的界面初始化全都是’ 0 ‘,将显示的界面初始化为全部都是’ * ',然后调用Setmine(char mine[][COL], int row, int col)函数布雷,接下来用户就可以开始排雷了,若用户输入坐标不合法,跳出本次循环,进入下一次循环;若用户输入坐标合法,即判断该坐标是否有雷;若第一次输入坐标有雷,将雷挪开,随机放入一个没有雷的位置,若不是第一次输入有雷,则显示游戏失败,并显示雷的分布;若该坐标没有雷,则显示该坐标周围雷数;若雷全都排除则显示用户游戏成功,并显示雷的分布。
void Game()
{
srand((unsigned)time(NULL));
char mine[ROW][COL];
char show[ROW][COL];
int x = 0;
int y = 0;
int times = ROW*COL - NUM;
memset(mine, '0', sizeof(mine));
memset(show, '*', sizeof(show));
Setmine(mine, ROW, COL);
do{
Show(show, ROW, COL);
printf("请输入坐标(x,y) > ");
scanf("%d %d", &x, &y);
if (x<1 || x>10 || y<1 || y>10){
printf("你输入的坐标有误,请重新输入坐标!\n");
continue;
}
if (show[x][y] != '*'){
printf("该位置已经排过了,请重新输入坐标!\n");
continue;
}
if (mine[x][y] == '1'){
if (times == ROW*COL - NUM){
mine[x][y] = '0';
int i = rand() % (ROW - 2) + 1;
int j = rand() % (COL - 2) + 1;
if (mine[i][j] == '0'){
times--;
mine[i][j] = '1';
}
}
else{
printf("真遗憾,你踩到雷了,游戏结束\n");
printf("雷的分布图如下 > \n");
Show(mine, ROW, COL);
break;
}
}
int mine_num = Getmine(mine, x, y);
show[x][y] = mine_num + '0';
Openmine(mine, show, ROW, COL, x, y);
times--;
} while (time > 0);
if (times == 0){
printf("恭喜,你赢了!\n");
printf("雷的分布图如下 > \n");
Show(mine, ROW, COL);
}
}
要注意的地方
1、在布雷的时候,产生的随机数是从0开始的,但是我们要用的是1到10;所以要对10取余载加1;
2、布雷的时候,在合法的位置布雷时,要注意赋值的’ = ‘不要写成’ == ‘;
3、虽然输出的是一个10 x 10的界面,但是为了方便起见,设计的是12 x 12的数组。
4、由于定义的数组都是字符型的,所以显示用户排雷坐标周围雷数时,还要再加上’ 0 ’
可以改进的地方
1、为了更清楚明了,可以把用户排雷和第一步踩雷不死,写成单独的函数;
2、可以另加游戏难度的选项,让使用者有更多的选择。
运行结果:
最开始的菜单:
开始游戏,显示初始化界面:
开始排雷:
坐标周围没有雷,展开:
输入坐标已排过:
输入坐标有误:
踩到有雷的坐标,给出提示并输出雷的分布图:
选择2,退出:
完整代码:
本次程序使用多文件编译的,分别有game.h ;game.c ;main.c
game.h
#ifndef __GAME_H__
#define __GAME_H__
#include<stdio.h>
#include<windows.h>
#include<time.h>
#include<string.h>
#define ROW 12
#define COL 12
#define NUM 20
#pragma warning(disable:4996)
void Menu();
void Setmine(char show[][COL], int row, int col);
void Show(char show[][COL], int row, int col);
int Getmine(char mine[][COL], int row, int col);
void Openmine(char mine[ROW][COL], char show[ROW][COL], int row, int col, int x, int y);
void Game();
#endif
game.c
#include"game.h"
void Menu()
{
printf("\t\t\t*******************************************************\n\n\n");
printf("\t\t\t******************* 欢迎来到扫雷游戏 ******************\n\n\n");
printf("\t\t\t****************** 1、Play 2、Exit ******************\n\n\n");
printf("\t\t\t*******************************************************\n\n");
}
void Setmine(char mine[][COL], int row, int col)
{
int count = NUM;
while (count > 0){
int x = rand() % (row - 2) + 1;
int y = rand() % (col - 2) + 1;
if (mine[x][y] == '0'){
mine[x][y] = '1';
count--;
}
}
}
void Show(char show[][COL], int row, int col)
{
int i = 0;
int j = 0;
printf(" ");
for (i = 1; i <= 10; i++){
printf(" %d ", i);
}
printf("\n");
for (i = 1; i <= 10; i++){
printf("----");
}
printf("----\n");
for (i = 1; i <= 10; i++){
printf(" %2d |", i);
for (j = 1; j <= 10; j++){
printf(" %c |", show[i][j]);
}
printf("\n");
int k = 0;
for (k = 1; k <= 10; k++){
printf("----");
}
printf("----\n");
}
}
int Getmine(char mine[][COL], 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 Openmine(char mine[ROW][COL], char show[ROW][COL], int row, int col, int x, int y)
{
int m = 0;
m = Getmine(mine, x, y);
if (m == 0){
show[x][y] = '0';
if (x - 1 > 0 && y - 1 > 0 && show[x - 1][y - 1] == '*'){
Openmine(mine, show, row, col, x - 1, y - 1);
}
if (x - 1 > 0 && y > 0 && show[x - 1][y] == '*'){
Openmine(mine, show, row, col, x - 1, y );
}
if (x - 1 > 0 && y + 1 > 0 && show[x - 1][y + 1] == '*'){
Openmine(mine, show, row, col, x - 1, y + 1);
}
if (x > 0 && y - 1 > 0 && show[x][y - 1] == '*'){
Openmine(mine, show, row, col, x , y - 1);
}
if (x > 0 && y + 1 > 0 && show[x ][y + 1] == '*'){
Openmine(mine, show, row, col, x , y + 1);
}
if (x + 1 > 0 && y - 1 > 0 && show[x + 1][y - 1] == '*'){
Openmine(mine, show, row, col, x + 1, y - 1);
}
if (x + 1 > 0 && y > 0 && show[x + 1][y ] == '*'){
Openmine(mine, show, row, col, x + 1, y );
}
if (x + 1 > 0 && y + 1 > 0 && show[x + 1][y + 1] == '*'){
Openmine(mine, show, row, col, x + 1, y + 1);
}
}
else{
show[x][y] = Getmine(mine, x, y)+'0';
}
}
void Game()
{
srand((unsigned)time(NULL));
char mine[ROW][COL];
char show[ROW][COL];
int x = 0;
int y = 0;
int times = ROW*COL - NUM;
memset(mine, '0', sizeof(mine));
memset(show, '*', sizeof(show));
Setmine(mine, ROW, COL);
do{
Show(show, ROW, COL);
printf("请输入坐标(x,y) > ");
scanf("%d %d", &x, &y);
if (x<1 || x>10 || y<1 || y>10){
printf("你输入的坐标有误,请重新输入坐标!\n");
continue;
}
if (show[x][y] != '*'){
printf("该位置已经排过了,请重新输入坐标!\n");
continue;
}
if (mine[x][y] == '1'){
if (times == ROW*COL - NUM){
mine[x][y] = '0';
int i = rand() % (ROW - 2) + 1;
int j = rand() % (COL - 2) + 1;
if (mine[i][j] == '0'){
times--;
mine[i][j] = '1';
}
}
else{
printf("真遗憾,你踩到雷了,游戏结束\n");
printf("雷的分布图如下 > \n");
Show(mine, ROW, COL);
break;
}
}
int mine_num = Getmine(mine, x, y);
show[x][y] = mine_num + '0';
Openmine(mine, show, ROW, COL, x, y);
times--;
} while (time > 0);
if (times == 0){
printf("恭喜,你赢了!\n");
printf("雷的分布图如下 > \n");
Show(mine, ROW, COL);
}
}
main.c
#include"game.h"
void main()
{
int quit = 1;
int select = 0;
while (quit){
Menu();
printf("请输入你的选择 > ");
scanf("%d", &select);
switch (select){
case 1:
Game();
break;
case 2:
quit = 0;
break;
default:
printf("您的输入有误,请重新输入!");
break;
}
}
system("pause");
}