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

C语言实现扫雷游戏

程序员文章站 2024-03-18 13:48:34
...

C语言实现扫雷游戏,可以大致分为一下几个部分。
 
 
 
· 选择两个棋盘,一个棋盘负责显示,另一个棋盘进行布雷。
 
 
 
· 初始化两个棋盘,显示棋盘全部初始化为:‘*’,布雷棋盘全部初始化为:‘0’
 
 
 
· 进行布雷操作,采用随机数,对布雷棋盘进行随机布雷。
 
 
 
· 显示棋盘。对用户输入的坐标进行显示,并将该坐标显示为附近坐标的雷数。
 
 
 
· 炸开输入坐标附近无雷的坐标。
 
 
 
· 结果判定,若显示棋盘上的‘*’数和雷数NUM相等,则扫雷成功。

 
 
 
1. 选择两个棋盘。

	char board[ROW][COL];
	char mine[ROW][COL];

这两个棋盘都是12 * 12 的,但显示的时候只显示10 * 10的,为什么呢?
C语言实现扫雷游戏
里面是一个10 * 10的棋盘,外面为12 * 12的棋盘。
当初始化的时候,对全部进行初始化, 而当在计算的布雷和显示的时候,仅仅只显示10 * 10的棋盘。
在计算附近雷数的时候,可以很方面的计算出,第一行第一列,最后一行最后一列附近的雷数,而不用再进行if判定。

比如这样:
C语言实现扫雷游戏
这样就可以直接计算出(1,1)坐标附近的雷数。

 
 
 
2.初始化棋盘

void Initial(char board[][COL], int row, int col,char p)//棋盘初始化函数,在这里,需要对全部棋盘进行初始化
{
	int i = 0;
	for (; i < row; i++)
	{
		int j = 0;
		for (; j < row; j++)
		{
			board[i][j] = p;
		}
	}
}

棋盘初始化函数,在这里,需要对全部棋盘进行初始化。因为,后面需要计算输入坐标附近的雷数,则需要对整个棋盘进行初始化。

 
 
 
3.布雷

void SetMine(char mine[][COL], int row, int col,int n)//布雷,使用随机数进行布雷,同样,只对1~10行列进行布雷
{
	while (n)
	{
		int i = rand() % (row - 2) + 1;
		int j = rand() % (col - 2) + 1;
		if (mine[i][j] == ONE)
		{
			continue;
		}
		mine[i][j] = ONE;
		n--;
	}
}

进行布雷,只需要对10 * 10大小的进行布雷。

ONE='1',为雷,ZERO='0',无雷。

 
 
 
4.显示棋盘

void Show(char board[][COL], int row, int col)//棋盘显示,这里只显示1~10行列的棋盘
{
	int i = 0;
	for (i = 1; i < row - 1; i++)
	{
		printf("%s", "---");
	}
	printf("---\n");
	printf("   ");
	for (i=1; i < row - 1; i++)
	{
		printf("%2d|", i);
	}
	printf("\n");
	for (i = 1; i < row - 1; i++)
	{
		printf("%s", "---");
	}
	printf("---\n");
	for (i = 1; i < row - 1; i++)
	{
		printf("%2d|", i);
		int j = 1;
		for (; j < col - 1; j++)
		{
			printf("%2c|", board[i][j]);
		}
		printf("\n");
		for (j = 1; j < row - 1; j++)
		{
			printf("%s", "---");
		}
		printf("---\n");
	}
}

在这里,显示同样只显示10 * 10 大小的棋盘。

 
 
 
5.显示输入坐标附近的雷数

char GetNum(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] - 7 * ZERO;
}

C语言实现扫雷游戏
输入坐标(x,y),显示附近⑧个坐标总的雷数,并返回字符。‘1’=‘0’+1,‘2’=‘0’+2,‘3’=‘0’+3

 
 
 
6.炸开输入坐标附近的坐标

在这里,可以使用递归方式炸开,但这样炸开,直接就炸开了整个坐标系。

void Boom(char mine[][COL], char board[][COL], int x, int y)//递归展开,这样展开就展开了全部棋盘
{
	char num = mine[x][y];
	if (num == ZERO)
	{
		board[x][y] = GetNum(mine, x, y);
		if (board[x - 1][y - 1] == '*')
		{
			Boom(mine, board, x - 1, y - 1);
		}
		if (board[x - 1][y ] == '*')
		{
			Boom(mine, board, x - 1, y );
		}
		if (board[x - 1][y + 1] == '*')
		{
			Boom(mine, board, x - 1, y + 1);
		}
		if (board[x ][y - 1] == '*')
		{
			Boom(mine, board, x , y - 1);
		}
		if (board[x][y + 1] == '*')
		{
			Boom(mine, board, x, y + 1);
		}
		if (board[x+1][y - 1] == '*')
		{
			Boom(mine, board, x+1, y - 1);
		}
		if (board[x + 1][y ] == '*')
		{
			Boom(mine, board, x + 1, y );
		}
		if (board[x + 1][y+1] == '*')
		{
			Boom(mine, board, x + 1, y+1);
		}
	}
}

这样炸,会将整个棋盘全部炸开,扫雷就自动实现了。
另一种方法,只炸开,输入坐标附近的⑧个坐标。

void Boom2(char mine[][COL], char board[][COL], int x, int y)//炸开输入坐标附近的几个坐标的雷数
{
	board[x][y] = GetNum(mine, x, y);
	if (mine[x - 1][y - 1] == ZERO)
	{
		board[x - 1][y - 1] = GetNum(mine, x - 1, y - 1);
	}
	if (mine[x - 1][y] == ZERO)
	{
		board[x - 1][y] = GetNum(mine, x - 1, y);
	}
	if (mine[x - 1][y + 1] == ZERO)
	{
		board[x - 1][y + 1] = GetNum(mine, x - 1, y + 1);
	}
	if (mine[x][y - 1] == ZERO)
	{
		board[x][y - 1] = GetNum(mine, x, y - 1);
	}
	if (mine[x][y + 1] == ZERO)
	{
		board[x][y + 1] = GetNum(mine, x, y + 1);
	}
	if (mine[x + 1][y - 1] == ZERO)
	{
		board[x + 1][y - 1] = GetNum(mine, x + 1, y - 1);
	}
	if (mine[x + 1][y] == ZERO)
	{
		board[x + 1][y] = GetNum(mine, x + 1, y);
	}
	if (mine[x + 1][y + 1] == ZERO)
	{
		board[x + 1][y + 1] = GetNum(mine, x + 1, y + 1);
	}
}

这样就可以一步步完成扫雷。

 
 
 
7.结果判定

		for (i = 1; i < ROW - 1; i++)//计算board上‘*’的数为多少
		{
			int j = 0;
			for (j = 1; j < ROW - 1; j++)
			{
				if (board[i][j] == '*')
				{
					number++;
				}
			}
		}
		if (number == NUM)//若‘*’数和NUM相等,结束循环
		{
			break;
		}
		
	if (number == NUM)//结果判定
	{
		Sleep(2000);
		system("cls");
		printf("\n恭喜你,完美通关!\n");
	}
	else
	{
		Sleep(2000);
		system("cls");
		printf("\n很遗憾,游戏失败,再接再厉!\n");
	}

 
 
 
源程序及注释:

//分了三个文件夹写
//test.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <Windows.h>
#pragma warning(disable:4996)

#define ROW 12   //棋盘数
#define COL 12
#define NUM 50   //雷数
#define ZERO '0'  //没有雷
#define ONE '1'   //雷

void Game();
void Initial(char board[][COL], int row, int col,char p);//初始化
void Show(char board[][COL], int row, int col);//显示棋盘
void SetMine(char mine[][COL], int row, int col,int n);//布雷
char GetNum(char mine[][COL],int x,int y);//获得附近的雷数
void Boom(char mine[][COL], char board[][COL], int x, int y);//递归展开
void Boom2(char mine[][COL], char board[][COL], int x, int y);//展开附近几个点的雷数



//main.c
void Menu()
{
	printf("###############################\n");
	printf("##     1.Play      2.Quit    ##\n");
	printf("###############################\n");
	printf("Please input your choice:>");
}
int main()
{
	int select = 1;
	while (select == 1)
	{
		Menu();
		scanf("%d", &select);
		switch (select)
		{
		case 1:
			Game();
			printf("\n要不要再玩一局?\n");
			break;
		case 2:
			break;
		default:
			break;
		}
	}
	return 0;
}



//test.c

void Initial(char board[][COL], int row, int col,char p)//棋盘初始化函数,在这里,需要对全部棋盘进行初始化
{
	int i = 0;
	for (; i < row; i++)
	{
		int j = 0;
		for (; j < row; j++)
		{
			board[i][j] = p;
		}
	}
}

void Show(char board[][COL], int row, int col)//棋盘显示,这里只显示1~10行列的棋盘
{
	int i = 0;
	for (i = 1; i < row - 1; i++)
	{
		printf("%s", "---");
	}
	printf("---\n");
	printf("   ");
	for (i=1; i < row - 1; i++)
	{
		printf("%2d|", i);
	}
	printf("\n");
	for (i = 1; i < row - 1; i++)
	{
		printf("%s", "---");
	}
	printf("---\n");
	for (i = 1; i < row - 1; i++)
	{
		printf("%2d|", i);
		int j = 1;
		for (; j < col - 1; j++)
		{
			printf("%2c|", board[i][j]);
		}
		printf("\n");
		for (j = 1; j < row - 1; j++)
		{
			printf("%s", "---");
		}
		printf("---\n");
	}
}

void SetMine(char mine[][COL], int row, int col,int n)//布雷,使用随机数进行布雷,同样,只对1~10行列进行布雷
{
	while (n)
	{
		int i = rand() % (row - 2) + 1;
		int j = rand() % (col - 2) + 1;
		if (mine[i][j] == ONE)
		{
			continue;
		}
		mine[i][j] = ONE;
		n--;
	}
}

char GetNum(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] - 7 * ZERO;
}

void Boom(char mine[][COL], char board[][COL], int x, int y)//递归展开,这样展开就展开了全部棋盘
{
	char num = mine[x][y];
	if (num == ZERO)
	{
		board[x][y] = GetNum(mine, x, y);
		if (board[x - 1][y - 1] == '*')
		{
			Boom(mine, board, x - 1, y - 1);
		}
		if (board[x - 1][y ] == '*')
		{
			Boom(mine, board, x - 1, y );
		}
		if (board[x - 1][y + 1] == '*')
		{
			Boom(mine, board, x - 1, y + 1);
		}
		if (board[x ][y - 1] == '*')
		{
			Boom(mine, board, x , y - 1);
		}
		if (board[x][y + 1] == '*')
		{
			Boom(mine, board, x, y + 1);
		}
		if (board[x+1][y - 1] == '*')
		{
			Boom(mine, board, x+1, y - 1);
		}
		if (board[x + 1][y ] == '*')
		{
			Boom(mine, board, x + 1, y );
		}
		if (board[x + 1][y+1] == '*')
		{
			Boom(mine, board, x + 1, y+1);
		}
	}
}

void Boom2(char mine[][COL], char board[][COL], int x, int y)//炸开输入坐标附近的几个坐标的雷数
{
	board[x][y] = GetNum(mine, x, y);
	if (mine[x - 1][y - 1] == ZERO)
	{
		board[x - 1][y - 1] = GetNum(mine, x - 1, y - 1);
	}
	if (mine[x - 1][y] == ZERO)
	{
		board[x - 1][y] = GetNum(mine, x - 1, y);
	}
	if (mine[x - 1][y + 1] == ZERO)
	{
		board[x - 1][y + 1] = GetNum(mine, x - 1, y + 1);
	}
	if (mine[x][y - 1] == ZERO)
	{
		board[x][y - 1] = GetNum(mine, x, y - 1);
	}
	if (mine[x][y + 1] == ZERO)
	{
		board[x][y + 1] = GetNum(mine, x, y + 1);
	}
	if (mine[x + 1][y - 1] == ZERO)
	{
		board[x + 1][y - 1] = GetNum(mine, x + 1, y - 1);
	}
	if (mine[x + 1][y] == ZERO)
	{
		board[x + 1][y] = GetNum(mine, x + 1, y);
	}
	if (mine[x + 1][y + 1] == ZERO)
	{
		board[x + 1][y + 1] = GetNum(mine, x + 1, y + 1);
	}
}


void Game()
{
	srand((int)time(0));
	char board[ROW][COL];
	char mine[ROW][COL];

	Initial(board, ROW, COL, '*');//显示棋盘初始化,初始化为‘*’
	Initial(mine, ROW, COL, ZERO);//初始化布雷棋盘,初始化为‘0’
	SetMine(mine, ROW, COL,NUM);//布雷,布雷个数为NUM个,布雷为‘1’
	//Show(board, ROW, COL);
	//Show(mine, ROW, COL);

	int number = 0;//这里是为了判定,显示棋盘上的‘*’和NUM数相等,就表示扫雷成功
	while (1)
	{
		system("cls");
		Show(board, ROW, COL);
		int x = 0;
		int y = 0;
		int i = 0;
		number = 0;
		printf("请输入要扫的坐标:>");
		scanf("%d %d", &x, &y);
		printf("正在显示....\n");
		if (x<1 || x>(ROW - 2) || y<1 || y>(ROW - 2))//对输入进行判定,输入坐标大了
		{
			printf("输入坐标错误,请重新输入...\n");
			Sleep(1000);
			continue;
		}
		if (board[x][y] != '*')//输入坐标被扫过了
		{
			printf("输入坐标已被扫过,请重新输入...\n");
			Sleep(1000);
			continue;
		}
		if (mine[x][y] == ZERO)//输入坐标无雷
		{
			//Boom(mine, board, x, y);//递归展开,这样展开就展开了全部
			Boom2(mine, board, x, y);//炸开输入坐标附近的坐标
			//char num = GetNum(mine, x, y);
			//board[x][y] = num;
			Sleep(1000);
		}
		else//输入坐标有雷
		{
			printf("\n游戏结束,(%d,%d)坐标有雷\n",x,y);
			break;
		}
		for (i = 1; i < ROW - 1; i++)//计算board上面,‘*’的数为多少
		{
			int j = 0;
			for (j = 1; j < ROW - 1; j++)
			{
				if (board[i][j] == '*')
				{
					number++;
				}
			}
		}
		if (number == NUM)//若‘*’数和NUM相等,结束循环
		{
			break;
		}
	}
	if (number == NUM)//结果判定
	{
		Sleep(2000);
		system("cls");
		printf("\n恭喜你,完美通关!\n");
	}
	else
	{
		Sleep(2000);
		system("cls");
		printf("\n很遗憾,游戏失败,再接再厉!\n");
	}
	Show(mine, ROW, COL);//再显示一下mine棋盘
	Sleep(2000);
}

运行结果:
C语言实现扫雷游戏
需要程序的小伙伴可以来这里直接下载完整代码:扫雷游戏
 
 
 
未自动实现难度升级。