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

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

相关推荐
恋猫de小郭12 分钟前
再聊 Flutter Riverpod ,注解模式下的 Riverpod 有什么特别之处,还有发展方向
android·前端·flutter
马剑威(威哥爱编程)1 小时前
C语言操作MySQL从入门到精通
c语言·mysql·adb
*星星之火*4 小时前
【GPT入门】第5课 思维链的提出与案例
android·gpt
EasyCVR5 小时前
EasyRTC嵌入式视频通话SDK的跨平台适配,构建web浏览器、Linux、ARM、安卓等终端的低延迟音视频通信
android·arm开发·网络协议·tcp/ip·音视频·webrtc
韩家老大5 小时前
RK Android14 在计算器内输入特定字符跳转到其他应用
android
Kurbaneli7 小时前
深入理解 C 语言函数的定义
linux·c语言·ubuntu
Archer1947 小时前
C语言——链表
c语言·开发语言·链表
张拭心8 小时前
2024 总结,我的停滞与觉醒
android·前端
面会菜.8 小时前
C语言(队列)
c语言·开发语言