【C语言】------ 实现扫雷游戏


个人主页

好久不见呀我的粉丝朋友们,由于近段时间太忙碌,导致更新博文的更新速度大幅降低了,在这里先对大家说声不好意思!恰好今天是2025年3月8日,祝各位女性朋友们女神节快乐!

我今这次要跟大家分享的是如何 使用C语言实现一个游戏-----扫雷游戏! 希望看完这篇博文能给你带来帮助,非常感谢大家对博主的支持!

文章目录

🎡一、前言

扫雷游戏,相信大家对此并不陌生。这次我们使用C语言实现扫雷游戏的目的就是为了巩固我们之前所学习的知识,将我们的所学的知识串联起来,加深我们对知识的理解。

🎄二、功能说明

  1. 使用控制台实现经典的扫雷游戏
  2. 游戏可以通过菜单实现是否继续或者退出游戏
  3. 棋盘大小为9 * 9的规格
  4. 随机布置10个雷
  5. 排查雷
    (1)如果该位置不是雷,就显示周围有几个雷
    (2)若该位置是雷,则被炸死,游戏结束
    (3)如果10个雷都被排查出来,说明排雷成功,游戏结束

🏠三、分析和设计

  1. 数据结构分析
    在扫雷的过程中,布置雷的信息和排查出雷的信息都需要被存储起来,因此我们会想到创建一个数组为9 * 9大小用来存储相关信息。
  2. 如果这个位置是雷,我们就存放'1',否则存放'0'
  3. 在排雷的过程中,如图一,当我们排查(8,6)这个坐标时,我们发现会产生越界访问,因此在设计数组时,给数组扩大一圈,如图二,布置雷的时候还是布置在中间9*9的坐标上,这样设计就可以避免数组产生越界访问了。

    4.我们在棋盘上布置是雷为'1',不是雷为'0'的信息,假设我们排查出某一位置不是雷并统计周围有多少雷的个数时,我们需要将周围雷的个数给打印出来,作为我们排查雷的依据,那么这个周围雷的个数信息该存放在哪呢?如果存放在布置雷的数组中,就会和我们布置雷的信息产生混淆。因此我们想到专门给一个棋盘mine为布置好雷的信息,给另外一个棋盘show为排查出雷的信息,这样就不会互相干扰了。为了保持神秘,我们将show数组全部初始化为 ' * ' ,mine数组全部初始化为 ' 0 ',布置好雷的位置为 ' 1 '。 如下图所示:

⭐四、多文件处理

我们为了代码逻辑清晰,我们一共分为三个文件来实现:

  1. game.c(完成游戏主要功能代码实现)
  2. game.h(完成游戏中需要的头文件以及函数声明)
  3. test.c (测试游戏运行的逻辑)

🚀五、游戏各功能的实现

1. 创建菜单

我们设计当用户输入1的时候则进入游戏,输入0的时候则退出。当用户输入其他数字时我们会提示输入数字非法等相关信息,并重新输入,因此需要使用循环来实现相关功能。

c 复制代码
void Menu()
{
	printf("***********************\n");
	printf("*******  1.PLAY  ******\n");
	printf("*******  0.EXIT  ******\n");
	printf("***********************\n");
}

int main()
{
	int input = 0;
	do
	{
		Menu();
		printf("请输入:>\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("扫雷游戏开始\n");
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入数字非法,请重新输入\n");
		}
	} while (input);
	return 0;
}

2. 初始化棋盘

c 复制代码
//初始化棋盘
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			arr[i][j] = set;
		}
	}
}

3. 打印棋盘

c 复制代码
//打印棋盘
void PrintBoard(char arr[ROWS][COLS], int row, int col)
{
	int i = 0;
	printf("-----扫雷游戏--------\n");
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (int i = 1; i <= row; i++)
	{
		printf("%d ", i);
		int j = 0;
		for (j = 1; j <= col; j++)
		{
			printf("%c ", arr[row][col]);
		}
		printf("\n");
	}
}

效果展示:

4. 布置雷

一、随机产生雷

要想随机产生雷,我们就需要随机数的产生,那要怎么样实现随机数的产生呢?C语言提供了一个函数叫rand来生成随机数,它生成随机数的大小范围为:0-RAND_MAX,而这个最大值通常为32767。使用这一函数时需要包含头文件 <stdlib.h> 但需要注意的是,rand函数生成的是伪随机数,而不是真正的随机数,每一次程序运行时同一个rand函数生成的随机数是相同的,是因为rand的函数是对一个"种子"的基准值进行运算而生成的随机数,而rand的种子默认为1。因此要生成真正的随机数,就要让种子不断发生改变。对此,C语言又提供一个函数叫srand函数。程序每次使用rand函数时先调用srand函数,通过srand种子的改变来改变rand种子所生成的随机数。那么该怎么让srand函数的种子是随机的呢?经过我们的考虑,我们发现时间是一直在改变的,如果我们将时间作为种子,那么rand就可以生成每次不一样的随机数了。C语言也提供了time函数,也需要包含头文件 <time.h> ,该函数的返回类型为time_t。

二、布置雷的范围

由于我们想布置雷的范围为横纵坐标轴1 - 9。因此我们需要确定rand的范围

c 复制代码
rand() % 9 //所得到的为 0-8的余数
rand() % 9 + 1 // 所得到的为 1-9的余数

了解上述知识后,我们就可以进行代码实现了

c 复制代码
//布置雷
void SetMine(char arr[ROWS][COLS], int row, int col)
{
	int count = EasyCount;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (arr[x][y] == '0')
		{
			arr[x][y] = '1';
			count--;
		}
	}
}

5. 排查雷

c 复制代码
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win < row * col - EasyCount)
	{
		printf("请输入你要排查的坐标:>\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (show[x][y] == '*')
			{
				if (mine[x][y] == '1')
				{
					printf("很遗憾,你被炸死了!\n");
					PrintBoard(mine, ROW, COL);
					break;
				}
				else
				{
					//统计周围雷的个数
					int count = GetCountMine(mine, x, y);
					show[x][y] = count + '0';
					PrintBoard(show, ROW, COL);
					win++;
				}
			}
			else
			{
				printf("输入坐标已经被排查,请重新输入!\n");
			}
			
		}
		else
		{
			printf("输入坐标非法,请重新输入\n");
		}
	}
	if (win == row * col - EasyCount)
	{
		printf("恭喜你,排雷成功!游戏结束\n");
		PrintBoard(show, ROW, COL);
	}
}

6. 计算九宫格内雷的个数

字符'0'的ASCII值为49,字符'1'的ASCII值为48,我们只需要将字符'1'减去字符'0',得到的就是数字1,按照这一逻辑我们就可以得到周围雷的个数。

c 复制代码
int GetCountMine(char mine[ROW][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';
}

🎉六、整体代码

1. game.h

c 复制代码
#pragma once

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

#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
//雷的个数
#define EasyCount 10

//初始化棋盘
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set);

//打印棋盘
void PrintBoard(char arr[ROWS][COLS], int row, int col);

//布置雷
void SetMine(char arr[ROWS][COLS], int row, int col);

//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

2. game.c

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"

//初始化棋盘
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			arr[i][j] = set;
		}
	}
}

//打印棋盘
void PrintBoard(char arr[ROWS][COLS], int row, int col)
{
	int i = 0;
	printf("-----扫雷游戏--------\n");
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (int i = 1; i <= row; i++)
	{
		printf("%d ", i);
		int j = 0;
		for (j = 1; j <= col; j++)
		{
			printf("%c ", arr[i][j]);
		}
		printf("\n");
	}
}

//布置雷
void SetMine(char arr[ROWS][COLS], int row, int col)
{
	int count = EasyCount;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (arr[x][y] == '0')
		{
			arr[x][y] = '1';
			count--;
		}
	}
}

//统计周围雷的个数
int GetCountMine(char mine[ROW][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 FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win < row * col - EasyCount)
	{
		printf("请输入你要排查的坐标:>\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (show[x][y] == '*')
			{
				if (mine[x][y] == '1')
				{
					printf("很遗憾,你被炸死了!\n");
					PrintBoard(mine, ROW, COL);
					break;
				}
				else
				{
					//统计周围雷的个数
					int count = GetCountMine(mine, x, y);
					show[x][y] = count + '0';
					PrintBoard(show, ROW, COL);
					win++;
				}
			}
			else
			{
				printf("输入坐标已经被排查,请重新输入!\n");
			}
			
		}
		else
		{
			printf("输入坐标非法,请重新输入\n");
		}
	}
	if (win == row * col - EasyCount)
	{
		printf("恭喜你,排雷成功!游戏结束\n");
		PrintBoard(show, ROW, COL);
	}
}

3. test.c

c 复制代码
#include"game.h"

void Menu()
{
	printf("***********************\n");
	printf("*******  1.PLAY  ******\n");
	printf("*******  0.EXIT  ******\n");
	printf("***********************\n");
}

void game()
{
	//mine数组
	char mine[ROWS][COLS] = { 0 };
	//show数组
	char show[ROWS][COLS] = { 0 };

	//初始化棋盘
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');

	//打印棋盘
	PrintBoard(mine, ROW, COL);
	//PrintBoard(show, ROW, COL);
	
	//布置雷
	SetMine(mine, ROW, COL);
	PrintBoard(mine, ROW, COL);

	//排查雷
	FindMine(mine, show, ROW, COL);
}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		Menu();
		printf("请输入:>\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("扫雷游戏开始\n");
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入数字非法,请重新输入\n");
		}
	} while (input);
	return 0;
}

感谢读者们耐心的观看,希望看完这篇文章能给你带来有所帮助,今天的分享到这里就结束了!期待我们下次的相遇(●'◡'●)

相关推荐
teacher伟大光荣且正确1 小时前
Qt Creator 配置 Android 编译环境
android·开发语言·qt
飞猿_SIR4 小时前
Android Exoplayer 实现多个音视频文件混合播放以及音轨切换
android·音视频
HumoChen994 小时前
GZip+Base64压缩字符串在ios上解压报错问题解决(安卓、PC模拟器正常)
android·小程序·uniapp·base64·gzip
吃个早饭5 小时前
2025年第十六届蓝桥杯大赛软件赛C/C++大学B组题解
c语言·c++·蓝桥杯
qwertyuiop_i6 小时前
pe文件二进制解析(用c/c++解析一个二进制pe文件)
c语言·c++·pe文件
我叫珂蛋儿吖8 小时前
[redis进阶六]详解redis作为缓存&&分布式锁
运维·c语言·数据库·c++·redis·分布式·缓存
周Echo周8 小时前
20、map和set、unordered_map、un_ordered_set的复现
c语言·开发语言·数据结构·c++·算法·leetcode·list
沙振宇8 小时前
【HarmonyOS】ArkTS开发应用的横竖屏切换
android·华为·harmonyos
安装虚拟机的老师傅8 小时前
【2025最新】Windows系统装VSCode搭建C/C++开发环境(附带所有安装包)
c语言·windows·vscode·其他
真的想上岸啊9 小时前
c语言第一个小游戏:贪吃蛇小游戏06
c语言·算法·链表