C语言扫雷游戏完整实现(上)

文章目录

  • 前言
  • 一、新建好头文件和源文件
  • 二、实现游戏菜单选择功能
  • 三、定义游戏函数
  • 四、初始化棋盘
  • 五、 打印棋盘函数
  • 六、布置雷函数
  • 七、玩家排雷菜单
  • 八、标记功能的菜单
  • 九、标记功能菜单的实现
  • 总结


前言

C语言从新建文件到游戏菜单,游戏函数,初始化棋盘,打印棋盘,布置雷函数,玩家排雷菜单,标记功能菜单及实现等的操作。

下半部分: C语言扫雷游戏完整实现(下)

一、新建好头文件和源文件

  • 库函数头文件常数都定义在game.h头文件中
  • 在test.c源文件和game.c源文件中通过#include "game.h"引入game.h头文件即可
    1. 在test.c源文件中实现菜单以及游戏函数的调用等功能。
    1. 在game.h头文件中主要完成游戏函数的声明等功能。
    1. 在game.c源文件中完成函数的定义/实现工程。

在这里插入图片描述

二、实现游戏菜单选择功能

// game.h 头文件
#include <stdio.h>

// test.c 源文件
#include "game.h"// 定义游戏菜单函数
void menu()
{printf("**********************\n");printf("*****   1. Play  *****\n");printf("*****   0. Quit  *****\n");printf("**********************\n");
}
int main()
{int input = 0; // 定义输入菜单选项的变量do{// 游戏菜单menu();printf("请选择:>");scanf("%d", &input);// 不同选择对应不同结果switch (input){case 1:printf("扫雷游戏开始!!!\n");break;case 0:printf("推出游戏!!!\n");break;default:printf("选择错误,请重新输入\n");break; // 因为要重新输入所以从菜单开始循环}} while (input); // 输入为0退出游戏,同时停止循环return 0;
}

三、定义游戏函数

  • 以9×9为例
  • 需要首先定义 11 × 11(为了便于检测棋盘边边位置的雷) 的棋盘(二维数组)
  • 打印9×9的棋盘即可
  • -需要定义两个棋盘
  • 一个用来存放布置雷的信息
  • 一个用来存放玩家操作信息
// game.h 头文件
#include <stdio.h>#define ROW 9
#define COL 9#define ROWS ROW + 2
#define COLS COL + 2

// test.c 源文件
#include "game.h"
// 定义游戏菜单函数
void menu()
{printf("**********************\n");printf("*****   1. Play  *****\n");printf("*****   0. Quit  *****\n");printf("**********************\n");
}
--------------------------------------------------------------
void game()
{// 定义两个二维数组char mine[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };// 初始化棋盘
}
---------------------------------------------------------------
int main()
{int input = 0; // 定义输入菜单选项的变量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); // 输入为0退出游戏,同时停止循环return 0;
}

四、初始化棋盘

  • 将存放布置雷信息的棋盘初始化为 ‘0’。----设计 ‘0’表示没有雷,‘1’表示雷。
  • 将玩家操作信息的棋盘初始化为 ‘*’。
// test.c --game函数
void game()
{// 定义两个二维数组char mine[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };// 初始化棋盘InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');
}

// game.h 头文件
#include <stdio.h>#define ROW 9
#define COL 9#define ROWS ROW + 2
#define COLS COL + 2// 初始化棋盘函数的声明
void InitBoard(char board[ROWS][COLS], int rows, int cols, char sign);

// game.c 源文件
#include "game.h"// 初始化棋盘函数的定义
void InitBoard(char board[ROWS][COLS], int rows, int cols, char sign)
{int i = 0;for (i = 0; i < rows; i++){int j = 0;for (j = 0; j < cols; j++){board[i][j] = sign;}}
}

五、 打印棋盘函数

  • 只打印9×9的棋盘,所以传入参数 ROW 和 COL。
  • 打印棋盘的同时还可以打印出每行每列的数字,方便玩家操作。
  • 同时打印出分割线例如 -----------扫雷游戏---------------
//test.c 源文件
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);
}

//game.h 头文件
#include <stdio.h>#define ROW 9
#define COL 9#define ROWS ROW + 2
#define COLS COL + 2// 初始化函数声明
void InitBoard(char board[ROWS][COLS], int rows, int cols, char sign);// 打印函数声明
void DisplayBoard(char board[ROWS][COLS], int row, int col);

//game.c 源文件
// 打印棋盘函数定义
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{// 打印游戏开头分割线printf("-----扫雷游戏------\n");int i = 0;// 打印每一列数字for (i = 0; i <= row; i++){printf("%d ", i); // 打印每一列数字}printf("\n");// 打印列数字完换行for (i = 1; i <= row; i++){// 打印每一列数字之前先打印出行号printf("%d ", i);int j = 0;for (j = 1; j <= col; j++){printf("%c ", board[i][j]);}printf("\n");}// 打印游戏结尾分割线printf("-----扫雷游戏------\n");
}

目前可以实现的效果如下图
在这里插入图片描述

六、布置雷函数

  • 在初始化棋盘和打印棋盘之间,应该先布置雷。在mine棋盘(数组)中布置。
  • 在game.h文件中定义常量 EASY_COUNT 来表示雷的数量。
  • 雷只用在9×9的范围内布置即可,所以传入参数 ROW 和 COL。
  • 通过生成9×9范围内的随机数,来布置雷。
  • 用到rand函数,引入 stdlib.h 和 time.h 头文件。
  • 为了保证随机数的随机性,需要在test.c的主函数一开始使用srand函数如下图
    在这里插入图片描述
//test.c 源文件 -- game函数
void game()
{// 定义两个二维数组char mine[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };// 初始化棋盘InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');// 布置雷SetBoard(mine, ROW, COL);// 打印棋盘DisplayBoard(mine, ROW, COL);DisplayBoard(show, ROW, COL);
}

//game.h 头文件
#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_COUNT 10// 初始化函数声明
void InitBoard(char board[ROWS][COLS], int rows, int cols, char sign);// 打印函数声明
void DisplayBoard(char board[ROWS][COLS], int row, int col);// 布置雷函数声明
void SetBoard(char board[ROWS][COLS], int row, int col);

//game.c 源文件
// 布置雷函数定义
void SetBoard(char board[ROWS][COLS], int row, int col)
{int count = EASY_COUNT;int x = 0;int y = 0;while (count){x = rand() % row + 1;y = rand() % col + 1;if (board[x][y] == '0'){board[x][y] = '1';count--;}}
}

七、玩家排雷菜单

  • 玩家排雷之前要有标记,排雷,以及退出终止的菜单。
  • 菜单选择需要玩家输入,所以定义变量,如若出入错误,循环输入。
//test.c 源文件 --- game函数
void game()
{int choose = 0;// 定义两个二维数组char mine[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };// 初始化棋盘InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');// 布置雷SetBoard(mine, ROW, COL);// 打印棋盘DisplayBoard(mine, ROW, COL);DisplayBoard(show, ROW, COL);// 玩家开始排雷do{printf("****************\n");printf("*** 1. 标记  ***\n");printf("*** 2. 排雷  ***\n");printf("*** 0. 退出  ***\n");printf("****************\n");printf("请选择:>");scanf("%d", &choose);if (1 == choose){printf("标记功能\n");}else if (2 == choose){printf("排雷功能\n");}else if (0 == choose){printf("退出游戏\n");break;}else{printf("输入错误,请重新输入\n");}} while (choose);}

实现效果如下图:
在这里插入图片描述

八、标记功能的菜单

  • 标记功能是玩家操作信息,传入show棋盘(数组)。
  • 玩家只在9×9棋盘中标记,所以使用 ROW 和 COL。
  • 标记功能应该有 1. 标记位置 2. 取消标记 3. 不标记了等三个功能。
  • 标记功能实现的同时对标记的雷进行计数,方便判断胜利。
//test.c 源文件 -- game函数
void game()
{int choose = 0;// 定义两个二维数组char mine[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };// 初始化棋盘InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');// 布置雷SetBoard(mine, ROW, COL);// 打印棋盘DisplayBoard(mine, ROW, COL);DisplayBoard(show, ROW, COL);// 玩家开始排雷do{printf("****************\n");printf("*** 1. 标记  ***\n");printf("*** 2. 排雷  ***\n");printf("*** 0. 退出  ***\n");printf("****************\n");printf("请选择:>");scanf("%d", &choose);if (1 == choose){printf("标记功能\n");SignBoard(show, mine, ROW, COL);}else if (2 == choose){printf("排雷功能\n");}else if (0 == choose){printf("退出游戏\n");break;}else{printf("输入错误,请重新输入\n");}} while (choose);}

//game.h 头文件
#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_COUNT 10// 初始化函数声明
void InitBoard(char board[ROWS][COLS], int rows, int cols, char sign);// 打印函数声明
void DisplayBoard(char board[ROWS][COLS], int row, int col);// 布置雷函数声明
void SetBoard(char board[ROWS][COLS], int row, int col);// 标记功能函数声明
int SignBoard(char show[ROWS][COLS],char mine[ROWS][COLS], int row, int col);

//game.c 源文件 ---SignBoard函数
// 标记功能函数定义
int SignBoard(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
{int choose = 0;do{printf("******************\n");printf("*** 1.标记位置 ***\n");printf("*** 2.取消标记 ***\n");printf("*** 0.不标记了 ***\n");printf("******************\n");printf("请选择:>");scanf("%d", &choose);if (1 == choose){printf("标记位置\n");}else if (2 == choose){printf("取消标记\n");}else if (0 == choose){printf("不标记了\n");break;}else{printf("输入错误,请重新输入\n");}} while (choose);
}

实现效果如下图:
在这里插入图片描述

九、标记功能菜单的实现

  • 标记位置需要玩家输入
  • 需要判断合法性
  • 需要判断是否被排查
  • 定义两个计数变量,若两变量相等,并且等于雷的个数时,判定排雷成功
  • 每次标记完成或取消标记后,打印棋盘
//game.c 源文件---SignBoard函数完整
// 标记功能函数定义
int SignBoard(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
{int x = 0;int y = 0;int choose = 0;static int sum = 0; // 定义标记的总数static int count = 0; // 定义标记的雷的总数do{printf("******************\n");printf("*** 1.标记位置 ***\n");printf("*** 2.取消标记 ***\n");printf("*** 0.不标记了 ***\n");printf("******************\n");printf("请选择:>");scanf("%d", &choose);if (1 == choose){printf("请输入标记坐标(空格隔开):>");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col) // 判断坐标合法性{if (show[x][y] == '*') // 判断坐标是否排查过{show[x][y] = '$';sum++; // 没标记一个加1if (mine[x][y] == '1'){count++; // 标记的位置如果是雷 加1}}else{printf("坐标已经被排查过了,请勿重复排查\n");}}else{printf("超出棋盘范围,请重新输入\n");}DisplayBoard(show, ROW, COL);}else if (2 == choose){printf("请输入标记坐标(空格隔开):>");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col) // 判断坐标合法性{if (show[x][y] == '$') // 判断坐标是否标记过{show[x][y] = '*';sum--; // 没标记一个加1if (mine[x][y] == '1'){count--; // 标记的位置如果是雷 加1}}else{printf("坐标未被标记,请重新选择\n");}}else{printf("超出棋盘范围,请重新输入\n");}DisplayBoard(show, ROW, COL);}else if (0 == choose){// 不标记直接跳转break;}else{printf("输入错误,请重新输入\n");}if (sum == count && count == EASY_COUNT){sum = 0;count = 0;return EASY_COUNT;}else{return 0;}} while (choose);
}
  • 把雷的个数设置为1进行测试
  • 主要过程是
    1. 先标记一个不是雷的位置。
    1. 再标记雷的位置。
    1. 最后取消标记不是雷的位置。
    1. 测试是否判定成功。
  • 效果如下图:
    在这里插入图片描述

总结

C语言从新建文件到游戏菜单,游戏函数,初始化棋盘,打印棋盘,布置雷函数,玩家排雷菜单,标记功能菜单及实现等的操作及实现效果。

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

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

相关文章

JavaScript-4.正则表达式、BOM

正则表达式 正则表达式包含在"/"&#xff0c;"/"中 开始与结束 ^ 字符串的开始 $ 字符串的结束 例&#xff1a; "^The"&#xff1a;表示所有以"The"开始的字符串&#xff08;"There"、"The cat"等&#x…

数据结构(八)——排序

八、排序 8.1 排序的基本概念 排序(Sort)&#xff0c;就是重新排列表中的元素&#xff0c;使表少的元素满足按关键字有序的过程。 输入∶n个记录R1,R2...., Rn&#xff0c;对应的关键字为k1, k2,... , kn 输出:输入序列的一个重排R1,R2....,Rn&#xff0c;使得有k1≤k2≤...≤…

综合大实验

题目&#xff1a; 1、R4为ISP&#xff0c;其上只配置IP地址&#xff1b;R4与其他所直连设备间均使用公有IP&#xff1b; 2、R3-R5、R6、R7为MGRE环境&#xff0c;R3为中心站点&#xff1b; 3、整个OSPF环境IP基于172.16.0.0/16划分&#xff1b;除了R12有两个环回&#xff0c;其…

VUE父组件向子组件传递值

创作灵感 最近在写一个项目时&#xff0c;遇到了这样的一个需求。我封装了一个组件&#xff0c;这个组件需要被以下两个地方使用&#xff0c;一个是搜索用户时用到&#xff0c;一个是修改用户信息时需要用到。其中&#xff0c;在搜索用户时&#xff0c;可以根据姓名或者账号进…

OllyDbg 快捷键及常用法

keywords: debug, ollydbg 快捷键 Ctrl --> C Shift --> S Alt --> M 功能快捷键设置/取消断点F2执行到光标所在行F4步过F8步进F7运行F9暂停F12回到应用层M-F9打开文件F3重新调试C-F2打开应用程序输入表C-n寻找表达式C-g打开断点窗口M-b切换断点状态空格添加备注…

[前端]NVM管理器安装、nodejs、npm、yarn配置

NVM管理器安装、nodejs、npm、yarn配置 NVM管理器安装 nvm(Node.js version manager) 是一个命令行应用&#xff0c;可以协助您快速地 更新、安装、使用、卸载 本机的全局 node.js 版本。 nvm下载地址&#xff1a;https://github.com/coreybutler/nvm-windows/releases 1.全部…

Unity面向切面编程

一直说面向AOP&#xff08;切面&#xff09;编程&#xff0c;好久直接专门扒出理论、代码学习过。最近因为某些原因&#x1f62d;还得再学学造火箭的技术。 废话不多说&#xff0c;啥是AOP呢&#xff1f;这里我就不班门弄斧了&#xff0c;网上资料一大堆&#xff0c;解释的肯定…

mybatis中<if>条件判断带数字的字符串失效问题

文章目录 一、项目背景二、真实错误原因说明三、解决方案3.1针对纯数字的字符串值场景3.2针对单个字符的字符串值场景 四、参考文献 一、项目背景 MySQL数据库使用Mybatis查询拼接select语句中进行<if>条件拼接的时候&#xff0c;发现带数字的或者带单个字母的字符串失效…

CPU资源控制

一、CPU资源控制定义 cgroups&#xff08;control groups&#xff09;是一个非常强大的linux内核工具&#xff0c;他不仅可以限制被namespace隔离起来的资源&#xff0c; 还可以为资源设置权重、计算使用量、操控进程启停等等。 所以cgroups&#xff08;control groups&#xf…

在ubuntu20上编译bcc时遇到:Could NOT find LibDebuginfod

参考&#xff1a;https://github.com/iovisor/bcc/issues/3601 环境 Ubuntu20.04 ARM64 问题 编译bcc时报下面的错误&#xff1a; -- Found BISON: /usr/bin/bison (found version "3.5.1") -- Found FLEX: /usr/bin/flex (found version "2.6.4") …

Netty学习——实战篇5 Netty 心跳监测/WebSocket长连接编程 备份

1 心跳监测 MyServer.java public class MyServer {public static void main(String[] args) {NioEventLoopGroup bossGroup new NioEventLoopGroup(1);NioEventLoopGroup workerGroup new NioEventLoopGroup();try {ServerBootstrap serverBootstrap new ServerBootstrap…

leetcode145--二叉树的后序遍历

1. 题意 求后序遍历 2. 题解 2.1 递归 class Solution { public:void addPost(TreeNode *root, vector<int> &res) {if ( nullptr root)return ;addPost(root->left, res);addPost(root->right, res);res.emplace_back( root->val );}vector<int>…

设计前后端系统以处理长时间运行的计算任务并提供缓存支持

后端设计 1. 任务队列 创建一个任务队列来存储提交的计算任务。 Component public class TaskQueue {private final Queue<CalculationTask> queue new LinkedList<>();public synchronized void addTask(CalculationTask task) {queue.add(task);}public sync…

C++ 全量枚举

在C中&#xff0c;全量枚举通常指的是为一个类型的所有可能值创建一个枚举。这样可以使代码更具可读性&#xff0c;特别是当你需要处理有限的、固定的值集合时。 下面是一个简单的例子&#xff0c;展示了如何定义和使用枚举&#xff1a; #include <iostream>// 定义枚举…

lvresize与lvextend扩容逻辑卷的区别

这两条命令都是用来扩展逻辑卷&#xff08;Logical Volume&#xff09;的命令&#xff0c;但是有一些区别&#xff1a; 1. lvresize命令&#xff1a; - lvresize命令是用来调整逻辑卷的大小的&#xff0c;可以缩小或扩大逻辑卷的大小。 - 在使用lvresize命令时&#xff0c;需…

20240425 每日一题:2739. 总行驶距离

题目简介 卡车有两个油箱。给你两个整数&#xff0c;mainTank 表示主油箱中的燃料&#xff08;以升为单位&#xff09;&#xff0c;additionalTank 表示副油箱中的燃料&#xff08;以升为单位&#xff09;。 该卡车每耗费 1 升燃料都可以行驶 10 km。每当主油箱使用了 5 升燃…

学习Docker笔记

在23号刚刚学完新版本的docker还想说回去继续学习老版本的springcloud课程里面的docker 结果一看黑马首页新版本课程出了&#xff0c;绷不住了。以下是我学习新版本docker的笔记&#xff0c;记录了我学习过程遇到的各种bug和解决&#xff0c;也参考了黑马老师的笔记&#xff1a…

TDengine高可用探讨

提到数据库&#xff0c;不可避免的要考虑高可用HA&#xff08;High Availability&#xff09;。但是很多人对高可用的理解并不是很透彻。 要搞清高可用需要回答以下几个问题&#xff1a; 什么是高可用&#xff1f;为什么需要高可用&#xff1f;高可用需要达到什么样的目标&am…

Unity射线实现碰撞检测(不需要rigbody组件)

使用physic.CapsulCast&#xff08;&#xff09;&#xff1b; 前面3个参数生成一个胶囊体&#xff0c; 向着发射方向&#xff0c;发射出一串的胶囊&#xff08;没有最大距离&#xff09; 有最大距离&#xff0c;可以节约性能开销。 physic.CapsulCast&#xff08;&#xff0…

记录一次使用springboot 3 用gradle脚本的踩坑记录

问题1 . 下载插件或者gradle以及gradle plus有问题 报错&#xff1a;Could not resolve org.springframework.boot:spring-boot-gradle-plugin:3.3.0-RC 解决方法&#xff1a;使用如下配置 settings.gradle的 pluginManagement下 repositories是插件的依赖或者插件的下载地址…