【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.rhkb.cn/news/302473.html

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

相关文章

基于ssm乐购游戏商城系统论文

摘 要 随着社会的发展&#xff0c;游戏品种越来越多&#xff0c;计算机的优势和普及使得乐购游戏商城系统的开发成为必需。乐购游戏商城系统主要是借助计算机&#xff0c;通过对信息进行管理。减少管理员的工作&#xff0c;同时也方便广大用户对个人所需信息的及时查询以及管理…

推荐一款自动化测试神器---Katalon Studio

Katalon Studio介绍 Katalon Studio 是一款在网页应用、移动和网页服务方面功能强大的自动化测试解决方案。基于 Selenium 和 Appium框架&#xff0c;Katalon Studio集成了这些框架在软件自动化方面的优点。这个工具支持不同层次的测试技能集。非程序员也可以快速上手一个自动…

maven profiles 配置

1.pom.xml中的文件配置 <profiles><profile> <!-- 开发/本地 默认激活 --><id>dev</id><activation><activeByDefault>true</activeByDefault></activation> <!--默认启用的是dev环境配置--><properties>&…

川川本人著作《Python3编程从零基础到实战》

在数字时代&#xff0c;Python已经成为了一种极为强大和灵活的编程语言&#xff0c;它的应用范围从网站开发到数据科学&#xff0c;再到机器学习和人工智能。无论你是一名编程新手还是希望深化已有技能的开发者&#xff0c;《Python3编程从零基础到实战》将成为你通往Python世界…

海外盲盒系统开发,盲盒出口成为企业新机遇

随着盲盒的兴起&#xff0c;国内消费市场形成了万物皆可盲盒的态势。并且&#xff0c;盲盒自带社交属性&#xff0c;也成为了年轻人的社交神器。 除了在国内&#xff0c;盲盒在海外也掀起了一股热潮&#xff0c;呈现出了爆发式增长形势&#xff0c;国内热门盲盒企业也出口到了…

DSP实时计算平台设计方案:912-基于6U CPCIe的双路光纤图像DSP实时计算平台

基于6U CPCIe的双路光纤图像DSP实时计算平台 一、设备概述 设备基于6U CPCIe架构&#xff0c;通过背板交换实现4片信号处理板卡的互联传输&#xff0c;每个信号处理板卡支持双TMS320C6678&#xff0c;支持2路光纤的图像处理&#xff0c;实现FPGA的预处理和备份工…

初识Python(注释、编码规范、关键字...)

&#x1f947;作者简介&#xff1a;CSDN内容合伙人、新星计划第三季Python赛道Top1 &#x1f525;本文已收录于Python系列专栏&#xff1a; 零基础学Python &#x1f4ac;订阅专栏后可私信博主进入Python学习交流群&#xff0c;进群可领取Python视频教程以及Python相关电子书合…

最新剧透前沿信息GPT-5或将今年发布

GPT2 很糟糕 &#xff0c;GPT3 很糟糕 &#xff0c;GPT4 可以 &#xff0c;但 GPT5 会很好。 PS:GPT2 很糟糕,3 很糟糕,4 可以,5 很可以。 如果想升级GPT4玩玩&#xff0c;地址 今年发布的具有推理功能的 GPT5不断发展&#xff0c;就像 iPhone 一样 Sam Altman 于 17 日&am…

【MATLAB高级编程】第二篇 | 元胞数组(cell)操作

【第二篇】元胞数组&#xff08;cell&#xff09;操作 1. 创建元胞数组cell2. 查看和修改cell内的元素值3. 高级操作: 可视化作图显示cell内的内容4. 把矩阵转换成单元数组5. 把单元数组转换成结构体变量 你好&#xff01; 欢迎进入 《MATLAB高级编程》 文章系列 &#xff0c;每…

Linux基础篇:Linux第三方软件仓库——可以让Linux变得有趣的软件仓库

Linux第三方软件仓库——可以让Linux变得有趣的软件仓库 一、epel源介绍 EPEL&#xff08;Extra Packages for Enterprise Linux&#xff09;源是一个由Fedora项目组维护的第三方软件仓库&#xff0c;为企业级Linux发行版&#xff08;如Red Hat Enterprise Linux&#xff08;…

IDEA中连接SQLserver数据库(DataGrip相同连接)

IDEA中连接SQLserver数据库(DataGrip相同连接) 1. 打开IDEA-database组件 2. 新建SQL server连接 3. 填写信息进行连接 填写连接名称&#xff0c;连接主机IP&#xff0c;端口&#xff0c;默认端口1433&#xff0c;数据库用户名密码&#xff0c;默认数据库用户名是sa 第一次连接…

(学习日记)2024.04.09:UCOSIII第三十七节:事件函数接口

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

Macos 部署自己的privateGpt(2024-0404)

Private Chatgpt 安装指引 https://docs.privategpt.dev/installation/getting-started/installation#base-requirements-to-run-privategpt 下载源码 git clone https://github.com/imartinez/privateGPT cd privateGPT安装软件 安装&#xff1a; Homebrew /bin/bash -c…

【Linux】磁盘与文件系统管理

目录 一、 磁盘结构 1. 数据结构 2. 物理结构 3. 硬盘的接口类型 二、 如何使用Linux中的磁盘 三、 文件系统 四、 磁盘分区 1. MBR分区 2. 分区的优缺点 3. 磁盘及分区的管理工具 五、格式化与挂载 1. 格式化 2. 挂载 六、实例演示 1. 演示分区格式化挂载 2. …

CICD流水线 发布应用到docker镜像仓库

准备工作 1.先注册免费的镜像仓库 复制链接: https://cr.console.aliyun.com/cn-beijing/instances 实施 1. 新建流水线&#xff0c;选择模板 2.添加流水线源&#xff0c;及是你的代码仓库, 选择对应分支. 3.代码检查以及单元测试&#xff0c;这个步骤可以不用动它. 4. …

【Android】App通信基础架构相关类源码解析

应用通信基础架构相关类源码解析 这里主要对Android App开发时&#xff0c;常用到的一些通信基础类进行一下源码的简单分析&#xff0c;包括&#xff1a; Handler&#xff1a;处理器&#xff0c;与某个Looper&#xff08;一个线程对应一个Looper&#xff09;进行关联。用于接…

基于SpringBoot+Vue的大学生体质测试管理系统(源码+文档+部署+讲解)

一.系统概述 大学生体质测试管理系统提供给用户一个简单方便体质测试管理信息&#xff0c;通过留言区互动更方便。本系统采用了B/S体系的结构&#xff0c;使用了java技术以及MYSQL作为后台数据库进行开发。系统主要分为系统管理员、教师和用户三个部分&#xff0c;系统管理员主…

四级作文模板——议论文——现象解释

议论文类型 现象解释 第一句 with the rapid development of society / economy / education / technology / culture / medical / service(任选) , it is of great necessity for youngster / students to improve our speaking ability.随着社会/经济/教育/科技/文化/医疗…

redis 集群模式(redis cluster)介绍

目录 一 redis cluster 相关定义 1&#xff0c; redis cluster 是什么 2&#xff0c;redis 集群的组成 3&#xff0c;集群的作用 4&#xff0c;集群架构图 二 Redis集群的数据分片 1&#xff0c;哈希槽是什么 2&#xff0c;哈希槽如何排布 3&#xff0c;Redis集…

Economic Census

Economic Census 经济普查&#xff0c;企业需提交文档&#xff08;1-6&#xff09;&#xff0c;或者汇总扫描提交