C语言项目实战——扫雷

2024-04-27 17:52
文章标签 语言 实战 项目 扫雷

本文主要是介绍C语言项目实战——扫雷,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1.前言

2.完整流程

2.1规划书

2.2代码部分

2.2.1文件的结构设计

2.2.2变量的创建

2.2.3菜单的基本实现

2.2.4初始化期棋盘

2.2.5输出完整棋盘

2.2.6埋雷的实现

2.2.7查询周围雷的数量

2.2.8扫雷的实现

 2.2.9完整代码

3.总结


1.前言

哈喽大家好吖,今天笔者就前期基本所学手搓了一个扫雷的小项目,考察的知识点很简单仅有基本的分支,循环,函数调用,数组的基本应用,相信你也可以做到滴,快来试试喔~

2.完整流程

2.1规划书

虽然完成扫雷的代码量并不大,但我们还是要理清楚我们需要完成的功能和运行的基本逻辑。

 

这是一张扫雷的基本界面,通过观察和实际游玩可分析得出:

基本功能包括:

  • 游戏可以通过菜单实现继续玩或者退出游戏
  • 扫雷的棋盘是9*9的格⼦
  • 默认随机布置10个雷
  • 可以排查雷
  • 如果位置不是雷,就显⽰周围有⼏个雷
  • 如果位置是雷,就炸死游戏结束
  • 把除10个雷之外的所有非雷都找出来,排雷成功,游戏结束

在梳理完需要实现的功能以后,就可以开始逐步实现以上功能咯。(当然笔者目前无法做出上述照片如此精良的扫雷,只能做一个简略版滴~)

2.2代码部分

2.2.1文件的结构设计

扫雷的代码量虽然不大,但是已经不适合用单文件来完成了,于是乎我们就把,游戏逻辑的基本实现,相关游戏函数的声明,以及游戏相关函数的实现分别打包,方便管理。

我们创建以下三个文件:

test.c //游戏的测试逻辑 
game.c //游戏中函数的实现
game.h //游戏需要的数据类型和函数声明等

完成后是这个样子。

另外,在正式敲代码前,我们应先在game.h这个头文件下加上

#pragma once

 #pragma once 是一个预处理指令,用来防止头文件的内容在一个编译单元中被多次包含。这与传统的头文件保护(也称为包含保护或头文件守卫)非常相似,后者通常使用#ifndef, #define, 和 #endif来实现。

2.2.2变量的创建

在扫雷这个游戏中,我们一共需要用到以下几个变量:

  • 棋盘一(origin)用于记录是否埋雷
  • 棋盘二(infor)用于记录雷的相关信息
  • 常量row,col分别用于记录扫雷中最核心的9*9区域
  • 常量rows,cols用于记录大棋盘11*11区域
  • 常量easy用于记录所要标记的雷

 实现分别如下(常量记得要在head.h里面创建):

//相关函数的声明
#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 easy 10//记录简单难度有十个雷

 俩个棋盘的创建我放在了game函数中。

void game() {char origin[rows][cols];char infor[rows][cols];//创建俩个棋盘//初始化棋盘init(origin, rows, cols, '0');init(infor, rows, cols, '*');//打印棋盘用于调试print(infor, row, col);//开始埋雷setboom(origin, row, col);//print(origin, row, col);//开始排雷findboom(origin, infor, row, col);}

2.2.3菜单的基本实现

为了菜单的基本美观,我们在实现的时候可以进行反复调试,代码如下:

void menu() {printf("------------------------\n");printf("------欢迎来到扫雷------\n");printf("------------------------\n");printf("----------菜单----------\n");printf("-------1.开始游戏-------\n");printf("-------2.结束游戏-------\n");//基础菜单实现printf("---------3.彩蛋---------\n");return;
}
int main() {int n = 0;//创建选项变量srand((unsigned int)time(NULL));do {menu();printf("请选择选项\n");scanf("%d", &n);switch (n) {case 1:game(); break;case 2:printf("已退出\n"); n = 0; break;case 3:printf("彩蛋\n"); n = 0; break;default:printf("请重新输入\n");}} while (n);//do while的巧妙利用return 0;
}

菜单的基本功能的实现是通过switch语句, 如果要玩游戏输入1进入game函数,如果选择退出或者彩蛋选项,将会在case语句中将n置为0从而跳出do while语句,最终实现是这个样子:

2.2.4初始化期棋盘

从这一部分往下,就是开始要分别写出实现每个小功能的函数,记得在game.c中写完函数要在game.h完成声明。

对于初始化,我们将origin这个棋盘全部置为字符'0',将infor这个棋盘全部置为'*'。

game.c中:

void init(char board[rows][cols], int rows1, int cols1, char set) {int i = 0;for (i = 0; i < rows; i++){int j = 0;for (j = 0; j < cols; j++){board[i][j] = set;}}
}

函数的声明我在这就不完成了,就是一个小小体力活, 最后完整代码会体现出来。效果如下:

2.2.5输出完整棋盘

输出的时候,除了将9*9的核心区域打印出来,还要记得标记行列(1~9)以及x,y轴,增加可玩性。

void print(char board[rows][cols], int row1, int col1) {printf("-----蘸豆---爽-----\n");printf("0 1 2 3 4 5 6 7 8 9 y\n");for (int i = 1; i <= row1; i++) {printf("%d ", i);for (int j = 1; j <= col1; j++) {printf("%c ", board[i][j]);}printf("\n");}printf("x\n");
}

最终效果如下:

2.2.6埋雷的实现

由于埋雷的随机性,这里需要一个c语言中的随机数函数rand。

rand用法:

在C语言中,rand() 是一个标准库函数,用于生成一个伪随机数。这个函数定义在 <stdlib.h> 头文件中。rand() 函数返回一个在 0 到 RAND_MAX 之间的整数,其中 RAND_MAX 是在 <stdlib.h> 中定义的一个宏,其值至少为 32767

由于 rand() 生成的是伪随机数,因此在每次程序运行时,如果不进行任何设置,它将生成相同的随机数序列。为了得到不同的随机数序列,通常在程序开始时使用 srand() 函数来设置随机数生成器的种子。种子的值通常来自于系统时间或者其他变化的数据。

这里就是用时间作为种子:srand((unsigned int)time(NULL)); (在主函数中书写了出来)

埋雷的时候我们使用while循环进行操作,另外有一个小小的注意点,如果该点已经被埋过雷了,注意排除,代码如下:

void setboom(char board[rows][cols], int row1, int col1) {int count = easy;//记录雷数while (count) {int x = rand() % 9 +1;int y = rand() % 9 +1;if (board[x][y] == '0') {board[x][y] = '1';count--;}}
}

如果该位置为'0'就进行埋雷操作,如果为'1'就重复该循环。

2.2.7查询周围雷的数量

在正式开始扫雷函数的实现前,我们还需要先实现查找以该点为中心(非雷)周围八个格子雷的数量。实现这个功能有很多方式,这我采用了ascii码的一些基本特性。 

int set_infor(char board[rows][cols], int x, int y) {return (board[x - 1][y - 1] + board[x][y - 1] +board[x - 1][y] + board[x][y + 1]+ board[x + 1][y - 1] + board[x + 1][y]+ board[x + 1][y + 1] + board[x - 1][y + 1] - 8 * '0');
}

因为我创建的俩个棋盘都是char类型,所以说这个方法就可以使用。

2.2.8扫雷的实现

这块部分比较核心,以下是思路讲解:

  • 创建下x,y变量用于记录坐标,创建win用于标记当前排除了多少个区域。
  • 主体函数为while循环,循环条件为win变量仍然小于9*9总格数减去总雷数,那么胜利条件自然是win变量等于9*9总格数减去总雷数。
  • 接下来讲解while主体里面思路:
  • 先让玩家输入x,y坐标,并判断该坐标是否为坐标上的合法目标,如果不是就让玩家重新输入,如果该坐标合法就进行下一步。
  • 判断如果玩家选择的坐标为雷,则该玩家被炸死并跳出循环。
  • 如果选择的非雷,就打印出该位置上周围八个格子的雷数。

最终代码如下:

void findboom(char origin1[rows][cols], char infor1[rows][cols], int row1, int col1) {int x = 0;int y = 0;int win = 0;//用于记录当前排掉了多少个雷while (win < row1 * col1 - easy) {printf("请输入你要排查的x坐标>__");scanf("%d", &x);printf("请输入你要排查的y坐标>__");scanf("%d", &y);if (x > 0 && y > 0 && x <= row1 && y <= col1) {if (origin1[x][y] == '1') {printf("你个憨批你被炸死了\n");break;}else {int num = set_infor(origin1, x, y);infor1[x][y] = num + '0';print(infor1, col1, row1);win++;}}else {printf("该坐标不在棋盘上,你这个笨蛋\n请重新输入\n");}}if (win == row1 * col1 - easy) {printf("恭喜你!你胜利咯\n");print(origin1, row1, col1);}
}

 运行如下图:

 2.2.9完整代码

game.h:

//相关函数的声明
#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 easy 10//记录简单难度有十个雷void menu();void init(char board[rows][cols], int rows1, int cols1, char set);void setboom(char board[rows][cols], int row1, int col1);void print(char board[rows][cols], int row1, int col1);int set_infor(char board[rows][cols], int x, int y);void findboom(char origin1[rows],char infor1[rows][cols],int row1,int col1);

 game.c:

#define  _CRT_SECURE_NO_WARNINGS 1
//相关函数的定义
#include"game.h"
void menu() {printf("------------------------\n");printf("------欢迎来到扫雷------\n");printf("------------------------\n");printf("----------菜单----------\n");printf("-------1.开始游戏-------\n");printf("-------2.结束游戏-------\n");//基础菜单实现printf("---------3.彩蛋---------\n");return;
}void init(char board[rows][cols], int rows1, int cols1, char set) {int i = 0;for (i = 0; i < rows; i++){int j = 0;for (j = 0; j < cols; j++){board[i][j] = set;}}
}void print(char board[rows][cols], int row1, int col1) {printf("-----蘸豆---爽-----\n");printf("0 1 2 3 4 5 6 7 8 9 y\n");for (int i = 1; i <= row1; i++) {printf("%d ", i);for (int j = 1; j <= col1; j++) {printf("%c ", board[i][j]);}printf("\n");}printf("x\n");
}void setboom(char board[rows][cols], int row1, int col1) {int count = easy;//记录雷数while (count) {int x = rand() % 9 +1;int y = rand() % 9 +1;if (board[x][y] == '0') {board[x][y] = '1';count--;}}
}int set_infor(char board[rows][cols], int x, int y) {return (board[x - 1][y - 1] + board[x][y - 1] +board[x - 1][y] + board[x][y + 1]+ board[x + 1][y - 1] + board[x + 1][y]+ board[x + 1][y + 1] + board[x - 1][y + 1] - 8 * '0');
}void findboom(char origin1[rows][cols], char infor1[rows][cols], int row1, int col1) {int x = 0;int y = 0;int win = 0;//用于记录当前排掉了多少个雷while (win < row1 * col1 - easy) {printf("请输入你要排查的x坐标>__");scanf("%d", &x);printf("请输入你要排查的y坐标>__");scanf("%d", &y);if (x > 0 && y > 0 && x <= row1 && y <= col1) {if (origin1[x][y] == '1') {printf("你个憨批你被炸死了\n");break;}else {int num = set_infor(origin1, x, y);infor1[x][y] = num + '0';print(infor1, col1, row1);win++;}}else {printf("该坐标不在棋盘上,你这个笨蛋\n请重新输入\n");}}if (win == row1 * col1 - easy) {printf("恭喜你!你胜利咯\n");print(origin1, row1, col1);}
}

test.c:

#define  _CRT_SECURE_NO_WARNINGS 1//游戏逻辑的实现
#include"game.h"void game() {char origin[rows][cols];char infor[rows][cols];//创建俩个棋盘//初始化棋盘init(origin, rows, cols, '0');init(infor, rows, cols, '*');//打印棋盘用于调试print(infor, row, col);//开始埋雷setboom(origin, row, col);//print(origin, row, col);//开始排雷findboom(origin, infor, row, col);}int main() {int n = 0;//创建选项变量srand((unsigned int)time(NULL));do {menu();printf("请选择选项\n");scanf("%d", &n);switch (n) {case 1:game(); break;case 2:printf("已退出\n"); n = 0; break;case 3:printf("彩蛋是这个~\n"); n = 0; break;default:printf("请重新输入\n");}} while (n);//do while的巧妙利用return 0;
}

3.总结

以上就是扫雷的基本功能实现了,其实还有许多可以扩展,例如点开一个非雷区自动展开周围其他非雷区域,调整难度等,大家都可以自己尝试尝试哦~。都看到这里了,希望大家对我多多支持喔,大家一起进步~

这篇关于C语言项目实战——扫雷的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/941154

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11 二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

滚雪球学Java(87):Java事务处理:JDBC的ACID属性与实战技巧!真有两下子!

咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java SE啦,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~ 🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!! 环境说明:Windows 10

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧