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

news/2024/5/19 0:56:46

文章目录

  • 前言
  • 一、排雷函数菜单
  • 二、排雷函数菜单的实现
  • 三、拓展棋盘功能
  • 四、源码
    • 1. test.c源文件
    • 2. game.h头文件
    • 3. game.c源文件
  • 总结


前言

C语言实现扫雷游戏的排雷菜单,以及功能的实现,拓展棋盘功能,以及源码等。

上半部分的链接地址: C语言扫雷游戏完整实现(上)

一、排雷函数菜单

  • 排雷函数菜单就只有1.排雷 和 2. 退出两个选择。
//test.c 源文件
void game()
{int choose = 0;int count = 0;int sum = 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){count = SignBoard(show, mine, ROW, COL);if (count != 0){printf("恭喜你,排雷成功!!\n");break;}}else if (2 == choose){printf("排雷功能\n"); // 可以删除sum = FineBoard(show, mine, ROW, COL);}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 1// 初始化函数声明
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);// 排雷函数声明
int FineBoard(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col);

//game.c 源文件 -- FineBoard函数菜单部分
// 排雷函数声明
int FineBoard(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
{int goway = 0;do{printf("**************\n");printf("*** 1.排雷 ***\n");printf("*** 0.退出 ***\n");printf("**************\n");printf("请选择:>");scanf("%d", &goway);if (1 == goway){printf("排雷开始\n");}else if (0 == goway){printf("退出游戏\n");}else{printf("输入错误,请重新输入\n");}} while (goway);

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

二、排雷函数菜单的实现

  • 玩家需要输入坐标,若超出范围或不合法应该重新输入,所以要用循环
  • 若玩家选择的位置不是雷,则显示周围雷的个数。
//test.c 源文件-- game函数
void game()
{int choose = 0;int count = 0;int sum = 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){count = SignBoard(show, mine, ROW, COL);if (count != 0){printf("恭喜你,排雷成功!!\n");break;}}else if (2 == choose){printf("排雷功能\n");sum = FineBoard(show, mine, ROW, COL);if (-1 == sum){printf("恭喜你,排雷成功!!\n");DisplayBoard(mine, ROW, COL);break;}else if (404 == sum){printf("很遗憾,你被炸死了!\n");DisplayBoard(mine, ROW, COL);break;}}else if (0 == choose){printf("退出游戏\n");break;}else{printf("输入错误,请重新输入\n");}} while (choose);}

//game.c 源文件-- FindBoard函数和BoomCount函数
// 计算周围雷的个数函数
int BoomCount(char board[ROWS][COLS], int x, int y)
{int i = 0;int sum = 0;for (i = -1; i <= 1; i++){int j = 0;for (j = -1; j <= 1; j++){if (i == j && 0 == j){continue;}sum = sum +  board[x+i][y+j] - '0';}}return sum;
}// 排雷函数声明
int FineBoard(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
{int goway = 0;int x = 0;int y = 0;static int number = 0;do{printf("**************\n");printf("*** 1.排雷 ***\n");printf("*** 0.取消 ***\n");printf("**************\n");printf("请选择:>");scanf("%d", &goway);if (1 == goway){while (1){printf("请输入排雷坐标(空格间隔):");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col) // 判断坐标合法性{if (show[x][y] == '*') // 判断是否被排查{if (mine[x][y] == '1'){return 404;}else{// 调用计算周围雷个数的函数int bct = BoomCount(mine, x, y);show[x][y] = bct + '0';DisplayBoard(show, ROW, COL);number++;break;}}else{printf("此位置已经排查完,请勿重复排查\n");break;}}else{printf("超出棋盘范围,请重新输入\n");}}if (number == row * col - EASY_COUNT){number = 0; // 游戏胜利,number重置为1return -1;}}else if (0 == goway){printf("取消排雷\n");}else{printf("输入错误,请重新输入\n");}} while (goway);}
  • 将雷的数量设置为79个即只有两个不是雷进行测试
  • 效果如下图:
    在这里插入图片描述

三、拓展棋盘功能

  • 此功能再排雷是判定选择的位置已经不是雷情况下执行。
  • 采用函数递归
    1. 如果这个位置周围没有雷,则这个位置可以为空格。
    1. 这个位置周围八个坐标没有排查过,排查过的位置直接跳过。
    1. 函数内部调用再次调用拓展函数,重新判断
    1. 如果满足继续排查
    1. 如果周围有雷,则停止排查,并将此位置显示周围雷的个数。

在这里插入图片描述

//game.c 源文件--ExtendBoard函数
// 拓展函数定义
void ExtendBoard(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y)
{int count = BoomCount(mine, x, y);if (count == 0){show[x][y] = ' ';int i = 0;for (i = -1; i <= 1; i++){int j = 0;for (j = -1; j <= 1; j++){if (i == j && 0 == j){continue;}if (show[x + i][y + j] != '*'){continue;}ExtendBoard(show, mine, x + i, y + j);}}}else{show[x][y] = count + '0';}}

这里只展示了一下拓展的效果。
拓展的效果如下图:
在这里插入图片描述

四、源码

1. test.c源文件

#include "game.h"
// 定义游戏菜单函数
void menu()
{printf("**********************\n");printf("*****   1. Play  *****\n");printf("*****   0. Quit  *****\n");printf("**********************\n");
}
void game()
{int choose = 0;int count = 0;int sum = 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){count = SignBoard(show, mine, ROW, COL);if (count != 0){printf("恭喜你,排雷成功!!\n");break;}}else if (2 == choose){//printf("排雷功能\n");sum = FineBoard(show, mine, ROW, COL);if (-1 == sum){printf("恭喜你,排雷成功!!\n");DisplayBoard(mine, ROW, COL);break;}else if (404 == sum){printf("很遗憾,你被炸死了!\n");DisplayBoard(mine, ROW, COL);break;}}else if (0 == choose){printf("退出游戏\n");break;}else{printf("输入错误,请重新输入\n");}} while (choose);}
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); // 输入为0退出游戏,同时停止循环return 0;
}

2. game.h头文件

#pragma once
#define  _CRT_SECURE_NO_WARNINGS#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);// 排雷函数声明
int FineBoard(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col);// 拓展函数声明
void ExtendBoard(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y);

3. game.c源文件

#pragma once#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;}}
}// 打印棋盘函数定义
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");
}// 布置雷函数定义
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--;}}
}// 标记功能函数定义
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){DisplayBoard(show, ROW, COL);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);
}// 计算周围雷的个数函数
int BoomCount(char board[ROWS][COLS], int x, int y)
{int i = 0;int sum = 0;for (i = -1; i <= 1; i++){int j = 0;for (j = -1; j <= 1; j++){if (i == j && 0 == j){continue;}sum = sum +  board[x+i][y+j] - '0';}}return sum;
}// 排雷函数声明
int FineBoard(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
{int goway = 0;int x = 0;int y = 0;static int number = 0;do{printf("**************\n");printf("*** 1.排雷 ***\n");printf("*** 0.取消 ***\n");printf("**************\n");printf("请选择:>");scanf("%d", &goway);if (1 == goway){DisplayBoard(show, ROW, COL);while (1){printf("请输入排雷坐标(空格间隔):");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col) // 判断坐标合法性{if (show[x][y] == '*') // 判断是否被排查{if (mine[x][y] == '1'){return 404;}else{number++;// 调用计算周围雷个数的函数int bct = BoomCount(mine, x, y);if (bct == 0){// 如果满足不是雷,并且周围没有雷的种种条件,则先调用拓展函数ExtendBoard(show, mine, x, y);DisplayBoard(show, ROW, COL);break;}else{show[x][y] = bct + '0';DisplayBoard(show, ROW, COL);break;}}}else{printf("此位置已经排查完,请勿重复排查\n");break;}}else{printf("超出棋盘范围,请重新输入\n");}}if (number == row * col - EASY_COUNT){number = 0;return -1;}}else if (0 == goway){printf("取消排雷\n");}else{printf("输入错误,请重新输入\n");}} while (goway);}// 拓展函数定义
void ExtendBoard(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y)
{int count = BoomCount(mine, x, y);if (count == 0){show[x][y] = ' ';int i = 0;for (i = -1; i <= 1; i++){int j = 0;for (j = -1; j <= 1; j++){if (i == j && 0 == j){continue;}if (show[x + i][y + j] != '*'){continue;}ExtendBoard(show, mine, x + i, y + j);}}}else{show[x][y] = count + '0';}}

总结

C语言实现扫雷游戏的排雷菜单,以及功能的实现,拓展棋盘功能,以及源码等。


http://www.mrgr.cn/p/07740010

相关文章

echart 常用属性

echart 常用属性 基础属性 title 左上角标题 legend 每一项的列表 xAxis: x轴上的数据 yAxis: y轴上的数据提示框 tooltip: {trigger: axis},demo地址:https://echarts.apache.org/v4/examples/zh/editor.html?c=line-stack 文字转动 斜着摆放 axisLabel.rotate: 30滚动条 da…

VScode远程连接虚拟机提示: 无法建立连接:XHR failed.问题解决方案

一问题描述 在vscode下载插件Remote-SSH远程连接虚拟机时提示无法建立连接 二.最大嫌疑原因&#xff1a; 我也是在网上找了许久&#xff0c;发现就是网络原因&#xff0c;具体不知&#xff0c;明明访问别的网页没问题&#xff0c;就是连不上&#xff0c;然后发现下载vscode的…

.Net添加了引用,仍然提示找不到命名空间

如图&#xff0c;MyStudy控制台程序引用了一个C#类库MyClassLibrary 代码里也能敲出来using MyClassLibrary&#xff0c;但是build时始终提示找不到命名空间MyClassLibrary 我检查了MyClassLibrary的Assembly&#xff0c;命名空间名称无误 又检查了MyStudy里的引用信息&#x…

three.js实现相机碰撞,相机不穿墙壁、物体

大家好,本文实现了相机碰撞检测,使相机不穿墙壁、物体,并给出了思路和代码,感谢大家~大家好,本文实现了相机碰撞检测,使相机不穿墙壁、物体,并给出了思路和代码,感谢大家~ 关键词:数字孪生、three.js、Web3D、WebGL、相机碰撞、游戏相机 我正在承接Web3D数字孪生项目,…

Windows服务器等保审核安全设置

1.开启账户锁定策略 进入Windows服务器,快捷键“WIN+R”打开运行窗口。输入“gpedit.msc”并点击确定,依次点击“计算机配置”>“Windows设置”>“安全设置”>“账户策略”>“账户锁定策略 示例: *多次登录锁定,可以设置次数多点 2、密码长度最小值建议设置为8…

20-vue组件传参(父传子,子传父)

父传子: 父组件向子组件传入一个参数,可以通过 props配置项,让组件接收外部传过来的数据 1)传递数据 这里需要注意,通过 age = "18"的方式,传递进去的数据是字符类型的,通过动态绑定 :age = "26" 的方式,传递进去的数据是整型类型<!--这里需要注…

状态模式和策略模式对比

状态模式和策略模式都是行为型设计模式&#xff0c;它们的主要目标都是将变化的行为封装起来&#xff0c;使得程序更加灵活和可维护。之所以将状态模式和策略模式进行比较&#xff0c;主要是因为两个设计模式的类图相似度较高。但是&#xff0c;从状态模式和策略模式的应用场景…

XV6源码阅读——进程地址空间

文章目录 前言页表实际情况 前言 一个本硕双非的小菜鸡&#xff0c;备战24年秋招。打算尝试6.S081&#xff0c;将它的Lab逐一实现&#xff0c;并记录期间心酸历程。 代码下载 官方网站&#xff1a;6.S081官方网站 页表 每个进程都有一个单独的页表&#xff0c;当xv6在进程之…

谁动了我的数据?如何防止数据偷偷溜走?

在数字化时代,数据成为了企业核心资产的重要组成部分。然而,随着数据量的不断增长和传输方式的多样化,数据泄露的风险也随之增加。那么,企业该如何保护自己的数据,确保数据安全呢?这里就为大家揭秘有效的数据监控策略。实施实时监控是保护数据的关键。通过安装专业的数据…

HTML+CSS热词设计

HTML+CSS的热词设计效果代码: `<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>a {display: block;width: 200px;h…

【漏洞复现】云时空社会化商业ERP系统slogin SQL注入漏洞

漏洞描述&#xff1a; 云时空社会化商业ERP系统slogin存在SQL注入漏洞&#xff0c;攻击者可以通过此漏洞获取数据库敏感信息。 搜索语法: Fofa-Query: app"云时空社会化商业ERP系统" 漏洞详情&#xff1a; 1.云时空社会化商业ERP系统。 2.漏洞POC&#xff1a; …

前端H5动态背景登录页面(下)

最近正好有点儿时间&#xff0c;把之前没整理完的前端动态背景登录页面给整理一下&#xff01;这是之前的连接前端H5动态背景登录页面&#xff08;上&#xff09;&#xff0c;这主要是两个登陆页面&#xff0c;一个彩色气泡&#xff0c;一个动态云朵&#xff0c;感兴趣的可以点…

使用Docker搭建Redis主从集群

文章目录 ☃️前言☃️搭建❄️❄️架构❄️❄️实例说明❄️❄️搭建第一个服务器上的两个实例❄️❄️搭建第二个服务器上的一个实例 ☃️开启主从❄️❄️改配置❄️❄️重启从节点 ☃️验证 欢迎来到 请回答1024 的博客 &#x1f353;&#x1f353;&#x1f353;欢迎来到 …

探索ChatGPT在提高人脸识别与软性生物识准确性的表现与可解释性

概述 从GPT-1到GPT-3&#xff0c;OpenAI的模型不断进步&#xff0c;推动了自然语言处理技术的发展。这些模型在处理语言任务方面展现出了强大的能力&#xff0c;包括文本生成、翻译、问答等。 然而&#xff0c;当涉及到面部识别和生物特征估计等任务时&#xff0c;这些基于文…

Mac 硬盘空间告急,你可以试试这几款免费清理工具 Mac第三方磁盘管理工具 MacBook磁盘工具下载 cleanmymac和appcleaner哪个好

在选购 Mac 时&#xff0c;昂贵的增加自带存储空间成本&#xff0c;往往是让很多购买用户肉痛的选择&#xff0c;因此不少用户在预算有限的情况下&#xff0c;选择配置更倾向于选择更大的运行内存而非存储空间。 这也让 macOS 存储空间捉襟见肘成为不少 Mac 用户头疼的问题&am…

【STM32F4】STM32CUMX相关环境配置

一、环境配置 我们需要以下两个软件 &#xff08;一&#xff09;keil5 最正统&#xff0c;最经典的嵌入式MCU开发环境。 该环境的配置可以看看之前的文章 所需文件如下&#xff1a; 当时配置的是STC8H的环境&#xff0c;现在基于此&#xff0c;重新给STM32配置环境。能让STC…

重庆软航H5 PDF签章产品经nginx代理之后在浏览器中在线打开PDF盖章时提示:签章失败:网络错误 413 Request Entity Too Large的问题解决办法

问题现象:问题描述:在系统中集成了软航H5 PDF签章产品,软航H5 PDF签章产品的对应服务是通过nginx代理的,在奇安信浏览器中在线打开PDF点击产品的工具栏上的盖章按钮:选定印章之后,在PDF文档上选定盖章位置之后,提示:签章失败:网络错误。 最近在做这个软航H5 PDF电子签…

Java之oop(面向对象编程)

目录面向对象编程(OOP)一、面向过程与面向对象二、Java基本元素:类和对象三、对象的创建与使用1. 对象的使用2.内存解析3.匿名对象四、类的成员1. 属性1.1概念1.2分类2. 方法2.1 声明格式2.2 方法的重载2.3 可变形参的方法2.4 方法参数的值传递机制2.5 递归方法3. 构造器4.…

顺序栈的接口程序

顺序栈的接口程序 头文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h>创建顺序栈 // 指的是顺序栈中的元素的数据类型,用户可以根据需要进行修改 typedef int DataType_t; // 构造记录顺序栈SequenceStack各项参数(栈底地址+栈容量+栈顶元…

【八股】Java基础、集合、JVM

面向对象三大特性 1 封装&#xff1a; 将 方法 和 属性 写到同一个类中&#xff0c;并将属性 私有化&#xff0c;生成 get set方法&#xff0c;外部访问属性需要通过get和set方法,内部可以直接访问属性&#xff0c;这样的一个类我们认为它完成了封装。 2 继承&#xff1a; 子…