C语言经典小游戏之扫雷(超详解释+源码)
“少年气,是历尽千帆举重若轻的沉淀,也是乐观淡然笑对生活的豁达!” 今天我们学习一下扫雷游戏怎么用C语言来实现!
扫雷小游戏
- 1.游戏介绍
- 2.游戏准备
- 3.游戏实现
- 3.1生成菜单
- 3.2游戏的具体实现
- 3.2.1初始化棋盘
- 3.2打印棋盘
- 3.3布置雷
- 3.4排查雷
- 4.扫雷游戏的详细代码
1.游戏介绍
一个扫雷盘面由许多方格(cell)组成,方格中随机分布着一定数量的雷(mine),一个格子中至多只有1雷。胜利条件是打开所有安全格(非雷格,safe cell),失败条件是打开了一个雷格(踩雷)。下面图片中是一个9*9的示例:

2.游戏准备
和前面的三子棋一样,这里,我们也需要三个源文件来共同实现这个程序。

(1)头文件
game.h,头文件里是用来存放函数的声明,#define常量的定义,库函数的引用的。
(2)源文件test.c,这个文件里面放的是游戏的测试逻辑。
(3)源文件game.c,这个文件里面放的是游戏的实现逻辑(函数实现)。
3.游戏实现
3.1生成菜单
这里呢,我们和三子棋一样,还是通过switch语句给用户选择,当用户输入不同的数字,我们的程序就会给出不同的功能。
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
#include <stdio.h>
void menu()
{printf("******************************\n");printf("********* 1.play *********\n");printf("********* 0.exit *********\n");printf("******************************\n");
}
void game()
{}
int main()
{int input = 0;do{menu();printf("请选择:>");scanf("%d", &input);switch(input){case 1:game();break;case 0:printf("退出游戏!\n");break;default:printf("选择错误,重新选择!\n");break;}} while (input);return 0;
}
大致的框架就出来了,现在我们就需要看扫雷游戏的具体实现了。

3.2游戏的具体实现
这里我们简化游戏,设置一个
9*9的棋盘,安置10个雷。
排查过程如下:
1.如果这个位置是雷,那么游戏结束。
2.如果把不是雷的位置都找出来了,那么游戏结束。
3.如果这个位置不是雷,就计算这个位置的周围的8个格子有几个雷,并显示出雷的个数。
3.2.1初始化棋盘
我们这里的棋盘是9*9的,可以和三子棋一样,先将每个棋盘都初始化为0,如下图所示,然后有雷的地方填上1,如下图所示:

但是,我们从游戏规则中知道,当我们点到一个不是雷的格子的时候,要返回它周围八个格子中雷的个数。如下图中,如果我们点到了绿色1的那个格子,那么该位置将返回1这个值,此时,这里的1就会和表示雷的1就混起来了。

同时,当我们点到一个处于四边的格子的时候,还会出现越界的问题:

这个时候,我们就可以考虑在排查雷的时候,将棋盘扩展成11*11的棋盘。

同时,我们可以将排查雷的9*9的格子里都初始化为*,避免出现两个1意义不同混淆的情况。这样的话,我们就得到两个11*11的棋盘。

//game.h
#pragma once
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//初始化棋盘函数的声明
void Init_Board(char board[ROWS][COLS], int rows, int cols, char set);//game.h*
//初始化棋盘的定义
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void Init_Board(char board[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++){board[i][j] = set;}}
}//test.c
void game()
{char assign[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };Init_Board(assign,ROWS,COLS,'0');Init_Board(show, ROWS, COLS, '*');
}
初始化完成之后,我们想要验证一下对不对呢?这个时候,我们就需要将棋盘打印出来。
3.2打印棋盘
虽然我们这里初始化的是11*11的棋盘,但是用户需要的是中间区域的9*9,因此,我们只需要打印中间的9*9就可以了。
//game.h
//打印棋盘函数的声明
void Display_Board(char board[ROWS][COLS], int row, int col);//game.c
//打印棋盘函数的定义
//我们只需要打印出中间的9*9的格子
void Display_Board(char board[ROWS][COLS], int row, int col)
{int i = 0;for (i = 1; i <= row; i++){int j = 0;for (j = 1; j <= col; j++){printf("%c ", board[i][j]);}printf("\n");}
}//test.c
void game()
{Display_Board(assign, ROW, COL);
}

这里我们需要把行号和列号也打印出来,能够看的更清晰。代码进行这样的修改就好啦!

再优化一下,就如下图所示:

3.3布置雷
我们希望的是在这个9*9的棋盘里随机生成10个雷,这里我们就想到了能够产生随机数的函数rand()和srand(),使用这两个函数,需要添加头文件#include <time.h>和#include <stdlib.h>,同时,在主函数内还需要添加语句srand((unsigned int)time(NULL));来产生随机数的种子。
//game.h
#define Easy_Thunder 10
#include <stdlib.h>
#include <time.h>
//布置雷函数的声明
void Set_thunder(char board[ROWS][COLS], int row, int col);//game.c
//布置雷函数的定义
void Set_thunder(char board[ROWS][COLS], int row, int col)
{int count = Easy_Thunder;while (count){int x = rand() % row + 1;//生成横坐标int y = rand() % col + 1;//生成纵坐标if (board[x][y] == '0')//防止在同一个地方重复布雷{board[x][y] = '1';count--;}}
}//test.c
void game()
{char assign[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };Init_Board(assign,ROWS,COLS,'0');Init_Board(show, ROWS, COLS, '*');Display_Board(assign, ROW, COL);Set_thunder(assign, ROW, COL);
}
int main()
{srand((unsigned int)time(NULL));return 0;
}
那么,代码写好了,我们来验证一下,这样是不是能够布置出十个雷呢?

3.4排查雷
我们开始随机点一个格子,当这个格子不是雷的时候,可以计算它周围八个格子字符的ASCII码值,减去8个'0'的ASCII码值,就可以知道,这个格子周围有多少个雷了,然后我们加上'0'的ASCII码值就能在该处的格子上返回相应的字符。当我们把所有不是雷的格子找出来的时候,给用户提示排雷成功。当我们踩到雷的时候,也给出相应的提示给用户,游戏结束。这里和三子棋一样,我们可以添加清屏的操作system("cls");,让我们的游戏面板不是那么的冗长。

//game.h
//排查雷函数的声明
void Find_thunder(char assign[ROWS][COLS], char show[ROWS][COLS], int row, int col);//game.c
int Getassign(char assign[ROWS][COLS], int row, int col)//查找不是雷的格子周围有几个雷
{return (assign[row - 1][col - 1]//字符'0'的ASCII值为48,字符'1'的ASCII值为49+ assign[row - 1][col]+ assign[row - 1][col + 1]+ assign[row][col - 1]+ assign[row][col + 1]+ assign[row + 1][col - 1]+ assign[row + 1][col]+ assign[row + 1][col + 1] - 8 * '0');
}
//排查雷函数的定义
void Find_thunder(char assign[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{int x = 0;int y = 0;int win = 0;//计算没有踩到雷的次数while (win<col*row-Easy_Thunder){printf("请输入坐标:>");scanf("%d%d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (assign[x][y] == '1'){printf("很遗憾,你被炸死了!\n");Display_Board(assign, ROW, COL);break;}else{//如果这个位置不是雷就统计周围八个格子雷的个数int c = Getassign(assign, x, y);show[x][y] = c + '0';Display_Board(show, ROW, COL);system("cls");Display_Board(show, ROW, COL);win++;}}else{printf("坐标非法,请重新输入!\n");}}if (win == row * col - Easy_Thunder){printf("恭喜你排雷成功!\n");Display_Board(assign, ROW, COL);}
}//test.c
void game()
{Find_thunder(assign, show, ROW, COL);//排雷函数的引用
}
这里,我们随机输入,不用思考,试一下踩到雷的结果:

那么,如果我们仔细思考,看看当我们把所有不是雷的格子找出来的时候,能不能成功:

4.扫雷游戏的详细代码
//game.h
#pragma once
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define Easy_Thunder 10
#include <stdlib.h>
#include <time.h>
//初始化棋盘函数的声明
void Init_Board(char board[ROWS][COLS], int rows, int cols, char set);
//打印棋盘函数的声明
void Display_Board(char board[ROWS][COLS], int row, int col);
//布置雷函数的声明
void Set_thunder(char board[ROWS][COLS], int row, int col);
//排查雷函数的声明
void Find_thunder(char assign[ROWS][COLS], char show[ROWS][COLS], int row, int col);//game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//初始化棋盘的定义
void Init_Board(char board[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++){board[i][j] = set;}}
}
//打印棋盘函数的定义
//我们只需要打印出中间的9*9的格子
void Display_Board(char board[ROWS][COLS], int row, int col)
{int i = 0;int j = 0;printf("--------扫雷--------\n");for (i = 0; i <= col; i++){printf("%d ", i);}printf("\n");for (i = 1; i <= row; i++){printf("%d ", i);for (j = 1; j <= col; j++){printf("%c ", board[i][j]);}printf("\n");}
}
//布置雷函数的定义
void Set_thunder(char board[ROWS][COLS], int row, int col)
{int count = Easy_Thunder;//布置10个雷while (count){int x = rand() % row + 1;//生成横坐标int y = rand() % col + 1;//生成纵坐标if (board[x][y] == '0')//防止在同一个地方重复布雷{board[x][y] = '1';count--;}}
}
int Getassign(char assign[ROWS][COLS], int row, int col)//查找不是雷的格子周围有几个雷
{return (assign[row - 1][col - 1]//字符'0'的ASCII值为48,字符'1'的ASCII值为49+ assign[row - 1][col]+ assign[row - 1][col + 1]+ assign[row][col - 1]+ assign[row][col + 1]+ assign[row + 1][col - 1]+ assign[row + 1][col]+ assign[row + 1][col + 1] - 8 * '0');
}
//排查雷函数的定义
void Find_thunder(char assign[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{int x = 0;int y = 0;int win = 0;//计算没有踩到雷的次数while (win<col*row-Easy_Thunder){printf("请输入坐标:>");scanf("%d%d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (assign[x][y] == '1'){printf("很遗憾,你被炸死了!\n");Display_Board(assign, ROW, COL);break;}else{//如果这个位置不是雷就统计周围八个格子雷的个数int c = Getassign(assign, x, y);show[x][y] = c + '0';Display_Board(show, ROW, COL);system("cls");//清屏操作Display_Board(show, ROW, COL);win++;}}else{printf("坐标非法,请重新输入!\n");}}if (win == row * col - Easy_Thunder){printf("恭喜你排雷成功!\n");Display_Board(assign, ROW, COL);}
}//test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
#include <stdio.h>
void menu()
{printf("******************************\n");printf("********* 1.play *********\n");printf("********* 0.exit *********\n");printf("******************************\n");
}
void game()
{char assign[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };Init_Board(assign,ROWS,COLS,'0');Init_Board(show, ROWS, COLS, '*');Display_Board(assign, ROW, COL);Set_thunder(assign, ROW, COL);Find_thunder(assign, show, ROW, COL);
}
int main()
{srand((unsigned int)time(NULL));int input = 0;do{menu();printf("请选择:>");scanf("%d", &input);switch(input){case 1:game();break;case 0:printf("退出游戏!\n");break;default:printf("选择错误,重新选择!\n");break;}} while (input);return 0;
}
以上就是关于扫雷游戏的全部代码啦!当然这个程序还是存在可优化的空间(比如我们的游戏只能一个一个点,但是不能像网页版的那样能展示一片,这还有待思考),欢迎大家在评论区交流,优化代码。
相关文章:
C语言经典小游戏之扫雷(超详解释+源码)
“少年气,是历尽千帆举重若轻的沉淀,也是乐观淡然笑对生活的豁达!” 今天我们学习一下扫雷游戏怎么用C语言来实现! 扫雷小游戏 1.游戏介绍2.游戏准备3.游戏实现3.1生成菜单3.2游戏的具体实现3.2.1初始化棋盘3.2打印棋盘3.3布置雷…...
算法leetcode|67. 二进制求和(rust重拳出击)
文章目录 67. 二进制求和:样例 1:样例 2:提示: 分析:题解:rust:go:c:python:java: 67. 二进制求和: 给你两个二进制字符串 a 和 b &a…...
【ASP.NET MVC】第一个登录页面(8)
一、准备工作 先从网上(站长之家、模板之家,甚至TB)下载一个HTML模板,要求一整套的CSS和必要的JS,比如下图: 登录页面的效果是: 首页: 利用这些模板可以减少前台网页的设计——拿来…...
使用Openoffice或LibreOffice实现World、Excel、PPTX在线预览
使用Openoffice或LibreOffice实现World、Excel、PPTX在线预览 预览方案使用第三方服务使用前端库转换格式 jodconverterjodconverter概述主要特性OpenOfficeLibreOffice jodconverter的基本使用添加依赖配置创建DocumentConverter实例上传与转换预览启动上传与预览World 与Spri…...
20天学会rust(三)没有object的rust怎么面向对象?
面向对象我们都很熟悉,可以说它是一种软件开发最重要的编程范式之一,它将程序中的数据和操作数据的方法组织成对象。面向对象有几个重要特性: 封装、继承和多态,基于这些特性带来了在可重用性、可维护性、扩展性、可靠性的优点。 …...
整数规划——第三章 全单模矩阵
整数规划——第三章 全单模矩阵 若线性规划问题的约束矩阵为全单模矩阵,则该问题可行域的顶点都是整数点,从而线性规划与整数规划的最优解相同。 3.1 全单模性与最优性 考虑线性整数规划问题: (IP) min c T x , s . t . A x ≤ b , x …...
数据结构和算法
数据结构和算法目录表 CCJava线性结构 1. 数组、单链表和双链表 2. Linux内核中双向链表的经典实现 数组、单链表和双链表 数组、单链表和双链表 栈 栈 栈 队列 队列 队列树形结构 二叉查找树 二叉查找树 二叉查找树 AVL树 AVL树 AVL树 伸展树 伸展树 伸展树 1. 红黑树(一)之…...
[Vulnhub] matrix-breakout-2-morpheus
目录 <1> 信息收集 <2> getshell <3> Privilege Escalation(提权) <1> 信息收集 nmap -sP 192.168.236.0/24 扫描一下靶机ip 靶机ip: 192.168.236.154 nmap -A -p 1-65535 192.168.236.154 扫描一下靶机开放哪些服务 开放…...
JDK, JRE和JVM之间的区别和联系
JDK, JRE和JVM是与Java编程语言相关的三个重要的概念,它们分别代表Java Development Kit(Java开发工具包)、Java Runtime Environment(Java运行时环境)和Java虚拟机(Java Virtual Machine)。它们…...
mac电脑访问windows共享文件夹连接不上(设置445端口)
前提:首先需要保证mac和windows都在同一局域网内,如果不在肯定是连不上的,就不用往下看了。 事情是这样的,公司入职发了mac电脑,但是我是window重度用户,在折腾mac的过程中,有许多文件需要从wi…...
metersphere性能压测执行过程
(1) 首先在controller层,通过RunTestPlanRequest接收请求参数 PostMapping("/run")public String run(RequestBody RunTestPlanRequest request) (2) 在PerformanceTestService中的run中进行具体的逻辑处理, 首先根据请求中ID来获取库中存储…...
揭秘Word高级技巧:事半功倍的文字处理策略
Microsoft Word是一款广泛使用的文字处理软件,几乎每个人都有使用过它的经历。但是,你是否知道Word中隐藏着许多高级技巧和功能,可以帮助你事半功倍地处理文字?在本文中,我们将揭秘一些Word的高级技巧,让你…...
06-1_Qt 5.9 C++开发指南_对话框与多窗体设计_标准对话框
在一个完整的应用程序设计中,不可避免地会涉及多个窗体、对话框的设计和调用,如何设计和调用这些对话框和窗体是搞清楚一个庞大的应用程序设计的基础。本章将介绍对话框和多窗体设计、调用方式、数据传递等问题,主要包括以下几点。 Qt 提供的…...
模拟实现消息队列项目(系列7) -- 实现BrokerServer
目录 前言 1. 创建BrokerServer类 1.1 启动服务器 1.2 停止服务器 1.3 处理一个客户端的连接 1.3.1 解析请求得到Request对象 1.3.2 根据请求计算响应 1.3.3 将响应写回给客户端 1.3.4 遍历Session的哈希表,把断开的Socket对象的键值对进行删除 2. 处理订阅消息请求详解(补充) …...
vscode插件不能搜索安装
1 现象 vscode搜索自己的插件,报错: Error while fetching extensions. HXR failed2 原因 之前用vscode开发golang语言,设置了proxy代理,所以导致错误,删除即可 重启vscode 3 结果...
路由器工作原理(第二十九课)
路由器工作原理(第二十九课) 一图胜过千言 1) 路由:数据从一个网络到另外一个网络之间转发数据包的过程称为路由 2) 路由器:连接不同网络,实现不同网段之间的通信 3)路由表:路由器选择数据的传输路径的依据 原始的路由表 Destination/Mask Proto Pre Cost …...
linux log 日志
/* author: hjjdebug * date: 2023年 08月 08日 星期二 13:18:08 CST * descriptor: linux log 日志 * destinator: 搞清linux 下log 日志 * 下面代码编译通过即可运行 */ #include <stdio.h> #include <syslog.h> int main(void) { // 打开系统日志, 可…...
uniapp获取当前页面高度
设置动态高度:style"{height: pageHeightpx}" <view class"uni-content" :style"{height: pageHeightpx}" >... </view>获取当前页面高度: onLoad() {// 获取当前窗口高度this.pageHeight uni.getSystemInfoSync().wi…...
Java课题笔记~ Spring 集成 MyBatis
Spring 集成 MyBatis 将 MyBatis 与 Spring 进行整合,主要解决的问题就是将 SqlSessionFactory 对象交由 Spring 来管理。所以该整合,只需要将 SqlSessionFactory 的对象生成器SqlSessionFactoryBean 注册在 Spring 容器中,再将其注入给 Dao…...
分布式系统理论基础
文章目录 介绍目标 正文CAPConsistencyAvailabilityPartition tolerance BASEBasically AvailableSoft StateEventually Consistent ACIDatomicityconsistencyisolationdurability 参考文档 介绍 分布式系统面临的场景往往是众口难调,“这也要,那也要”…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...
Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...
通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器
拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件: 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...
DiscuzX3.5发帖json api
参考文章:PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下,适配我自己的需求 有一个站点存在多个采集站,我想通过主站拿标题,采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...
