扫雷游戏----C语言必写游戏之一

扫雷游戏

  • 背景
  • 起源与玩法
  • 基本实现思路
  • 涉及语言的主要内容
  • 具体实现步骤
    • 1.基本框架
    • 2.菜单页面的实现
    • 3.初始化棋盘
    • 4.在屏幕中显示棋盘
    • 5.布置好棋盘中的雷
    • 6.排查出棋盘中的雷
  • 扫雷游戏完整代码
  • 最后运行结果
  • 总结

背景

扫雷在科技历史上也扮演了相似的角色。这个基于数字的逻辑谜题最早来自20世纪六七十年代,当时Jerimac Ratliff推出的名为“Cube”的游戏已经非常受人欢迎。几十年后的1992年,扫雷游戏被加入了Windows3.1,这并不是为了展示Windows是游戏操作系统专家,而是为了训练用户的鼠标左右键操作能力,让这些动作变得非常自然,并培养鼠标移动的速度和准确性。

该介绍来自百度百科


起源与玩法

起源:
扫雷最原始的版本可以追溯到1973年一款名为“方块”的游戏。
不久,“方块”被改写成了游戏“Rlogic”。在“Rlogic”里,玩家的任务是作为美国海军陆战队队员,为指挥中心探出一条没有地雷的安全路线,如果路全被地雷堵死就算输。两年后,汤姆·安德森在“Rlogic”的基础上又编写出了游戏“地雷”,由此奠定了现代扫雷游戏的雏形。
1981年,微软公司的罗伯特·杜尔和卡特·约翰逊两位工程师在Windows3.1系统上加载了该游戏,扫雷游戏才正式在全世界推广开来。
玩法:
这款游戏的玩法是在一个9*9(初级),16*16(中级),16*30(高级),或自定义大小的方块矩阵中随机布置一定量的地雷(初级为10个,中级为40个,高级为99个)。由玩家逐个翻开方块,以找出所有地雷为最终游戏目标。如果玩家翻开的方块有地雷,则游戏结束

该介绍来自百度百科


比如上面这个扫雷盘,当点击那一个方块时,弹出来数字1,即表示在那个方块周围有一个雷,也就是上面标出的黑色矩形所在位置上有一个雷,只要排查出所有的雷,那么就取得了胜利


基本实现思路


涉及语言的主要内容

1.if、switch、for循环、while循环、do...while循环
2.宏定义、break的用法等
3.二维数组的创建、初始化、数组传参等
4.函数的声明、定义、调用等
5.布置雷需要生成随机数、rand()函数的使用等


具体实现步骤

1.基本框架

基本框架十分重要,如果连框架都搭建不起来,那么就更不用去谈论写一个完整的扫雷小游戏代码了。首先我们需要考虑大致实现的功能。
1.程序一运行就弹出菜单页面
2.可以对菜单上的内容进行选择
3.如果不小心选择失误,要能够实现再次选择
因此我们写出如下代码:

int main(void)
{int input = 0;do{//打印菜单Meau();printf("请选择菜单:");scanf("%d", &input);switch (input){case 1:printf("退出游戏!\n");break;case 2://进入游戏Game();break;case 3://游戏玩法介绍PlayWay();break;default:printf("选择有误,请重新输入\n");break;}} while (input != 1);return 0;
}

这样,我们的基本框架就已经搭建好了~


2.菜单页面的实现

在菜单的页面需要认真排版,因为菜单就像一家店的门面一样,如果排版不好,那么兴趣也就提不上来。

void Meau()
{printf("********************************\n");printf("********** 1.退出游戏  *********\n");printf("********** 2.开始游戏  *********\n");printf("********** 3.游戏玩法  *********\n");printf("********************************\n");
}

3.初始化棋盘

经过上面的步骤我们就要准备开始游戏了。现在游戏里还是一片空白,因此我们要有一个棋盘。对于棋盘,我们要实现的是,创建出一个空棋盘,然后再放置雷。
棋盘是一个二维的东西,因此我们采用二维数组。
为了增加用户的体验效果,我们还需要能够对棋盘的大小进行修改,此处采用宏定义的方式。为什么呢?
宏定义有两个优点:
(1) 方便程序的修改 使用简单宏定义可用宏代替一个在程序中经常使用的常量,这样在将该常量改变时,不用对整个程序进行修改,只修改宏定义的字符串即可,而且当常量比较长时,我们可以用较短的有意义的标识符来写程序,这样更方便一些。
(2) 提高程序的运行效率。

但是这时我们就会发现:我们很难确定边界的坐标周围有多少个‘雷’,因此我们实际的棋盘大小要更大一些,但呈现在玩家面前的只有中间那一块的棋盘。否则实际上会出现数组越界。

在实现思路里我说过我才用分块去写,因此声明和定义存放在头文件中

#pragma once//行
# define ROW 9
//列
# define COL 9# define ROWS ROW + 2# define COLS COL + 2

这里需要创建两个二维数组,一个用来存放雷的信息,另一个用来存放排查出雷的信息

 char mine[ROWS][COLS] = { 0 }; //存放布置好的雷的信息char show[ROWS][COLS] = { 0 }; //存放排查出的雷的信息

这个时候我们要让创建的棋盘内什么东西都不存放,或者存放一致的东西,方便以后在棋盘中布置雷,因此我们要将棋盘初始化。

//初始化棋盘
void Init_Board(char board[ROWS][COLS], int rows, int cols, char set )
{int i = 0; //循环变量int j = 0;for (i = 0; i < rows; ++i){for (j = 0; j < cols; ++j){board[i][j] = set; //将棋盘全部初始化为set这个传过来的参数}}
}

此处最后一个参数是方便自己来初始化棋盘。


4.在屏幕中显示棋盘

根据上面的初始化棋盘,我们知道呈现在玩家面前的只有中间那一块的棋盘。也就是只需要打印中间绿色的那一块棋盘。
虽然我们只是操作绿色部分9*9的那一块,但我们在传参的时候依旧传过去的是11*11的棋盘。因此在调用时打印棋盘函数时需要注意参数!

//调用
DisplayBoard(mine, ROW, COL); //实参
//定义
void DisplayBoard(char board[ROWS][COLS], int row, int col)//形参
{}

为了方便用户游戏,我们还需要将棋盘的列和行信息打印出来。于是得到下面的函数。

//显示棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{int i = 0;int j = 0;//实现对棋盘列数的信息提示for (i = 0; i <= 9; ++i){printf("%d ", i);}printf("\n");for (i = 1; i <= row; ++i) {printf("%d ", i); //实现对棋盘行数的信息提示for (j = 1; j <= col; ++j) //因为打印的是中间的棋盘,所以下标从1开始{printf("%c ", board[i][j]);}printf("\n"); //换行}printf("-------------------\n");//美化界面
}

5.布置好棋盘中的雷

初始化棋盘之后,棋盘中并没有雷,因此我们要开始在棋盘中布置雷。EASY_COUNT(雷的个数)在头文件中进行了宏定义。布置雷要涉及到随机数的生成。要使得电脑随机布置雷,这样才能够更好地实现扫雷游戏。在这里我们把字符‘1’当作雷。

//在棋盘中放置雷
void SetMine(char board[ROWS][COLS], int row, int col)
{int count = EASY_COUNT; //放置雷的个数while (count){//生成随机下标,行和列在范围之内int x = rand() % row + 1;int y = rand() % col + 1;if (board[x][y] != '1') //防止上一次这个位置已经布置雷{board[x][y] = '1';count--; //布置了雷才减少一次,因此要放在if里面}}
}

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');
}//查找雷
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{int count = GetMineCount(mine, x, y);show[x][y] = count + '0'; //让点出来的格子显示它的周围有几个雷DisplayBoard(show, ROW, COL);win++;}}else{printf("坐标非法,请重新输入\n");}}
}

扫雷游戏完整代码

头文件:

# 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 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);

game.c文件:

# include "game.h"void Meau()
{printf("********************************\n");printf("********** 1.退出游戏  *********\n");printf("********** 2.开始游戏  *********\n");printf("********** 3.游戏玩法  *********\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(show, ROW, COL);//布置雷SetMine(mine, ROW, COL);//排查出棋盘中的雷FindMine(mine, show, ROW, COL);
}int main(void)
{int input = 0;srand((unsigned)time(NULL)); //设置生成起点do{//打印菜单Meau();printf("请选择菜单:");scanf("%d", &input);switch (input){case 1:printf("退出游戏!\n");break;case 2://进入游戏Game();break;case 3://游戏玩法介绍PlayWay();break;default:printf("选择有误,请重新输入\n");break;}} while (input != 1);return 0;
}

test.c文件:

# include "game.h"//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set )
{int i = 0; //循环变量int j = 0;for (i = 0; i < rows; ++i){for (j = 0; j < cols; ++j){board[i][j] = set; //将棋盘全部初始化为set这个传过来的参数}}
}//显示棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{int i = 0;int j = 0;//实现对棋盘列数的信息提示for (i = 0; i <= 9; ++i){printf("%d ", i);}printf("\n");for (i = 1; i <= row; ++i) {printf("%d ", i); //实现对棋盘行数的信息提示for (j = 1; j <= col; ++j) //因为打印的是中间的棋盘,所以下标从1开始{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){//生成随机下标,行和列在范围之内int x = rand() % row + 1;int y = rand() % col + 1;if (board[x][y] != '1') //防止上一次这个位置已经布置雷{board[x][y] = '1';count--; //布置了雷才减少一次,因此要放在if里面}}
}//统计查找时方块周围雷的个数
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{int count = GetMineCount(mine, x, y);show[x][y] = count + '0'; //让点出来的格子显示它的周围有几个雷DisplayBoard(show, ROW, COL);win++;}}else{printf("坐标非法,请重新输入\n");}}
}

最后运行结果

这里为了方便演示结果,我在棋盘中放置了40个雷,同志们修改雷的个数请随意就好。
这是选择开始游戏的运行结果:

这里选择选项3的运行结果:

总结

虽然是一个很简单的游戏,但是却能够很巧妙地包含了C语言所涉及的内容。所有想要步入编程之路的小伙伴们,都值得一试!

小心踩雷!手把手教你制作扫雷游戏简单版本相关推荐

  1. PWA入门:手把手教你制作一个PWA应用

    摘要: PWA图文教程 原文:PWA入门:手把手教你制作一个PWA应用 作者:MudOnTire Fundebug经授权转载,版权归原作者所有. 简介 Web前端的同学是否想过学习app开发,以弥补自 ...

  2. 【对讲机的那点事】手把手教你制作馈线焊接M头

    在无线电车载台,中继台的应用中,馈线的好坏直接影响电波能量的传输,但是,馈线两端连接机器和天线的接头,通常是需要我们自己焊接制作的. 今天小编就带你手把手教你手把手教你制作馈线焊接M头: 在HF频段和 ...

  3. 手把手教你制作AppPreview视频并上传到appStore进行审核

    手把手教你制作AppPreview视频并上传到appStore进行审核 注意,你需要使用iMovie才能够制作AppPreview视频文件,用QuickTime录制的无效! 最终效果 1. 新建一个事 ...

  4. 最新免费自建APP平台哪个好?手把手教你制作APP

    大型二手交易网站咸鱼近日发布<90后分享经济消费报告>,报告显示:16-27岁的年轻人用户占比已达55%,90后已成为分享经济的绝对主力:基于地理位置或兴趣同好形成的社区"鱼塘& ...

  5. 手把手教你制作手机底部导航栏,领导看完都说好

    手把手教你制作手机底部导航栏,领导看完都说好

  6. Android反编译:手把手教你制作高德地图车机共存版

    Android反编译:手把手教你制作高德地图车机共存版 前言 前期准备 反编译流程 反编译获取有效信息 修改关键信息 修改包名 修改其它配置 生成APK 重新打包成apk 重新签名 绕过校验机制 定位 ...

  7. 猜字小游戏java方法体,手把手教你猜字小游戏,

    手把手教你猜字小游戏, package test07; import java.util.Scanner; //猜字符游戏 public class Guessing { //主方法 public s ...

  8. 天线巴伦制作和原理_【火腿DIY】巴伦知识图集|手把手教您制作1:1短波巴伦

    洛阳市无线电运动协会 CQ<现代通讯>杂志官网 黑暗森林的博客 什么是巴伦?短波用巴伦的作用是什么? 巴伦(英文:Balun)是平衡Balanced和不平衡Unbalanced转换器的英文 ...

  9. 使用Tableau制作扫雷游戏和三维地图

    一种利用低代码可视化工具处理复杂逻辑的有益尝试. 可视化作品的复杂度无外乎两种: 模型处理层的复杂度 和 可视化设计层的复杂度 模型处理层的复杂度 当计算逻辑异常复杂,无法直接通过线性计算获取计算结果 ...

最新文章

  1. 【我们都爱Paul Hegarty】斯坦福IOS8公开课个人笔记20 Multiple MVCs 多MVC模式、NavigationController导航控制器...
  2. python压缩包怎么安装-python – 如果安装的模块在zip文件的顶层添...
  3. JMS Java消息服务(Java Message Service)
  4. datagrid里面某一行双击打开代码
  5. svn里ignore不需要提交的用户文档
  6. 应用程序创建自己的奔溃转储(crash dump)文件
  7. Codeforces Round #285 (Div. 2) D. Misha and Permutations Summation 康托展开 + 线段树
  8. oracle 数据执行计划,Oracle 常见的执行计划步骤(explain结果的Description数据参考)...
  9. 说一说阿里云弹性公网IP那些事
  10. 收文处理和发文处理的环节_集气罩的设计是气体净化、废气处理系统设计的重要环节...
  11. 区块链在数据流通中的应用
  12. ShardingSphere源码解析 初步准备
  13. sqlserver CASE WHEN语句示例
  14. Google Code Review代码审查标准
  15. LabVIEW基于Kvaser USBcan的UDS烧录Hex文件
  16. Excel提示:您的组织策略阻止我们为您完成此操作
  17. python转义是什么意思_什么是python转义字符?看看人士如何理解它.
  18. c++实现种子填充算法与扫描线算法
  19. 【小沐学qt】生成二维码
  20. 为什么独热编码会引起维度诅咒,以及避免他的几个办法

热门文章

  1. 亚马逊云计算机视觉服务,亚马逊云科技宣布Amazon Lookout for Vision正式可用
  2. linux查询redis过期得到-2,Redis数据过期策略探究
  3. 为什么那么多企业选择了游戏盾?
  4. Python一些小例子的代码
  5. 图像中Alpha通道
  6. 数字新局面之下,网易数帆有何新思考?
  7. [学习计划]QSC Q-SYS Level 1 音频处理器
  8. arduino笔记34:nRF24l01模块使用 通信地址 数据通道 校验码 PID
  9. 服务器如何判断客户端非正常掉线-心跳连接
  10. 从零开始的 Rust 语言 blas 库之预备篇(1)—— blas 基础介绍