【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;
}

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

相关推荐
selt7912 分钟前
Redisson之RedissonLock源码完全解析
android·java·javascript
神圣的大喵23 分钟前
平台无关的嵌入式通用按键管理器
c语言·单片机·嵌入式硬件·嵌入式·按键库
Yao_YongChao37 分钟前
Android MVI处理副作用(Side Effect)
android·mvi·mvi副作用
非凡ghost2 小时前
JRiver Media Center(媒体管理软件)
android·学习·智能手机·媒体·软件需求
席卷全城2 小时前
Android 推箱子实现(引流文章)
android
齊家治國平天下2 小时前
Android 14 系统中 Tombstone 深度分析与解决指南
android·crash·系统服务·tombstone·android 14
喵了meme3 小时前
C语言实战2
c语言·开发语言·网络
Sui_Network4 小时前
备受期待的 POP 射击游戏 XOCIETY 正式在 Epic Games Store 开启体验
人工智能·游戏·rpc·区块链·量子计算·graphql
maycho1234 小时前
MATLAB环境下基于双向长短时记忆网络的时间序列预测探索
android
网易独家音乐人Mike Zhou4 小时前
【嵌入式模块芯片开发】LP87524电源PMIC芯片配置流程,给雷达供电的延时上电时序及API函数
c语言·stm32·单片机·51单片机·嵌入式·电源·毫米波雷达