文章目录

  • 一.分析
  • 二.游戏代码结构
  • 2.1主程序
  • 2.1.1main()函数
  • 2.1.2menu()函数
  • 2.1.3game()函数
  • 2.2game.h
  • 2.3game.c
  • 2.3.1初始化地图Init_Map()
  • 2.3.2打印地图Print_map()
  • 2.3.3布置雷Set_Beng()
  • 2.3.4判断是否为雷BengBeng()
  • 2.3.5计算坐标周围雷的个数Count_Beng
  • 三.结尾

一.分析

扫雷我想大部分应该都玩过吧,游戏规则我在这里就不做解释了。

首先我们得需要两个二维数组来存放我们所需的内容,

第一个二维数组里存放的内容是让玩家看的见的内容:

像这样,我们把这些灰色的方格用 * 代替,为了让玩家知道要在这里输入坐标,然后输入坐标后,要返回一个信息:这个坐标周围有几个雷。我们第一个数组目前就存放这些东西。

第二个数组存放的信息就是雷的位置了,通过rand函数来随机存放我们需要的雷的个数

如果我们希望格子是7 * 7的,那我们必须让地图的大小变成9 * 9的。

这是因为,我们需要有一个检查玩家输入的这个坐标周围的信息,如果地图范围只有7 * 7的话,那是不是边缘的信息在检查的时候就越界了?这样的话我们直接往外扩大一圈,然后初始化成0是不是就解决了。
而且我们两个地图的大小必须相同,这样可以起到一个映射的效果,因为玩家在第一个地图输入的坐标,该位置也可以反映到第二个地图的位置上,然后通过检查第二个地图里该坐标周围的雷的个数,然后在显示出来。

只用红框里面这部分,外面不用。

放置雷的方法:

可以将第二个数组里的内容全部初始化成0,然后随机将某些位置的0变成1,这样是为了在判断一个坐标周围位置的雷的时候,可以把他们的坐标(每个坐标要减去‘0’)加起来返回。

二.游戏代码结构

2.1主程序

#include "game.h"void menu()
{printf("************************\n");printf("******   1.play   ******\n");printf("******   0.exit   ******\n");printf("************************\n");
}void game()
{char uvis[ROWS][COLS];//让玩家看不到的地图char vis[ROWS][COLS];//能让玩家看到的地图//初始化地图Init_Map(uvis, vis);//打印可看见的地图Print_map(vis);//打印不可看见的地图//Print_map(uvis);//布置雷Set_Beng(uvis);Print_map(uvis);while (1){//输入坐标并判断是否为雷int flag = 0;flag = BengBeng(vis, uvis);if (flag == -1){printf("很遗憾,你被炸死了\n");break;}else if (flag == 1){system("cls");Print_map(vis);Print_map(uvis);}elsebreak;}
}int main()
{int input = 0;srand((unsigned int)time(NULL));do{menu();printf("请输入->");scanf("%d", &input);switch (input){case 1:system("cls");game();break;case 0:break;default:printf("输入错误,请重新输入:\n");break;}} while (input);return 0;
}

为了更好的维护写的代码,我把和实现游戏有关的代码全部写到了game.c这个文件里。现在我们先分析这个文件里的代码。

2.1.1main()函数

int main()
{int input = 0;srand((unsigned int)time(NULL));do{menu();//菜单printf("请输入->");scanf("%d", &input);switch (input){case 1:system("cls");game();break;case 0:break;default:printf("输入错误,请重新输入:\n");break;}} while (input);return 0;
}

main函数最外面的框架是do…while循环。循环里面是一个switch的选择语句。
我们通过玩家输入0,1来操作,如果输入1,则开始游戏,如果输入0就是退出游戏,如果输入其它就提示输入错误,重新输入。

srand((unsigned int)time(NULL));这行代码是为了和后面的rand函数相关联,到时候在解释,现在可以先跳过不用看。

system(“cls”);这是一个清屏的代码,主要是为了清理掉上次玩的游戏显示的界面,让画面变得更简洁。

2.1.2menu()函数

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

就是一个菜单,打印出来是这个效果:

2.1.3game()函数

void game()
{//ROWS,COLS我会在game.h头文件处解释char uvis[ROWS][COLS];//让玩家看不到的地图char vis[ROWS][COLS];//能让玩家看到的地图//初始化地图Init_Map(uvis, vis);//打印可看见的地图Print_map(vis);//打印不可看见的地图//Print_map(uvis);//布置雷Set_Beng(uvis);Print_map(uvis);while (1){//输入坐标并判断是否为雷int flag = 0;flag = BengBeng(vis, uvis);if (flag == -1){printf("很遗憾,你被炸死了\n");break;}else if (flag == 1){system("cls");Print_map(vis);Print_map(uvis);}elsebreak;}
}

游戏实现的步骤都在这里面,但是每个函数如何实现的放在了game.c文件里面。

2.2game.h

在这里我先把.h头文件里的内容给大家展示一下,以防一会在介绍.c文件里函数时,有些东西大家不知道。

//这是一会需要用到的库函数
#include <stdlib.h>
#include <stdio.h>
#include <time.h>//对一些参数做的宏定义//ROW,COL分别是行和列,是你希望地图的大小
#define ROW    9
#define COL    9//这两个是实际需要的行和列,刚在说过了,需要大一圈
#define ROWS   ROW + 2
#define COLS   COL + 2//这是你希望设置的炸弹的个数
#define BENG   10//下面就是一会需要用到的函数//初始化地图
void Init_Map(char uvis[ROW][COLS], char vis[ROWS][COLS]);//打印地图
void Print_map(char map[ROWS][COLS]);//布置雷
void Set_Beng(char uvis[ROWS][COLS]);//判断是否为雷
int BengBeng(char vis[ROWS][COLS], char uvis[ROWS][COLS]);

2.3game.c

#include "game.h"//初始化地图
void Init_Map(char uvis[ROW][COLS], char vis[ROWS][COLS])
{//玩家看到的地图数组内容全部初始化成*//看不到的数组里初始化为空格int i = 0;int j = 0;for (i = 0; i < ROWS; i++){for (j = 0; j < COLS; j++){vis[i][j] = '*';uvis[i][j] = '0';}}
}//打印地图
void Print_map(char map[ROWS][COLS])
{int i = 0;int j = 0;//打印列号for (j = 0; j <= COL; j++)printf("%d ", j);printf("\n");for (i = 1; i <= ROW; i++){//打印行号printf("%d ", i);for (j = 1; j <= ROW; j++){printf("%c ", map[i][j]);//map对应的那两个数组大小都是11*11,这里只是把一个数组中间9*9的拿出来//用来存放玩家输入的信息,所以存放的信息都是从1开始。}printf("\n");}
}//布置雷
void Set_Beng(char uvis[ROWS][COLS])
{int amount = BENG;while (amount){char x = rand() % ROW + 1;char y = rand() % COL + 1;if (uvis[x][y] == '0'){uvis[x][y] = '1';amount--;}}
}int Count_Beng(int x, int y, char uvis[ROWS][COLS])
{//因为外边两圈全初始化成0了,行列数只是打印出来//并没有改变数组里的内容return uvis[x + 1][y] +uvis[x - 1][y] +uvis[x][y + 1] +uvis[x][y - 1] +uvis[x - 1][y - 1] +uvis[x - 1][y + 1] +uvis[x + 1][y + 1] +uvis[x + 1][y - 1] - 8 * '0';}//判断是否为雷
int BengBeng(char vis[ROWS][COLS], char uvis[ROWS][COLS])
{while(1){//玩家输入坐标printf("请输入坐标->");int x = 0;int y = 0;scanf("%d %d", &x, &y);int count = 0;int count1 = 0;if (x >= 1 && x <= ROW && y >= 1 && y <= COL){if(uvis[x][y] != '1'){vis[x][y] = Count_Beng(x, y, uvis) + '0';system("cls");Print_map(vis);Print_map(uvis);count1++;}else{return -1;}}else{printf("输入不合法\n");}if (count1 == ROW * COL - BENG){printf("很遗憾,你没被炸死\n");return 0;}return 1;}
}

2.3.1初始化地图Init_Map()

void Init_Map(char uvis[ROW][COLS], char vis[ROWS][COLS])
{//玩家看到的地图数组内容全部初始化成*//看不到的数组里初始化为空格int i = 0;int j = 0;for (i = 0; i < ROWS; i++){for (j = 0; j < COLS; j++){vis[i][j] = '*';uvis[i][j] = '0';}}
}

用两个for循环把二维数组都遍历一遍。

2.3.2打印地图Print_map()

先给你们看下地图的样子:

void Print_map(char map[ROWS][COLS])
{int i = 0;int j = 0;//打印列号for (j = 0; j <= COL; j++)printf("%d ", j);printf("\n");for (i = 1; i <= ROW; i++){//打印行号printf("%d ", i);for (j = 1; j <= ROW; j++){printf("%c ", map[i][j]);//map对应的那两个数组大小都是11*11,这里只是把一个数组中间9*9的拿出来//用来存放玩家输入的信息,所以存放的信息都是从1开始。}printf("\n");}
}

先要在第一行把列号打印出来,也就是i=0的位置上。
后面每一行在打印之前也就是每一行的j=0的位置上把每一行的行号打印出来。
剩下的位置就是数组里的元素的位置,但是记住我们是从坐标[1,1]开始打印的。就是把11 * 11其中9 * 9位置上的信息打印出来。玩家在输入坐标的时候也是从[1,1]-[ROW,COL]。
行,列坐标是直接打印出来的,不会影响我们外面那一圈的内容。

2.3.3布置雷Set_Beng()

void Set_Beng(char uvis[ROWS][COLS])
{int amount = BENG;while (amount){char x = rand() % ROW + 1;char y = rand() % COL + 1;if (uvis[x][y] == '0'){uvis[x][y] = '1';amount--;}}
}

这里的rand函数是和刚在main函数里的srand函数一起用的。
srand()括号里面的内容里可以随便写一个值,可以把它当成种子,如果没有就默认为1,rand()每次用的时候都会检查是否调用过srand()函数,如果有就会产生一个随机值。但是这个种子如果不变的话,rand函数产生的随机值就固定了,换句话说,他就第一次随机,以后的值和第一次的一样。
这样的话我们就必须让srand函数里面的种子也是个随机值/不同值。这样就麻烦了,这不是套娃吗?所以为了满足我们的需求,我们通过time()函数来当作种子。
time():获取当前日历时间作为time_t类型的值.
我们直接把时间当成种子带进去,时间可不是固定的每分每秒都在运行。这样就会让我们每秒产生的随机值都不一样

因为time函数的返回值是time_t类型的,而srand需要的类型是unsigned int类型的,所以我们在使用时要强制类型转换。
time函数的参数填NULL空指针就行。

但是这个随机值的取值返回太大,所有我们必须把它限制在我们想要的范围来作为炸弹的坐标,我们发现炸弹的坐标应该在1 ~ ROW,和1 ~ COL之间。而一个任意数%x,这个取值范围是0 ~ x-1.所以为了让炸弹的坐标在我们希望的范围中就给%之后的值+1.

再布置炸弹的前提下是必须这个位置上的内容是‘0’,因为我们初始化的时候就全设为’0’,这样防止重复布置雷。我们将布置成功后那个坐标的内容置成‘1’。然后没布置成功一个amount–。布置的个数是我们需要的数量就停下来。

2.3.4判断是否为雷BengBeng()

int BengBeng(char vis[ROWS][COLS], char uvis[ROWS][COLS])
{while(1){//玩家输入坐标printf("请输入坐标->");int x = 0;int y = 0;scanf("%d %d", &x, &y);int count = 0;int count1 = 0;if (x >= 1 && x <= ROW && y >= 1 && y <= COL){if(uvis[x][y] != '1'){vis[x][y] = Count_Beng(x, y, uvis) + '0';system("cls");Print_map(vis);//Print_map(uvis);count1++;}else{return -1;}}else{printf("输入不合法\n");}if (count1 == ROW * COL - BENG){printf("很遗憾,你没被炸死\n");return 0;}return 1;}
}

玩家每走一步,我们都判断一下结果。

首先判断的是玩家输入的坐标是否合法,只有合法了,才能真正的判断这个位置是否为雷,或者这个位置周围有多少雷。

如果这一个位置的坐标不是雷,我们就通过函数Count_Beng来计算这个位置周围有多少雷,然后记录并打印下来,让玩家知道。
如果这一个位置的坐标就是雷的话,之间返回-1

玩家每成功下好一步,变量count1就++,这样的话在最后判断count1是否等于ROW * COL - BENG。
ROW * COL - BENG是棋盘的所有坐标之和-炸弹的个数,也就是地图上玩家所有不是炸弹的坐标的个数,如果满了就返回0说明,游戏结束,玩家赢了。

如果既没有返回0,也没有返回-1,说明游戏还要继续,还没结束,这样我们就返回1,以供game()函数里判断。

用函数Count_Beng计算出来的结果要+‘0’。因为我们返回的是一个整型,而数组里存放的是一个字符,所以+‘0’,让数字变成字符,这样才能打印出来让玩家看到。

2.3.5计算坐标周围雷的个数Count_Beng

int Count_Beng(int x, int y, char uvis[ROWS][COLS])
{//因为外边两圈全初始化成0了,行列数只是打印出来//并没有改变数组里的内容return uvis[x + 1][y] +uvis[x - 1][y] +uvis[x][y + 1] +uvis[x][y - 1] +uvis[x - 1][y - 1] +uvis[x - 1][y + 1] +uvis[x + 1][y + 1] +uvis[x + 1][y - 1] - 8 * '0';
}

我们把该坐标周围8个位置的坐标- 8 * ‘0’加起来之间返回即可,因为我们当初布置雷的时候把雷的位置里的内容记成了’1’,如果减去’0’也就是数字1,周围有几个雷,就有几个1,全加起来就是雷的个数。

三.结尾

以上就是扫雷的全部内容了。源码在上面已经列出来了,需要的可以自取。但是为了看到自己布置雷的位置,所以把玩家不该看到的地图也打印出来了,你们如果不想要注释掉就行。

C语言低配版扫雷游戏相关推荐

  1. 【C语言】简易版扫雷游戏(play game)

    目录 扫雷游戏

  2. rust低配设置图片_西部题材生存玩法,Steam这款免费游戏疑似低配版大表哥2?...

    近些年来,"开放题材"不断发展,精品游戏接连出现,各自玩出了各自的花样.18年有<Rust>,主打废土生存,在发售之初就颇受好评:19年有<荒野大镖客2>主 ...

  3. 绝地求生低配版显示当前服务器,为什么我的绝地求生低配版一进去游戏页面显示错误再你的地区不可使用...

    满意答案 为什么你的绝地求生低配版游戏错误感情的真谛在于无求. 爱一个人并不是要从对方身上得到什幺利益, 你爱一个人, 愿 意对他好,因为你觉得很快乐. 这就是为什幺我们会批评这是个无情的时代, 因为 ...

  4. c语言小游戏 精简_C语言开发简易版扫雷小游戏

    C 语言开发简易版扫雷小游戏 本文给大家分享的是一个使用 C 语言开发的命令行下的简易版扫雷小游戏, 本身没有什么太 多的技术含量, 只不过是笔者的处女作, 所以还是推荐给大家, 希望对大家学习 C ...

  5. 低配版语言助手----chatgptAPI调用、文本转语音、MP3播放

    文章目录 摘要 代码流程 代码 遇到bug 演示视频 参考 摘要 使用 OpenAI 的 GPT-3.5 模型进行智能聊天,并使用返回的聊天回复文本生成语音,并播放该语音. 代码流程 具体来说,代码的 ...

  6. 一个低配版小恐龙游戏

    用过Chrome的同学应该玩耍过自带的那个小恐龙 无聊的时候刷上一下下倒也是一种消遣 (讲道理打到这个分我都快眼瞎了) 以下正经脸 所以呢我就用Construct 2做个真·低配版吧 既然是低配版那就 ...

  7. 利用java开发简易版扫雷游戏

    1.简介 学了几周的Java,闲来无事,写个乞丐版的扫雷,加强一下Java基础知识. 2.编写过程 编写这个游戏,一共经历了三个阶段,编写了三个版本的游戏代码. 第一版:完成了扫雷游戏的基本雏形,实现 ...

  8. java muki_基于canvas和web audio实现低配版MikuTap

    导言 最近发掘了一个特别happy的网页小游戏--MikuTap.打开之后沉迷了一下午,导致开发工作没做完差点就要删库跑路了,还好boss瞥了我一眼就没下文了.于是第二天我就继续沉迷,随着一阵抽搐,这 ...

  9. 绝地求生低配版显示当前服务器,绝地求生低配版介绍 绝地求生低配版怎么样...

    绝地求生低配版介绍 绝地求生低配版怎么样 2018-10-04 16:23:13来源:游戏下载编辑:野狐禅评论(0) <绝地求生>官方公布消息要发布针对东南亚地区的低配版本,这个版本怎么样 ...

最新文章

  1. 程序员该怎样放松?8个好网站推荐
  2. session_unset()和session_destroy()的区别
  3. html单击按钮时弹出输入框,点击按钮弹出模态框的一系列操作代码实例
  4. MongoDB 基础浅谈
  5. 润乾单查日期特别慢_SQL编写不合理导致历史日志查询特别慢
  6. 3,外键之表关联关系,修改表,复制表
  7. csdn上传图片发现:缺少图像源文件地址
  8. java证书验证失败_Java 跳过 HTTPS 请求过程中证书验证问题
  9. 2013北理机试题——中缀算术表达式对应二叉树的先序遍历
  10. java高级教程pdf_《Java高级编程实用教程》PDF 下载_IT教程网
  11. 安卓系统和安卓服务器地址,给安卓应用配置服务器地址
  12. 图标设计的意思是什么?资深UI设计师告诉你图标的含义!
  13. Linux的磁盘配额设置
  14. 人月神话之四 贯彻执行、为什么巴比伦塔会失败
  15. 密码学技术如何选型?终探量子计算通信的安全模型
  16. 【操作系统】多线程、生产者——消费者同步与互斥代码实现
  17. three.js 07-06 之 Sprite 一幅图片多个精灵
  18. java采用什么与什么相结合的产物,智能仪器是
  19. 什么是云手机?有免费的云手机吗?
  20. vue如何在filter中使用this

热门文章

  1. salesforce与微信集成(一)-- 如何配置微信和salesforce
  2. 基于Linux平台上的外文文献阅读软件—需求分析
  3. 使用Navicat远程连接oracle数据库
  4. TPC-H和TPC-DS
  5. 右侧追击(二)——券商行业
  6. 笔记本计算机屏幕亮度暗,笔记本屏幕暗,详细教您怎么解决
  7. linux mmc驱动框架,Linux mmc framework2:基本组件之mmc
  8. 认识Access中的MDE文件
  9. 苹果机型中最具经典的三款机型
  10. 类型多样的终结者游戏成套模型素材,速来收藏