【C语言】扫雷小游戏

文章目录

  • 前言
  • 一、游戏玩法
  • 二、创建文件
    • test.c文件
      • menu()——打印菜单
      • game()——调用功能函数,游戏的实现
      • main()主函数
    • game.c文件
      • 初始化棋盘
      • 打印棋盘
      • 随机布置雷的位置
      • 统计周围雷的个数
      • 展开周围一片没有雷的区域
      • 计算已排查位置的个数
      • 排查雷(包括检测输赢):
    • game.h文件
      • 头文件
      • 棋盘的大小以及雷的个数
      • 主要功能函数的声明
  • 三、完整代码

前言

扫雷游戏与前文的三子棋小游戏有些类似,都是在二维数组的基础上进行的,但扫雷需要考虑的东西更多,也更难一点。今天我们就一起来学习如何实现扫雷小游戏,找回童年的回忆。(最后附有完整代码)

一、游戏玩法

没有玩过扫雷的小伙伴可以打开电脑自带的扫雷小游戏玩两把,很上头有没有,哈哈哈。

游戏规则:

1.首先,扫雷是在一个N*N的棋盘上进行的游戏,这些方格中随机暗藏着一定数量的雷。
2.揭开一个方格,如果没有地雷,则会显示周围8个方格的地雷的数量,如果周围8个方格都没有地雷,则会翻开一片区域。
3.如果揭开的是地雷,那么游戏失败。
4.可以选择标记未揭开的方格为雷,也可以取消标记,方便玩家记忆雷的位置

游戏胜利条件: 不触发地雷,找出所有不是雷的位置。

程序试玩:

初始菜单

在这里插入图片描述

上方是玩家棋盘,下方是布置好的雷盘

在这里插入图片描述

选择1排查雷,点开坐标(4,3)的方格,显示3,说明该坐标周围有3颗地雷

在这里插入图片描述
选择2,标记坐标(4,1)为雷,显示 " ! "

在这里插入图片描述

游戏失败!

在这里插入图片描述

二、创建文件

像三子棋一样,我们同样采用分模块的编程思想,创建三个文件来分别存放对应功能的代码。

test.c文件:主程序,功能的调用
game.c文件:扫雷游戏的具体功能实现
game.h文件:工程需要的头文件和函数声明以及宏定义

这样做的好处有:提高代码的可读性,方便后续调试,条理清晰,使主程序看起来简洁

test.c文件

menu()——打印菜单

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

game()——调用功能函数,游戏的实现

1.创建并初始化棋盘
2.随机布置雷的位置
3.打印棋盘信息
4.排查雷(包括判断游戏输赢)

这些是game.h中的宏定义信息,后面都会用到的,这里先声明一下

#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
#define count 10
void game()
{char mine[ROWS][COLS] = { 0 };//布置好的雷盘char show[ROWS][COLS] = { 0 };//排查出的雷盘init_board(mine, ROWS, COLS, '0');//mine棋盘全部初始化为0init_board(show, ROWS, COLS, '*');//show棋盘全部初始化为*set_mine(mine, ROW, COL);	//随机布置雷的位置print_board(show, ROW, COL);//打印玩家棋盘find_mine(mine, show, ROW, COL);//排查雷
}

之所以创建两个棋盘数组,是因为一个棋盘用来存放系统布置的雷的位置,一个棋盘用来存放玩家手中的棋盘信息。相当于一份是有答案的卷子,一份是玩家需要做的白卷。

创建的棋盘多两行两列是为了 方便后面排查周围8个格子时不会产生越界行为,不然要分情况讨论,很麻烦。显然,直接在创建数组时多开辟一圈更省事。

main()主函数

int main()
{srand((unsigned int)time(NULL));int input = 0;do{menu();printf("请选择->:");scanf("%d", &input);switch (input){case 0:printf("退出游戏\n");break;case 1:system("cls");game();break;default:printf("选择错误,请重新选择\n");break;}} while (input);return 0;
}

game.c文件

初始化棋盘

初始化棋盘为ch字符,可以自己定义初始化字符
我们将存放答案的那张棋盘全部初始化为字符0,后面布置有雷则置1
将玩家手中的游戏棋盘全部初始化为 * ,表示未揭开状态

void init_board(char board[ROWS][COLS], int rows, int cols, char ch)
{for (int i = 0; i < rows; i++){for (int j = 0; j < cols; j++){board[i][j] = ch;}}
}

打印棋盘

我们每写完一个功能模块,最好调用打印函数来验证是否正确

void print_board(char board[ROWS][COLS], int row, int col)
{printf("————扫雷————\n");printf("  ");for (int j = 1; j <= col; j++)printf("%d ", j);printf("\n");for (int i = 1; i <= row; i++){printf("%d ", i);for (int j = 1; j <= col; j++){printf("%c ", board[i][j]);}printf("\n");}
}

随机布置雷的位置

使用rand()产生随机数,但rand()每次只会产生固定的随机数,所以要在主函数中加入srand((unsigned int)time(NULL));将时间作为seed产生不断变化的随机数

rand()和srand()的使用需要包括头文件#include<stdlib.h>
time()函数的使用需要包括头文件#include<time.h>

void set_mine(char board[ROWS][COLS], int row, int col)
{int cnt = count;while (cnt){int x = rand() % row + 1; //得到1~row的随机数int y = rand() % col + 1; //得到1~col的随机数if (board[x][y] == '0'){board[x][y] = '1';//表示该位置布置了雷cnt--;}}
}

统计周围雷的个数

int get_mine_count(char mine[ROWS][COLS], int x, int y)
{int ret = 0;for (int i = x - 1; i <= x + 1; i++){for (int j = y - 1; j <= y + 1; j++){if(i != x || j != y)//周围8个位置,不包括自己ret = ret + mine[i][j] - '0';}}return ret;
}

展开周围一片没有雷的区域

如果该位置周围一个雷也没有,则继续打开周围的空白格子直到遇到周围有雷的格子。

void open_area(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)
{int cnt = get_mine_count(mine, x, y);if (cnt == 0){show[x][y] = '0';for (int i = x - 1; i <= x + 1; i++){for (int j = y - 1; j <= y + 1; j++){if (show[i][j] == '*' && x >= 1 && x <= row && y >= 1 && y <= col){open_area(mine, show, ROW, COL, i, j);//递归}}}}else//直到递归到周围8个位置存在雷的区域{show[x][y] = cnt + '0';}
}

计算已排查位置的个数

int get_win(char board[ROWS][COLS], int row, int col)
{int win = 0;for (int i = 1; i <= row; i++){for (int j = 1; j <= col; j++){if (board[i][j] != '*' && board[i][j] != '!')win++;}}return win;
}

排查雷(包括检测输赢):

首先根据选择,走向不同分支
选择1: 排查雷,首先判断坐标,若不在棋盘范围则重新输入,否则进入下一步判断;该位置若已被排查则重新输入坐标,没有排查过则进行排查,并显示周围雷的个数,同时计算已排查位置的个数
选择2: 标记雷,若该坐标已排查或已标记则重新输入,否则将该坐标置为" ! ",表示已被标记,并打印棋盘信息。
选择3: 取消标记,若该坐标已排查或未被标记则重新输入,否则将“ !”重新置为“ * ”。
其他选择则重新输入。

每选择一次,对win进行判断,若win等于棋盘上非雷个数的总和,则排雷成功,否则继续游戏直到游戏成功或失败。

void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{int x = 0;int y = 0;int win = 0;int input = 0;while (win < (row * col - count)){printf("请选择->:1.排查雷 2.标记雷 3.取消标记\n");scanf("%d", &input);if (input == 1){printf("请输入要排查的坐标->:");scanf("%d%d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (show[x][y] == '*' || show[x][y] == '!'){if (mine[x][y] == '1'){printf("很遗憾,你被炸死了!!!\n");print_board(mine, ROW, COL);break;}else{open_area(mine, show, ROW, COL, x, y);print_board(show, ROW, COL);win = get_win(show, ROW, COL);}}else{printf("该坐标已被排查,请重新输入\n");}}else{printf("坐标非法,请重新输入\n");}}else if (input == 2){printf("请输入要标记的坐标->:");scanf("%d %d", &x, &y);//判断坐标合法性if (x >= 1 && x <= row && y >= 1 && y <= col){if (show[x][y] == '*'){show[x][y] = '!';print_board(show, ROW, COL);}else if (show[x][y] == '!'){printf("该位置已被标记,请重新选择!\n");}else{printf("该位置已被排查,不能被标记,请重新选择!\n");}}else{printf("坐标不合法,请重新输入!\n");}}else if (input == 3){printf("请输入要取消标记的坐标->:");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (show[x][y] == '!'){show[x][y] = '*';print_board(show, ROW, COL);}else{printf("该位置不能取消标记,请重新选择!\n");}}else{printf("坐标不合法,请重新输入!\n");}}else{printf("输入有误,请重新输入!\n");}}if (win == row * col - count){printf("\n恭喜你,排雷成功!\n");printf("雷的分布情况:\n");print_board(mine, ROW, COL);}
}

game.h文件

头文件

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

棋盘的大小以及雷的个数

使用宏定义,方便随时修改棋盘规格以及雷的个数

#pragma once//防止头文件重复调用
#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
#define count 10

主要功能函数的声明

//初始化雷盘
void init_board(char board[ROWS][COLS], int row, int  col);
//打印雷盘
void print_board(char board[ROWS][COLS], int row, int col);
//布置雷
void set_mine(char board[ROWS][COLS], int row, int col);
//排查雷
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

三、完整代码

完整代码上传在gitee

点此跳转扫雷gitee源码

以上就是扫雷游戏的简单实现,细心的小伙伴发现错误欢迎指正。最后感谢您的观看和支持!

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

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

相关文章

3d模型太大怎么把物体显示小---模大狮模型网

在3D建模软件中&#xff0c;您可以通过缩放操作来改变物体的大小以便于显示和编辑。以下是在常见的3D建模软件(例如Blender、Maya、3ds Max等)中缩小物体的方法&#xff1a; Blender中缩小物体&#xff1a; 选择物体&#xff1a;首先&#xff0c;选择您想要缩小的物体。您可以…

科研学习|科研软件——SPSS统计作图教程:多组折线图(≥3个变量)

一、问题与数据 研究者想研究45-65岁不同性别人群中静坐时长和血胆固醇水平的关系,分别招募50名男性和女性(gender)询问其每天静坐时长(time,分钟),并检测其血液中胆固醇水平(cholesterol, mmol/L),部分数据如图1。研究者该如何绘图展示这两者间的关系呢? 二、问题…

秋招复习笔记——八股文部分:操作系统

笔试得刷算法题&#xff0c;那面试就离不开八股文&#xff0c;所以特地对着小林coding的图解八股文系列记一下笔记。 这一篇笔记是图解系统的内容。 硬件结构 CPU执行程序 计算机基本结构为 5 个部分&#xff0c;分别是运算器、控制器、存储器、输入设备、输出设备&#xf…

进制转换(0123456789ABCDEF)

题目 import java.util.Scanner;public class Main {public static void main(String[] args) {//将十进制数M转化为N进制数Scanner sc new Scanner(System.in);int m sc.nextInt();int n sc.nextInt();StringBuffer sb new StringBuffer();//1String s "0123456789…

坚持十天做完Python入门100题第一天

坚持十天做完Python入门100题第一天 第1题 变量更新第2题 变量命名规则第3题 类型错误第4题 序列索引第5题 序列切片第6题 负数切片第7题 Range函数 第1题 变量更新 解析&#xff1a;Python代码的读取和执行是由上至下的&#xff0c;变量n一开始被赋值为1&#xff0c;但被更新了…

每日OJ题_两个数组dp⑤_力扣10. 正则表达式匹配

目录 力扣10. 正则表达式匹配 解析代码 力扣10. 正则表达式匹配 10. 正则表达式匹配 难度 困难 给你一个字符串 s 和一个字符规律 p&#xff0c;请你来实现一个支持 . 和 * 的正则表达式匹配。 . 匹配任意单个字符* 匹配零个或多个前面的那一个元素 所谓匹配&#xff0c…

项目管理-Jiar Software

文章目录 前言Jira 中的关键词或术语功能应用场景优势 总结 前言 Jira Software 是由澳大利亚公司 Atlassian 开发的一款领先的敏捷项目管理工具&#xff0c;广泛应用于软件开发团队&#xff0c;以支持复杂的项目管理需求。以下是关于 Jira Software 的详细介绍&#xff0c;包…

安全左移是什么,如何为网络安全建设及运营带来更多可能性

长久以来&#xff0c;网络安全技术产品和市场需求都聚焦于在“右侧”防护&#xff0c;即在各种系统、业务已经投入使用的网络环境外围或边界&#xff0c;检测进出的流量、行为等是不是存在风险&#xff0c;并对其进行管控或调整。 然而事实上&#xff0c;安全风险不仅是“跑”…

Harmony鸿蒙南向驱动开发-GPIO

GPIO&#xff08;General-purpose input/output&#xff09;即通用型输入输出。通常&#xff0c;GPIO控制器通过分组的方式管理所有GPIO管脚&#xff0c;每组GPIO有一个或多个寄存器与之关联&#xff0c;通过读写寄存器完成对GPIO管脚的操作。 基本概念 GPIO又俗称为I/O口&am…

YOLOV8主干改进方法:DenseNet——最新提出DenseOne密集网络,打造高性能检测器(附改进代码)

原论文地址:原论文下载地址 优点:使得网络更容易训练,参数更小且计算更高效 摘要:最近的研究表明,如果卷积网络在靠近输入和接近输出的层之间包含更短的连接,那么卷积网络可以更深入、更准确、更有效地训练。在本文中,我们接受了这一观察结果,并引入了密集卷积网络(De…

MySQL-用户与权限管理:用户管理、权限管理、角色管理

用户与权限管理 用户与权限管理1.用户管理1.1 登录MySQL服务器1.2 创建用户1.3 修改用户1.4 删除用户1.5 设置当前用户密码1.6 修改其它用户密码 2. 权限管理2.1 权限列表2.2 授予权限的原则2.3 授予权限2.4 查看权限2.5 收回权限 访问控制连接核实阶段请求核实阶段 3. 角色管理…

论文中快速插入公式的方法

formula OCR 原地址&#xff1a;https://simpletex.cn/ai/latex_ocr&#xff08;防止超链接失效&#xff09; 找到参考文献中的公式&#xff0c;截图粘贴到网站&#xff0c;点击copy mathML&#xff0c;返回要插入公式的word文档&#xff0c;直接ctrlv&#xff0c;非常快捷和方…