欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

扫雷(C语言)

程序员文章站 2024-03-18 13:14:10
...

思路:
进行扫雷游戏,每次点击,若该位置有雷,则游戏结束,若无雷,则显示周围雷的数量,一直进行循环直至游戏结束(胜利或失败);

但一般情况下,第一次点到雷不会显示游戏结束,而是会把雷移到别的位置,不会让用户第一次落子就游戏结束;

另外,若用户点击,该位置及周围都没有雷就将附近没有雷的地方都展开。

在设计过程中,设计者和用户看到的是两个不同的棋盘,但是大小都是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、可以另加游戏难度的选项,让使用者有更多的选择。

运行结果:

最开始的菜单:
扫雷(C语言)

开始游戏,显示初始化界面:

扫雷(C语言)
开始排雷:
扫雷(C语言)
坐标周围没有雷,展开:
扫雷(C语言)
输入坐标已排过:
扫雷(C语言)
输入坐标有误:
扫雷(C语言)
踩到有雷的坐标,给出提示并输出雷的分布图:
扫雷(C语言)
选择2,退出:
扫雷(C语言)

完整代码:
本次程序使用多文件编译的,分别有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");
}