C语言实现扫雷游戏

发布时间:2023年12月21日

一、整体模块设计

功能一:显示的棋盘
功能二:埋雷的棋盘
功能三:初始化棋盘
功能四:埋雷
功能五:显示棋盘
功能六:排雷

二、棋盘设计

初始化棋盘

首先我们可以知道的是需要设计一个玩家看到的棋盘页面,棋盘上没有任何的显示。

这是一个9*9的网格,那么我们可以用一个二维数组来存放它。

char show [ROWS][COLS];

这里棋盘上的*就相当于上面棋盘上的方格。

那么我们只需要先在数组里每个元素都存放上‘*’然后再打印出来就可以完成这个设计。

我们可以把这个存放*的初始化函数记为

void Init (char arr[ROWS][COLS], int x,int y, char set);

void Init(char arr[ROWS][COLS], int x, int y, char set)
{
	int i = 0, j = 0;
	for (i = 0; i < x; i++)
	{
		for (j = 0; j < y; j++)
		{
			arr[i][j] = set;
		}
	}

}

这里的ROWS和COLS解释一下。我们打印的是一个9*9的棋盘,玩家输入坐标进行排雷,那么可以宏定义一下ROW、COL=9;

其次,扫雷游戏每扫一个空格,都会显示周围八个格子的雷数。

那么对于1-9这个格子来说,他的右边和上边是没有格子的,那么为了方便设计我们可以添加上一行一列的空格子。

那么也就是说实际上我们设计一个9*9的棋盘,要初始化一个11*11的二维数组,那么宏定义一个ROWS和COLS=ROW+2;

现在我们初始化显示给玩家的棋盘

Init(show,ROWS,COLS,'*');

这样子显示给玩家的棋盘内存放的都是*,打印出来也就是*;

接着我们还需要初始化一个雷盘,里面存放雷的位置,我们可以用数字1表示雷,数字0表示没有雷。

Init(board, ROWS, COLS, '0');

设置雷盘

现在雷盘已经初始化完成,我们需要随即插入雷就完成了埋雷。

void Set(char arr[ROWS][COLS], int x, int y,int count)

这里count代表埋雷的数目,简单模式我们可以宏定义一下count=10;

void Set(char arr[ROWS][COLS], int x, int y,int count)
{
	int i = 0, j = 0;
	for (; count > 0;)
	{
		i = rand() % 9 + 1;
		j = rand() % 9 + 1;
		if (arr[i][j] == '0')
		{
			arr[i][j] = '1';
			count--;
		}
	}

}

通过随机数生成横纵坐标,然后判断这个坐标有没有被埋过雷,如果没有的话就在这个坐标买入雷。

随机数模9生成的数是0-8,而我们的位置坐标是1-10,所以在余数+1就能得到需要的坐标范围。

打印棋盘

我们这里打印的是显示给玩家的棋盘。

Display(show, ROW, COL);

一个9*9的棋盘然后在第一行前打印出来0-9,在第一列打印出来0-9,也就是需要打印一个10*10的网格。

void Display (char arr[ROWS][COLS], int x, int y)
{
	int i = 0, j = 0;
	printf("--------扫雷--------\n");
	for (i = 0; i < 1; i++)
	{
		for (j = 0; j <= y; j++)
		{
			printf("%d ",j);
		}
		printf("\n");
	}
	for (i = 1; i <= x; i++)
	{
		printf("%d ",i);
		for (j = 1; j <= y; j++)
		{
			printf("%c ",arr[i][j]);
		}
		printf("\n");
	}
	printf("--------扫雷--------\n");
}

三、排雷

排雷是整个游戏里面最主要的一部分,首先玩家输入想要排雷的坐标,然后对这个位置进行判断,

首先判断坐标输入是否合法,即1<row<9,1<col<9,合法再进行下一步。

如果arr[i][j]==‘1’,那么就证明这个位置是有雷的,那么这时候游戏就应该结束了,并且把埋雷的棋盘打印出来,告诉玩家哪里有雷。

如果arr[i][j]==‘0’,那么就证明这个位置没有雷,那么就应该把附近八个格子里面的雷数显示在这个格子里面,并且我们通过玩游戏可以知道,如果这个格子显示0的话,那么附近的格子也应该被扫出来。

就像如果我扫2-8这个位置附近都没有雷,那么它旁边就应该自动展开,这样子不仅方便玩家进行游戏,还能减少反复输入坐标进行排雷。

雷数判断

那么这里我们应该写一个函数,来计算周围八个格子里面到底有多少雷。

因为我们在雷盘里面存放的都是字符1和0,所以只需要把这些字符相加,再减去对应的字符0的个数,就能得到对应数字的值。

int countsum(char arr[ROWS][COLS], int x, int y)
{
	return arr[x - 1][y - 1] + arr[x - 1][y] + arr[x - 1][y + 1]
		+ arr[x][y - 1] + arr[x][y] + arr[x][y + 1]
		+ arr[x + 1][y - 1] + arr[x + 1][y] + arr[x + 1][y + 1]-9*'0';
}

中雷判断

然后我们这里扫雷是一个循环的过程,达到胜利或者失败条件再跳出这个循环,所以我们可以在一个死循环下面去跑这个扫雷的过程。

void Mine(char show[ROWS][COLS], char board[ROWS][COLS], int x, int y, int set)
{
	int row = 0, col = 0, count=x*y-set, sum=0, a=1;
	while (a)
	{
	
		printf("请输入排雷坐标\n");
		scanf("%d %d", &row, &col);
		if (row >= 1 && row <= x && col >= 1 && col <= y)
		{
			if (board[row][col] == '1')
			{
				printf("很遗憾,排雷失败!!!\n");
				Display(board, x, y);
				break;
			}
			else
			{
				sum = countsum(board, row, col);
				show[row][col] = sum+'0';
				int i = 0, j = 0;
				if (sum==0)
				{
					for (i = -1, j = -1; j < 2; j++)
					{
						show[row + i][col + j] = countsum(board, row + i, col + j)+'0';
						if (board[row + i][col + j] == '1')
							show[row + i][col + j] = '*';
					}
					for (i = 0, j = -1; j < 2; j++)
					{
						show[row + i][col + j] = countsum(board, row + i, col + j)+'0';
						if (board[row + i][col + j] == '1')
							show[row + i][col + j] = '*';
					}
					for (i = 1, j = -1; j < 2; j++)
					{
						show[row + i][col + j] = countsum(board, row + i, col + j)+'0';
						if (board[row + i][col + j] == '1')
							show[row + i][col + j] = '*';
					}
				}
				
				Display(show, ROW, COL);
				
			}
		}
		else
		{
			printf("输入错误,坐标非法");
		}
	}
	
}

赢家判断

现在我们需要一个胜利条件,去判断这局游戏是否赢了,否则即使我们排掉了全部的雷,循环还会继续运行。那么这个判断也很简单,我们可以想一下,如果排到最后,棋盘上只剩下10个‘*’,其余全部显示的是数字,那么我们只需要统计‘*’的个数,就可以这个是否赢下了这局游戏。

int Win(char show[ROWS][COLS])
{
	int i = 1, j = 1, z=0;
	for(i=1;i<=ROW;i++)
	{
		for (j=1; j <=COL; j++)
		{
			if (show[i][j] == '*')
			{
				z++;
			}
		}
	}
	if (z != easycount)
	{
		return z;
	}
	else
		return 0;

}

因为我们前面while的判断条件是a的值,所以我们在排雷一次以后就a = Win(show);

如果Win返回0的话,循环就会跳出,这时候就赢下了这局游戏。

总结

这个代码还是有些地方没有完善,比如扫雷展开那里,一次最多展开九个格子,还不能像我们平常玩的那种一下子展开一片,这里还需要继续改进一下。另外如果想升级难度,只需要改变一下棋盘大小和雷数就可以,代码的移植性还是比较高的。

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

# define easycount 10

# define ROW 9
# define COL 9

# define ROWS ROW+2
# define COLS COL+2

void Init(char arr[ROWS][COLS], int x, int y, char set)
{
	int i = 0, j = 0;
	for (i = 0; i < x; i++)
	{
		for (j = 0; j < y; j++)
		{
			arr[i][j] = set;
		}
	}

}

void Set(char arr[ROWS][COLS], int x, int y, int count)
{
	int i = 0, j = 0;
	for (; count > 0;)
	{
		i = rand() % 9 + 1;
		j = rand() % 9 + 1;
		if (arr[i][j] == '0')
		{
			arr[i][j] = '1';
			count--;
		}
	}

}

void Display(char arr[ROWS][COLS], int x, int y)
{
	int i = 0, j = 0;
	printf("--------扫雷--------\n");
	for (i = 0; i < 1; i++)
	{
		for (j = 0; j <= y; j++)
		{
			printf("%d ", j);
		}
		printf("\n");
	}
	for (i = 1; i <= x; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= y; j++)
		{
			printf("%c ", arr[i][j]);
		}
		printf("\n");
	}
	printf("--------扫雷--------\n");
}

int countsum(char arr[ROWS][COLS], int x, int y)
{
	return arr[x - 1][y - 1] + arr[x - 1][y] + arr[x - 1][y + 1]
		+ arr[x][y - 1] + arr[x][y] + arr[x][y + 1]
		+ arr[x + 1][y - 1] + arr[x + 1][y] + arr[x + 1][y + 1] - 9 * '0';
}

int Win(char show[ROWS][COLS])
{
	int i = 1, j = 1, z = 0;
	for (i = 1; i <= ROW; i++)
	{
		for (j = 1; j <= COL; j++)
		{
			if (show[i][j] == '*')
			{
				z++;
			}
		}
	}
	if (z != easycount)
	{
		return z;
	}
	else
		return 0;

}

void Mine(char show[ROWS][COLS], char board[ROWS][COLS], int x, int y, int set)
{
	int row = 0, col = 0, count = x * y - set, sum = 0, a = 1;
	while (a)
	{

		printf("请输入排雷坐标\n");
		scanf("%d %d", &row, &col);
		if (row >= 1 && row <= x && col >= 1 && col <= y)
		{
			if (board[row][col] == '1')
			{
				printf("很遗憾,排雷失败!!!\n");
				Display(board, x, y);
				break;
			}
			else
			{
				sum = countsum(board, row, col);
				show[row][col] = sum + '0';
				int i = 0, j = 0;
				if (sum == 0)
				{
					for (i = -1, j = -1; j < 2; j++)
					{
						show[row + i][col + j] = countsum(board, row + i, col + j) + '0';
						if (board[row + i][col + j] == '1')
							show[row + i][col + j] = '*';
					}
					for (i = 0, j = -1; j < 2; j++)
					{
						show[row + i][col + j] = countsum(board, row + i, col + j) + '0';
						if (board[row + i][col + j] == '1')
							show[row + i][col + j] = '*';
					}
					for (i = 1, j = -1; j < 2; j++)
					{
						show[row + i][col + j] = countsum(board, row + i, col + j) + '0';
						if (board[row + i][col + j] == '1')
							show[row + i][col + j] = '*';
					}
				}

				Display(show, ROW, COL);
				a = Win(show);
			}
		}
		else
		{
			printf("输入错误,坐标非法");
		}
	}
	if (a == 0)
		printf("恭喜你,成功完成游戏!\n");
}

void game()
{
	printf("开始游戏\n");
	//显示的棋盘
	char show [ROWS][COLS];
	//埋雷的棋盘
	char board [ROWS][COLS];
	//初始化棋盘
	Init(show,ROWS,COLS,'*');
	Init(board, ROWS, COLS, '0');//0表示没雷
	//埋雷
	Set(board,ROW, COL,easycount);
	//显示棋盘
	Display(show, ROW, COL);
	//Display(board, ROW, COL);
	//排雷
	Mine(show,board, ROW, COL, easycount);

}


void menu()
{
	printf("************\n");
	printf("***1.play***\n");
	printf("***0.exit***\n");
	printf("************\n");
}

int main()
{
	int input;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择\n");
		scanf("%d", &input);
		switch(input)
		{
			case 1:
				game();
				break;
			case 0:
				printf("退出游戏!\n");
				break;
			default:
				printf("输入错误,请重新输入\n");
				break;
		}
	} while (input);
	
	return 0;
 }

文章来源:https://blog.csdn.net/m0_63286151/article/details/132776732
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。