【c语言】扫雷
前言:
扫雷是一款经典的单人益智游戏,它的目标是在一个方格矩阵中找出所有的地雷,而不触碰到任何一颗地雷。在计算机编程领域,扫雷也是一个非常受欢迎的项目,因为它涉及到许多重要的编程概念,如数组、循环、条件语句和函数等。
C语言是一种广泛使用的编程语言,它具有高效、灵活和可移植等特点,非常适合编写各种类型的应用程序。因此,使用C语言编写一个扫雷游戏是一个很好的学习编程的项目。
在这篇博客中,我们将介绍如何使用C语言编写一个简单的扫雷游戏。我们将从基本的编程概念开始讲解,逐步深入到更复杂的程序设计技术。我们还将提供完整的代码示例和详细的注释,以帮助读者更好地理解和掌握这个项目。
无论您是初学者还是有一定编程经验的开发者,相信通过阅读本篇博客,您都能够学到一些有用的知识和技巧。让我们一起来探索如何使用C语言编写一个令人兴奋的扫雷游戏吧!
前期准备:
先开一个test.c文件用来游戏的逻辑测试,在分别开一个game.c文件和game.h头文件用来实现游戏的逻辑
1. 主要步骤:
1.1 游戏规则:
输入1(0)开始(结束)游戏,输入一个坐标,如果该坐标不是雷则会显示该坐标周围有几个雷
1.2 打印菜单:
void menu()
{printf("----------------扫雷----------------\n");printf("| |\n");printf("| 1.play |\n");printf("| 0.exit |\n");printf("| |\n");printf("------------------------------------\n");
}
int main()
{int input = 0;srand((unsigned int )time(NULL));do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case 1:game();break;case 0:printf("游戏结束,退出游戏\n");break;default :printf("输入错误请重新输入\n");}} while (input);return 0;
}
1.3 打印棋盘:
写两个数组一个是用来打印给玩家看的棋盘,一个是用来放置炸弹的隐藏棋盘,等到游戏结束我们才会打印这个棋盘。然后我们给数组初始化,用*来初始化我们给玩家看的棋盘,用字符‘0’初始化隐藏棋盘。
char mine[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };//初始化棋盘InitBoard(show, ROWS, COLS, '*');InitBoard(mine, ROWS, COLS, '0');//打印棋盘DisPalyBoard(show, ROW, COL);//DisPalyBoard(mine, ROW, COL);
1.4 打印行列:
因为我们是用坐标来选择排雷的,所以我们需要在棋盘的周围打印出行列才可以让玩家更好的去选择。
首先在打印棋盘for循环上方加上一个打印0~9的for循环就可以打印出棋盘的行了,然后用打印列的for循环套在打印棋盘的for循环上就可以打印出棋盘的列了。
void DisPalyBoard(char arr[ROWS][COLS], int row, int col)
{printf("------扫雷游戏------\n");int i = 0;//打印行的for循环for (i = 0; i <= col; i++){printf("%d ", i);}printf("\n");//打印列的for循环for ( i = 1; i <= row; i++) {printf("%d ", i);//打印棋盘的for循环for (int j = 1; j <= col; j++){printf("%c ", arr[i][j]);}printf("\n");}
}
1.5 放置炸弹:
要想棋盘上随机分布十个炸弹(炸弹我们用字符‘1’定义),我们就需要生成随机数使数组的随机十个元素等于字符‘1’,而生成随机数就需要调用到前面我写猜数字游戏时讲过的rand函数、srand函数、time函数了。
void SetMine(char arr[ROWS][COLS], int row, int col)
{int count = EsayCount;while (count){int x = rand() % row + 1;int y = rand() % col + 1;if (arr[x][y] == '0')//防止生成相同随机数时,使多个炸弹放置在同一位置{arr[x][y] = '1';count--;}}
}
1.6 排查炸弹:
当我们输入一个坐标后如果时炸弹结束游戏,如果不是炸弹则需要显示炸弹的数量。
判断是否是炸弹只需写一个if语句判断该坐标中数组所对应的元素是否等于‘1’就行了。
显示周围有几个雷,我们就需要将所选坐标的周围的数加起来就可以了,这些加起来的数的和替换所选坐标的元素就可以了。
int GetMineCount(char mine[ROWS][COLS],int x,int y)
{return (mine[x - 1][y] + mine[x - 1][y - 1] + mine[x][y - 1] + mine[x + 1][y - 1]+ mine[x + 1][y + 1] + mine[x - 1][y + 1] + mine[x - 1][y + 1] + mine[x][y + 1] - 8 * '0');
}
也可以用for循环统计
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{int a = 0;for (int i = x - 1; i <= x + 1; i++){for (int j = y - 1; j <= y + 1; j++){a += mine[i][j];}}return a - '0' * 9;
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{int x = 0, y = 0;int win = 0;while (win < row*col - EsayCount){printf("请输入要排查的坐标:>");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (mine[x][y] == '1'){printf("很遗憾,你被炸死了\n");DisPalyBoard(mine, ROW, COL);break;}else{//该坐标不是雷,就得统计该坐标的周围有几个雷int count = GetMineCount(mine, x, y);show[x][y] = count + '0';DisPalyBoard(show, ROW, COL);win++;}}else{printf("坐标非法,请重新输入\n");}}if (win == row * col - EsayCount){printf("恭喜你,排雷成功\n");DisPalyBoard(mine, ROW, COL);}
}
1.7 周围没有雷就展开一片
首先需要判断所选坐标的周围是否有雷,即判断count是否等于0,如果所选坐标周围没有雷的话,就将此坐标的周围的坐标都调用显示雷的数量的函数。当然还需要判断一下坐标是否为‘*’,如果没有这个判断它就会重复的调用函数,从而进入了死循环。
void arr(char mine[ROWS][COLS], char show[ROWS][COLS], int x,int y)
{if (show[x][y] == '*'){int count = GetMineCount(mine, x, y);show[x][y] = count + '0';if (x >= 1 && x <= ROW && y >= 1 && y <= ROW){if (count == 0){arr(mine, show, x - 1, y);arr(mine, show, x - 1, y - 1);arr(mine, show, x - 1, y + 1);arr(mine, show, x, y - 1);arr(mine, show, x, y + 1);arr(mine, show, x + 1, y - 1);arr(mine, show, x + 1, y + 1);arr(mine, show, x + 1, y);}}}
}
1.8 计算游戏时间
time函数可以返回一个时间戳,我们可以利用这个函数计算游戏的时间。
int y = time(NULL);
while (1)
{system("cls");int x = time(NULL) - y;printf("%d", x);Sleep(1000);
}
1.9 游戏可改性
因为在写这个程序时需要输入很多的数字,如果我们想修改这些数时就要一个一个改,这样非常的麻烦。为了避免这些麻烦我们只需要在头文件定义某字符等于某个数字就可以了,这样我们想改游戏参数的时候在头文件game.h改就行了。
#define ROW 9
#define COL 9#define ROWS ROW+2
#define COLS COL+2
#define EsayCount 10
比如当我们想改行和列改为16炸弹数量改为40的时候,我们只需要在头文件将ROW 与 COL定义为16就可以了。
#define ROW 16
#define COL 16#define ROWS ROW+2
#define COLS COL+2
#define EsayCount 40
1.10 控制台颜色的修改
使用system("color attr");函数可以修改控制台颜色,这个函数需要使用#include<windonws.h>调用。颜色可以参考下面这张图:
例:
2. 完整代码
2.1 game.h头文件
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<windows.h>
#define ROW 9
#define COL 9#define ROWS ROW+2
#define COLS COL+2
#define EsayCount 10//声明函数
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char test);
//
void DisPalyBoard(char arr[ROW][COL], int row, int col, int o);
//布置雷的信息
void SetMine(char arr[ROWS][COLS], int row, int col, int o);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int o);
2.2 game.c文件
#include"game.h"
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)
{int i = 0;for (i = 0; i < rows; i++){for (int j = 0; j < cols; j++){arr[i][j] = set;}}
}
void DisPalyBoard(char arr[ROWS][COLS], int row, int col,int o)
{//清屏system("cls");printf("-----------扫雷游戏----------\n");//计算时间printf("已用时间:%ds\n", time(NULL) - o);int i = 0;for (i = 0; i <= col; i++){printf("%2d ", i);}printf("\n");for (i = 1; i <= row; i++){printf("%2d ", i);for (int j = 1; j <= col; j++){printf("%2c ", arr[i][j]);}printf("\n");}
}void SetMine(char arr[ROWS][COLS], int row, int col)
{int count = EsayCount;while (count){int x = rand() % row + 1;int y = rand() % col + 1;if (arr[x][y] == '0'){arr[x][y] = '1';count--;}}
}int GetMineCount(char mine[ROWS][COLS], int x, int y)
{//return (mine[x - 1][y] + mine[x - 1][y - 1] + mine[x][y - 1] + mine[x + 1][y - 1] // + mine[x + 1][y + 1] + mine[x - 1][y + 1] + mine[x + 1][y] + mine[x][y + 1] - 8 * '0');int a = 0;for (int i = x - 1; i <= x + 1; i++){for (int j = y - 1; j <= y + 1; j++){a += mine[i][j];}}return a - '0' * 9;
}int win = 0;
void arr(char mine[ROWS][COLS], char show[ROWS][COLS], int x,int y)
{if (show[x][y] == '*'&& x >= 1 && x <= ROW && y >= 1 && y <= ROW){int count = GetMineCount(mine, x, y);show[x][y] = count + '0';win++;if (count == 0){arr(mine, show, x - 1, y);arr(mine, show, x - 1, y - 1);arr(mine, show, x - 1, y + 1);arr(mine, show, x, y - 1);arr(mine, show, x, y + 1);arr(mine, show, x + 1, y - 1);arr(mine, show, x + 1, y + 1);arr(mine, show, x + 1, y);}}
}void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int o)
{int x = 0, y = 0;while (win < row * col - EsayCount){printf("请输入要排查的坐标(0 0重开):>");scanf("%d %d", &y, &x);if (x >= 1 && x <= row && y >= 1 && y <= col){if (mine[x][y] == '1'){DisPalyBoard(mine, ROW, COL, o);printf("你被炸死了!!!\n");break;}else{//该坐标不是雷,就得统计该坐标的周围有几个雷arr(mine, show, x, y);DisPalyBoard(show, ROW, COL, o);}}else if (x == 0 && y == 0){printf("重新开始游戏。\n");break;}else{printf("坐标非法,请重新输入\a\n");}}if (win == row * col - EsayCount){DisPalyBoard(mine, ROW, COL, o);printf("恭喜你,排雷成功\n");}
}
2.3 test.c文件
#include"game.h"void menu()
{printf("----------------扫雷----------------\n");printf("| |\n");printf("| 1.play |\n");printf("| 0.exit |\n");printf("| |\n");printf("------------------------------------\n");
}void game()
{int o = time(NULL);//存放布置好雷的信息char mine[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };InitBoard(show, ROWS, COLS, '*');InitBoard(mine, ROWS, COLS, '0');//随机布置10个雷SetMine(mine, ROW, COL, o);//打印棋盘/*DisPalyBoard(mine, ROW, COL,o);*/DisPalyBoard(show, ROW, COL, o);//排查雷FindMine(mine, show, ROW, COL, o);
}
int main()
{int input = 0;srand((unsigned int)time(NULL));do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case 1:game();break;case 0:printf("游戏结束,退出游戏\n");break;default:printf("输入错误请重新输入\a\n");}} while (input);return 0;
}
2.4 效果图:
相关文章:

【c语言】扫雷
前言: 扫雷是一款经典的单人益智游戏,它的目标是在一个方格矩阵中找出所有的地雷,而不触碰到任何一颗地雷。在计算机编程领域,扫雷也是一个非常受欢迎的项目,因为它涉及到许多重要的编程概念,如数组、循环…...

自然语言处理的崛起:从初步分析到深度理解
自然语言处理(NLP)是计算机科学、人工智能和语言学的交叉领域,旨在让计算机能够理解和生成人类语言。随着时间的推移,NLP 经历了一系列革命性的变化,从简单的规则和模式匹配到如今的深度学习模型,它们使计算…...
Git学习笔记:版本回滚
文章目录 回到过去:开启新时间线,时间分叉路口1. 回溯开发2. 临时恢复特性3. 实验性开发4. 分支维护和发布5. 调试历史问题类比推理: 方法:1. 临时查看旧版本2. 永久回滚到旧版本3. 创建新的分支指向旧版本 回到过去:开…...

OpenCV图像的基本操作
图像的基本操作(Python) 素材图 P1:die.jpg P2:cool.jpg V:rabbit.mp4, 下载地址 读取展示-图像 import cv2img_1 cv2.imread(./die.jpg) # default cv2.IMREAD_COLOR print("die.jpg shape(imre…...

小白水平理解面试经典题目LeetCode 594 Longest Harmonious Subsequence(最大和谐字符串)
594 最大和谐字符串 这道题属于字符串类型题目,解决的办法还是有很多的,暴力算法,二分法,双指针等等。 题目描述 和谐数组是指一个数组里元素的最大值和最小值之间的差别 正好是 1 。 现在,给你一个整数数组 nums …...

Vue-35、Vue中使用ref属性
1、ref属性 2、代码 <template><div id"app"> <!-- <img alt"Vue logo" src"./assets/logo.png">--><h1 v-text"msg" ref"title"></h1><button click"showDOM" ref&…...

网络通信(15)-C#TCP客户端掉线重连实例
本文上接前面的文章使用Socket在C#语言环境下完成TCP客户端的掉线重连实例。 掉线重连需要使用心跳包发送测试网络的状态,进而进入重连循环线程。 前面实例完成的功能: 客户端与服务器连接,实现实时刷新状态。 客户端接收服务器的数据。 客户端发送给服务器的数据。 客…...

React进阶 - 14(说一说”虚拟DOM“中的”Diff算法“)
本章内容 目录 一、了解 Diff 算法二、key 值的重要性三、为什么不建议使用 index 做 key 值 上一节我们初步了解了 React中的”虚拟 DOM“ ,本节我们来说一说”虚拟DOM“中的”Diff算法“ 一、了解 Diff 算法 在上一篇中,我们有讲到:当 st…...

#GPU|LLM|AIGC#集成显卡与独立显卡|显卡在深度学习中的选择与LLM GPU推荐
区别 核心区别:显存,也被称作帧缓存。独立显卡拥有独立显存,而集成显卡通常是没有的,需要占用部分主内存来达到缓存的目的 集成显卡: 是集成在主板上的,与主处理器共享系统内存。 一般会在很多轻便薄型的…...

HCIP-IPV6实验
实验拓扑 实验需求 全网可达 实验思路 配置IP地址 配置路由协议-ospf 配置R2 配置IPV6 配置R2Tunnel 将所有地址引流到Tunnel0/0/0接口 ripng配置 汇总 实验步骤 配置IP地址 以R2为例 [Huawei]sys r2 [r2]int g0/0/0 [r2-GigabitEthernet0/0/0]ip address 12.1.1…...

如何训练和导出模型
介绍如何通过DI-engine使用DQN算法训练强化学习模型 一、什么是DQN算法 DQN算法,全称为Deep Q-Network算法,是一种结合了Q学习(一种价值基础的强化学习算法)和深度学习的算法。该算法是由DeepMind团队在2013年提出的,…...

Springboot注解@Aspect(一)之@Aspect 作用和Aop关系详解
目录 Aspect的使用 配置 作用 通知相关的注解 例子 结果: Aspect作用和Spring Aop关系 示例 标签表达式 Aspect的使用 配置 要启用 Spring AOP 和 Aspect 注解,需要在 Spring 配置中启用 AspectJ 自动代理,但是在 Spring Boot 中&a…...

自动化防DDoS脚本
简介 DDoS (分布式拒绝服务攻击)是一种恶意的网络攻击,旨在通过占用目标系统的资源,使其无法提供正常的服务。在DDoS攻击中,攻击者通常控制大量的被感染的计算机或其他网络设备,同时将它们协调起来向目标系…...
ubuntu怎么查看有几个用户
在Ubuntu中,可以使用以下命令来查看系统中的用户数量: cat /etc/passwd | wc -l这个命令会读取 /etc/passwd 文件中的用户信息,并使用 wc -l 命令来计算行数,即用户数量。 另外,你也可以使用以下命令来查看当前登录到…...

Linux | makefile简单教程 | Makefile的工作原理
前言 在学习完了Linux的基本操作之后,我们知道在linux中编写代码,编译代码都是要手动gcc命令,来执行这串代码的。 但是我们难道在以后运行代码的时候,难道都要自己敲gcc命令嘛?这是不是有点太烦了? 在vs中…...

pcl+vtk(十四)vtkCamera相机简单介绍
一、vtkCamera相机 人眼相当于三维场景下的相机, VTK是用vtkCamera类来表示三维渲染场景中的相机。vtkCamera负责把三维场景投影到二维平面,如屏幕、图像等。 相机位置:即相机所在的位置,用方法vtkCamera::SetPosition()设置。 相…...

TS基础知识点快速回顾(上)
基础介绍 什么是 TypeScript? TypeScript,简称 ts,是微软开发的一种静态的编程语言,它是 JavaScript 的超集。 那么它有什么特别之处呢? js 有的 ts 都有,所有js 代码都可以在 ts 里面运行。ts 支持类型支持&#…...
hook(post-receive)无法使用
hook(post-receive)无法使用 为什么无法使用? 只有一个问题:权限不够,你想想,blog.git是一个中转站,咱们要把上传的东西转到blog下面,肯定要有写入操作呀,这个Git仓库的…...

qt学习:tcp区分保存多个客户端
在前面文掌的tcp客服端服务端进行更改 qt学习:Network网络类tcp客户端tcp服务端-CSDN博客https://blog.csdn.net/weixin_59669309/article/details/135842933?spm1001.2014.3001.5501前面的服务端每次有新的客户端连接,就会覆盖掉原来的指针࿰…...

ORM-08-EclipseLink 入门介绍
拓展阅读 The jdbc pool for java.(java 手写 jdbc 数据库连接池实现) The simple mybatis.(手写简易版 mybatis) 1. EclipseLink概述 本章介绍了EclipseLink及其关键特性:包括在EclipseLink中的组件、元数据、应用程序架构、映射和API。 本…...

python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...

定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...