C语言:扫雷游戏实现

一、扫雷游戏的分析和设计

扫雷游戏想必大家都玩过吧,初级的玩法是在一个9*9的棋盘上找到没有雷的格子,而今天我们就要做的就是9*9扫雷游戏的实现。

1、游戏功能和规则

  • 使用控制台实现经典的扫雷游戏
  • 游戏可以通过菜单实现继续玩或者退出游戏
  • 扫雷的棋盘是9*9的格⼦
  • 默认随机布置10个雷(可随意)
  • 可以排查雷

如果位置不是雷,就显示周围有几个雷

如果位置是雷,就炸死游戏结束

把除10个雷之外的所有非雷都找出来,排雷成功,游戏结束

2、游戏实现思路

  1. 首先,创建一个主函数用于判断是否进行游戏,并设计一个菜单。
  2. 创建用于存放雷的棋盘,并进行棋盘的初始化。
  3. 设计棋盘的打印。
  4. 放入雷,并实现有雷棋盘的打印。
  5. 输入坐标进行排查,并返回排查结果。
  6. 进行循环直到排查成功或被炸死。

在布置雷的过程中我们将雷设置为'1',不是雷设置为'0'; 

二、代码实现

在实现代码前,我们可以用多文件的方式,对我们的函数进行声明和定义,这样可以简化和简洁直观的设计和表达代码。

  • game.h:我们可以在game.h文件中包含我们所有需要用到的头文件,常量的定义和函数的声明,其他文件只需要声明game.h 即可。
  • game.c:写入游戏所需要的功能函数。
  • test.c:代码的整合

1、主函数的实现

在主函数中我们先创建一个input值,用于输入我们的选择,根据 do while 循环判断我们是否进行游戏,并且每次循环都打印菜单,在接着使用switch语句根据玩家输入进行判断,如果输入为1就开始游戏执行game(),如果为0,游戏结束并跳出循环,如果输入错误就继续进行循环直到主动退出。

int main()
{int input = 0;srand((unsigned int)time(NULL));do {menu();printf("请输入选项:");scanf("%d", &input);switch (input){case 1:printf("开始游戏\n");game();break;case 0:printf("游戏结束\n");break;default:printf("选择错误,请重新选择:\n");break;}} while (input);return 0;
}

 2、菜单的实现

不需要返回所以用void

void menu()
{printf("****************\n");printf("**** 1.play ****\n");printf("**** 0.exit ****\n");printf("****************\n");
}

 3、游戏函数的实现

1、棋盘的设计

在排雷的过程中如果我们选择的位置不是雷就会看它周围的8个坐标中是否有雷,如果有雷就会显示雷的个数。

但如果我们选择的是边界位置,就会超出棋盘的范围,导致越界。

所以我们要将棋盘扩大一圈,这样就不存在越界问题了。

假设我们现在已经布置好了雷(雷用1表示,不是雷用0表示),当我们输入一个坐标的时候,如果这个坐标周围有一个雷,那么我们需要将这个雷的数量信息记录并存储下来,同时打印给玩家,但是我们存放雷的数组里面已经有数据了,如果再存放在里面就会可能产生混淆从而导致棋盘混乱打印困难,所以我们可以设置两个棋盘,一个是雷的棋盘mine,一个是用于放置雷的信息的棋盘show,我们后面会把雷布置到到mine数组里面,再mine数组排查雷之后,将雷的信息存放到show数组里面,然后打印show数组的信息给用户参考排查,这样就不会存在数据混淆了。

同时我们也要在game.h文件里进行常量的定义。

2、棋盘的初始化

在设计好棋盘后,我们就应该对棋盘进行初始化,首先,我们将mine棋盘全初始化为'0',show棋盘全初始化为'*'.

//棋盘的初始化
void InitBoard(char board[ROWS][COLS], int row, int col, char set)
{for (int i = 1; i < row; i++){for (int j = 1; j < col; j++){board[i][j] = set;}}
}

因为要初始化两个数组,所以我们需要创建一个char set,用于接收'0' 和 '*' 。

3、打印棋盘

因为是扫雷游戏,所以我们只需要打印一个隐藏信息的棋盘即可

我们只需要将show数组,行和列传给函数,并且为了显示行和列数,我们可以先利用for循环打印0-col的一行数,再进入棋盘的打印 ,在行的循环中打印一列数

//棋盘的打印
void DisplayBoard(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");}printf("-----------扫雷-------------\n");
}

 

4、雷的布置

 我们需要在mine数组里布置雷,那我们该如何布置呢?

1.这就需要用到我们的rand()函数了。

rand()函数是随机数生成函数,需要使用stdlib,h文件,但生成的数不是完全的随机数,而是伪随机数,我们需要改变他的种子,才能真正的生成随机数;

 2.这就需要用到我们的srand()函数了

它一般用于初始化随机数生成器,通常是为rand函数设置种子,以便生成不同的随机数序列。所以我们在每次调用rand函数之前应先调用srand函数,以传入不同的种子。而srand函数通过参数seed来设置它的随机生成数,也就是说我们需要种子的种子不是一个固定值,只有这样,rand函数生成的数才是真正的随机数。

 3、这就用到了time()函数了

因为时间一直在变化,所以我们可以用时间来当作srand函数的种子,它需要包含time.h的头文件。

所以我们在主函数里设计了srand函数

但随机数的范围是没法确定的,所以我们需要固定一个范围

用x表示行用y表示列,如果棋盘长度为9,rand()%9就是0-8,+1就是0-9,同理列也是这样

之后我们设置雷的数量, 设为count=EASY_COUNT,在game.h上也定义常量EASY_COUNT 10;

在利用while循环条件设置为count,布置一个雷count--;在循环中,利用if语句将随机生成的下标位置如果不等与'1',就设置为'1'

//布置雷
void SetMine(char board[ROWS][COLS], int row, int col)
{int count = EASY_COUNT;while (count){//生成随机下标//x:1-9//y:1-9int x = rand() % row + 1;int y = rand() % col + 1;if (board[x][y] != '1');{board[x][y] = '1';count--;}}
}

5、雷的排查

排查雷需要利用循环,那么判断循环结束的条件是什么呢? 

把除10个雷之外的所有非雷都找出来,排雷成功,游戏结束

如果位置是雷,就炸死游戏结束

所以条件就是找到不是雷的所有坐标既

设置win为不是雷的坐标数

row*col:全部坐标数

EASY_COUNT:雷数

win<row*col-EASY_COUNT 

我们需要规定输入坐标的范围,如果判断的坐标值为'1',游戏结束,并打印所有雷;如果不是,win++,并返回周围雷数,由于返回的值应该是字符 ,所以要让返回值+'0';并打印所有雷。

如果排查雷数等于win=row*col-EASY_COUNT 就是排查成功,并打印所有雷。

//排查雷
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 - EASY_COUNT){printf("请输入你想要排查的坐标:");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (mine[x][y] == '1'){printf("很遗憾,此处是雷,被炸死\n");DisplayBoard(mine, ROW, COL);break;}else{win++;printf("还要排查%d个位置\n", row * col - EASY_COUNT - win);int c = GetMineCount(mine, x, y);show[x][y] = c + '0';DisplayBoard(show, ROW, COL);}}else{printf("输入坐标有误,请重新输入\n");}}if (win == row * col - EASY_COUNT){printf("恭喜你,排雷成功\n");DisplayBoard(mine, ROW, COL);}}

6、返回周围雷数

//返回周围雷数
int GetMineCount(char mine[ROWS][COLS], 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,非雷为0;所以将周围坐标相加就是雷数,再减去8*'0',就是雷的个数.

三、完整代码

game.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>#define EASY_COUNT 10#define ROW 9
#define COL 9#define ROWS ROW+2
#define COLS COL+2void InitBoard(char board[ROWS][COLS],int row, int col, int set);void DisplayBoard(char board[ROWS][COLS], int row, int col);void SetMine(char board[ROWS][COLS], int row, int col);void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

test.c

#include"game.h"void menu()
{printf("****************\n");printf("**** 1.play ****\n");printf("**** 0.exit ****\n");printf("****************\n");
}void game()
{//建立数组char mine[ROWS][COLS] = { 0 };//用来存放布置好的雷的信息char show[ROWS][COLS] = { 0 };//用来存放排查出的雷的信息//初始化InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');//打印棋盘//DisplayBoard(mine, ROW, COL);DisplayBoard(show, ROW, COL);//布置雷SetMine(mine, ROW, COL);//排查雷FindMine(mine,show, ROW, COL);}int main()
{int input = 0;srand((unsigned int)time(NULL));do {menu();printf("请输入选项:");scanf("%d", &input);switch (input){case 1:printf("开始游戏\n");game();break;case 0:printf("游戏结束\n");break;default:printf("选择错误,请重新选择:\n");break;}} while (input);return 0;
}

game.c

#include"game.h"//棋盘的初始化
void InitBoard(char board[ROWS][COLS], int row, int col, char set)
{for (int i = 1; i < row; i++){for (int j = 1; j < col; j++){board[i][j] = set;}}
}//棋盘的打印
void DisplayBoard(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");}printf("-----------扫雷-------------\n");
}//布置雷
void SetMine(char board[ROWS][COLS], int row, int col)
{int count = EASY_COUNT;while (count){//生成随机下标//x:1-9//y:1-9int x = rand() % row + 1;int y = rand() % col + 1;if (board[x][y] != '1');{board[x][y] = '1';count--;}}
}//返回周围雷数
int GetMineCount(char mine[ROWS][COLS], 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 - EASY_COUNT){printf("请输入你想要排查的坐标:");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (mine[x][y] == '1'){printf("很遗憾,此处是雷,被炸死\n");DisplayBoard(mine, ROW, COL);break;}else{win++;printf("还要排查%d个位置\n", row * col - EASY_COUNT - win);int c = GetMineCount(mine, x, y);show[x][y] = c + '0';DisplayBoard(show, ROW, COL);}}else{printf("输入坐标有误,请重新输入\n");}}if (win == row * col - EASY_COUNT){printf("恭喜你,排雷成功\n");DisplayBoard(mine, ROW, COL);}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/388135.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flink SQL 的工作机制

前言 Flink SQL 引擎的工作流总结如图所示。 从图中可以看出&#xff0c;一段查询 SQL / 使用TableAPI 编写的程序&#xff08;以下简称 TableAPI 代码&#xff09;从输入到编译为可执行的 JobGraph 主要经历如下几个阶段&#xff1a; 将 SQL文本 / TableAPI 代码转化为逻辑执…

面试经典算法150题系列-数组/字符串操作之多数元素

序言&#xff1a;今天是第五题啦&#xff0c;前面四题的解法还清楚吗&#xff1f;可以到面试算法题系列150题专栏 进行复习呀。 温故而知新&#xff0c;可以为师矣&#xff01;加油&#xff0c;未来的技术大牛们。 多数元素 给定一个大小为 n 的数组 nums &#xff0c;返回其…

C#实现深度优先搜索(Depth-First Search,DFS)算法

深度优先搜索&#xff08;DFS&#xff09;是一种图搜索算法&#xff0c;它尽可能深入一个分支&#xff0c;然后回溯并探索其他分支。以下是使用C#实现DFS的代码示例&#xff1a; using System; using System.Collections.Generic;class Graph {private int V; // 顶点的数量pr…

大模型算法备案流程最详细说明【流程+附件】

文章目录 一、语料安全评估 二、黑盒测试 三、模型安全措施评估 四、性能评估 五、性能评估 六、安全性评估 七、可解释性评估 八、法律和合规性评估 九、应急管理措施 十、材料准备 十一、【线下流程】大模型备案线下详细步骤说明 十二、【线上流程】算法备案填报…

ChatGLM3-6B模型部署微调实战

准备 视频教程 https://www.bilibili.com/video/BV1ce411J7nZ?p14&vd_source165c419c549bc8d0c2d71be2d7b93ccc 视频对应的资料 https://pan.baidu.com/wap/init?surlAjPi7naUMcI3OGG9lDpnpQ&pwdvai2#/home/%2FB%E7%AB%99%E5%85%AC%E5%BC%80%E8%AF%BE%E3%80%90%E8…

HTTP协议详解(一)

协议 为了使数据在网络上从源头到达目的&#xff0c;网络通信的参与方必须遵循相同的规则&#xff0c;这套规则称为协议&#xff0c;它最终体现为在网络上传输的数据包的格式。 一、HTTP 协议介绍 HTTP&#xff08;Hyper Text Transfer Protocol&#xff09;&#xff1a; 全…

Monorepo简介

Monorepo 第一章&#xff1a;与Monorepo的邂逅第二章&#xff1a;Multirepo的困境第三章&#xff1a;Monorepo的魔力 - 不可思议的解决问题能力第四章&#xff1a;Monorepo的挑战与应对策略第五章&#xff1a;总结第六章&#xff1a;参考 第一章&#xff1a;与Monorepo的邂逅 …

【AI大模型】分布式训练:深入探索与实践优化

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 文章目录 一、分布式训练的核心原理二、技术细节与实现框架1. 数据并行与模型并行2. 主流框架 三、面临的挑战与优化策略1. 通信开销2. 数据一致性3. 负载均衡 4.使用示例示例一&#xff1a;TensorFlow中的数据…

VAE、GAN与Transformer核心公式解析

VAE、GAN与Transformer核心公式解析 VAE、GAN与Transformer&#xff1a;三大深度学习模型的异同解析 【表格】VAE、GAN与Transformer的对比分析 序号对比维度VAE&#xff08;变分自编码器&#xff09;GAN&#xff08;生成对抗网络&#xff09;Transformer&#xff08;变换器&…

设计师的素材管理神器,eagle、千鹿大测评

前言 专业的设计师都会精心维护自己的个人素材库&#xff0c;常常需要耗费大量时间用于浏览采集、分类标注、预览筛选、分享协作&#xff0c;还要管理字体、图片、音视频等各类设计素材 如果你作为设计师的话&#xff0c;今天&#xff0c;就为大家带来两款热门的素材管理工具…

SpringMVC中的常用注解

目录 SpringMVC的定义 SpringMVC的常用注解 获取Cookie和Session SpringMVC的定义 Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架&#xff0c;从⼀开始就包含在 Spring 框架中。它的正式名称“Spring Web MVC”来⾃其源模块的名称(Spring-webmvc)&#xff0c;但它…

全麦饼:健康与美味的完美结合

在追求健康饮食的当下&#xff0c;全麦饼以其独特的魅力脱颖而出&#xff0c;成为了众多美食爱好者的新宠。食家巷全麦饼&#xff0c;顾名思义&#xff0c;主要由全麦面粉制作而成。与普通面粉相比&#xff0c;全麦面粉保留了小麦的麸皮、胚芽和胚乳&#xff0c;富含更多的膳食…

免费聊天回复神器微信小程序

客服在手机上通过微信聊天&#xff0c;回复客户咨询的时候&#xff0c;如果想把整理好的话术一键发给客户&#xff0c;又不想切换微信聊天窗口&#xff0c;微信小程序是一个很好的选择 微信小程序支持微信聊天 客服在手机上通过微信聊天&#xff0c;回复客户咨询的时候&#x…

Shell编程——简介和基础语法(1)

文章目录 Shell简介什么是ShellShell环境第一个Shell脚本Shell脚本的运行方法 Shell基础语法Shell变量Shell传递参数Shell字符串Shell字符串截取Shell数组Shell运算符 Shell简介 什么是Shell Shell是一种程序设计语言。作为命令语言&#xff0c;它交互式解释和执行用户输入的命…

linux进程控制——进程等待——wait、waitpid

前言&#xff1a;本节内容仍然是进程的控制&#xff0c;上一节博主讲解的是进程控制里面的进程创建、进程退出、终止。本节内容将讲到进程的等待——等待是为了能够将子进程的资源回收&#xff0c;是父进程等待子进程。 我们前面的章节也提到过等待&#xff0c; 那里的等待是进…

ThreadPoolExecutor工作原理及源码详解

一、前言 创建一个线程可以通过继承Thread类或实现Runnable接口来实现&#xff0c;这两种方式创建的线程在运行结束后会被虚拟机回收并销毁。若线程数量过多&#xff0c;频繁的创建和销毁线程会浪费资源&#xff0c;降低效率。而线程池的引入就很好解决了上述问题&#xff0c;…

计算机组成原理---机器中的数字表示

二进制&#xff0c;八进制&#xff0c;十六进制之间转化 十进制转二进制 75.3的整数部分75&#xff1a; 75.3小数部分0.3&#xff1a; 原则&#xff1a;1.先除r/乘r得到的是结果部分中接近小数点的数字 2.都是取结果一部分&#xff08;余数/整数部分&#xff09;&#xff0c;使…

51单片机15(直流电机实验)

一、序言&#xff1a;我们知道在单片机当中&#xff0c;直流电机的控制也是非常多的&#xff0c;所以有必要了解一些这个电机相关的一些知识&#xff0c;以及如何使用单片机来控制这个电机&#xff0c;那么在没有学习PWM之前&#xff0c;我们先简单的使用GPIO这个管脚来控制电机…

npm提示 certificate has expired 证书已过期 已解决

在用npm新建项目时&#xff0c;突然发现报错提示 : certificate has expired 证书已过期 了解一下&#xff0c;在网络通信中&#xff0c;HTTPS 是一种通过 SSL/TLS 加密的安全 HTTP 通信协议。证书在 HTTPS 中扮演着至关重要的角色&#xff0c;用于验证服务器身份并加密数据传输…

vue实现电子签名、图片合成、及预览功能

业务功能&#xff1a;电子签名、图片合成、及预览功能 业务背景&#xff1a;需求说想要实现一个电子签名&#xff0c;然后需要提供一个预览的功能&#xff0c;可以查看签完名之后的完整效果。 需求探讨&#xff1a;后端大佬跟我说&#xff0c;文档我返回给你一个PDF的oss链接…