C语言之扫雷小游戏(完整代码版)

说起扫雷游戏,这应该是很多人童年的回忆吧,中小学电脑课最常玩的必有扫雷游戏,那么大家知道它是如何开发出来的吗,扫雷游戏背后的原理是什么呢?今天就让我们一探究竟!

扫雷游戏介绍

如下图,简单版本的扫雷游戏,就是在一个9*9的方格阵中,埋藏了10颗地雷,而玩家就是根据这个方阵的反馈,进行10颗地雷位置的排查。

 具体的游戏规则如下,玩家随机选择一个位置,如果选取位置不是雷,则显示数字。对于边缘的数字,则显示图中数字周围临近的5个方格中含有的地雷个数,例如下图红色圈起来的数字2,则说明红框之中必有两个地雷,即黑色×处。再看绿色框出来的数字2,它处于方格阵的中间位置,则看它周围临近的8个方格,含有2个地雷,也是黑色×处。

玩家可以根据数字的提示,筛选出10颗雷的位置,最终获得游戏胜利。反之,如果不幸选取到雷(即踩雷),则游戏失败。 

 扫雷游戏设计方案

1. 创建两个两个二维数组,一个作为埋雷地图,另一个作为玩家视角的排雷视图。
2. 设计一个9*9的扫雷游戏,但为了防止在统计坐标周围雷的个数的时候越界,设定数组的大小为11*11。
3. 数组均为字符数组.
4. 此次游戏实现同样采用多文件的形式设计。
               test.c             ——          测试游戏功能是否完好的代码
               game.c          ——          实现游戏逻辑的核心代码
               game.h          ——          游戏变量及函数的声明

扫雷游戏具体实现

(一)game.h文件

#pragma once#include<stdio.h>
#include<stdlib.h>
#include<time.h>#define ROW 9
#define COL 9#define ROWS 11
#define COLS 11#define EASY_MODEL 10void InitGame(char board[ROWS][COLS], int row, int col, char set);//初始化棋盘
void DisPlayBoard(char board[ROWS][COLS], int row, int col);//展示棋盘
void InitMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);//初始化地雷
void StartGame(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
int GetMine(char mine[ROWS][COLS], int row, int col);
//int SearchMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col,int x, int y,int count);
void SearchMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y, int* num);

(二)test.c文件

1.main函数

        在实现游戏功能的时候,一般都是在main函数中写出大体的框架,当遇到需要实现一些功能时,我们再去设计函数完成对应功能。
       这里设定游戏可以玩多局,即当游戏结束是不用退出可以继续选择是否进行下一局游戏,所以这里使用循环。同时,在第一局开始前询问玩家是否开始游戏,则采用do....while()循环。
        这里设置一个菜单来提醒玩家是否进行游戏。同时,玩家选择1时表示开始游戏,选择0时表示游戏结束,退出程序,选择其他时要提示玩家输入非法,并重新进行选择,所以这里需要一个switch选择语句。同时设置随机种子,方便每次开始扫雷游戏时,地雷都能随机位置。

int main()
{int input = 0;srand((unsigned int)(time(NULL)));//设置随机种子do {menu();scanf("%d", &input);switch (input){default:printf("输入错误嗷,请重新输入!\n");break;case 1:printf("扫雷游戏启动....\n");game();break;case 0:printf("扫雷游戏结束咯....\n");break;}} while (input);return 0;
}

2.menu函数

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

3.game函数

当玩家开始玩游戏时,game函数就是用来实现游戏整体框架,并调用其他实现具体功能的函数,具体代码如下。

void game()
{char mine[ROWS][COLS];	//埋雷地图char show[ROWS][COLS];	//玩家窗口InitGame(mine, ROW, COL, '0');InitGame(show, ROW, COL, '*');//初始化棋盘InitMine(mine, show, ROW, COL);//埋雷DisPlayBoard(show, ROW, COL);StartGame(mine, show, ROW, COL);}

其中mine数组时用来存储埋雷信息,show数组是用来存放排查出雷的信息。首先将mine数组的内容全都初始化为字符0,show数组将内容初始化为'*'表示此时位置还未被排雷。初始化棋盘后开始埋雷,将雷设置为1(具体后面会说)。mine数组的视图仅在程序开发时给程序员看,方便进行游戏调试。当正式游戏时,mine数组应该不给玩家看。

(三) game.c文件

1.InitGame函数(初始化棋盘)

此为初始化棋盘函数,由于需要确保函数的通用性,并且考虑到有一个mine视图和一个show视图需要同时初始化,而这两个视图初始化的内容也不同,所以设定一个set参数,每次调用函数的时候可以设置不同的初始化内容。

void InitGame(char board[ROWS][COLS], int row, int col, char set)
{for (int i = 0; i < ROWS; i++){for (int j = 0; j < COLS; j++){board[i][j] = set;}}
}

2.DisPlayBoard函数(显示棋盘 )

在实现DisPlayBoard函数时,不仅仅需要把数组内容给打印出来,还要考虑到玩家在玩游戏时输入地雷坐标方便,需要将整个方阵的横纵坐标给显示出来便于玩家判断。同时,还要提示玩家此局游戏中一共埋藏了多少颗雷。而雷的个数我们用一个全局变量EASY_COUNT来代替,这样也方便后续修改雷的个数。打印代码具体如下:

void DisPlayBoard(char board[ROWS][COLS], int row, int col)
{printf("------------------------------\n");printf("本场游戏,一共有%d颗地雷\n", EASY_MODEL);for (int i = 0; i <= col; i++){printf("%d ", i);//输出列号}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");}printf("\n");
}

3.InitMine函数(埋雷)

       本游戏设计10个雷,即EASY_MODEL的值设置为10。test.c的main函数中设计了随机种子,让雷的位置是随机的。使用rand函数来随机生成雷的位置的坐标,同时需要保证10颗雷的位置不能重复。因此采用while循环,如果成功布置雷就将count-1,直至count的值为0时结束循环。
        最后,我们将放置雷的位置上的信息改为字符'1',而非雷的位置信息依旧为字符'0'(即修改mine数组中对应位置的内容),修改为1是为了方便后续统计一个坐标周围的8个位置中有多少颗雷。需要注意的是:由于数组的下标是从0开始,而玩家所看到的方格的坐标是从1开始,因此我们在随机生成的雷的坐标中需要对x,y进行+1操作。代码如下:

void InitMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{//初始化雷区int mine_num = EASY_MODEL;while (mine_num){int x = rand() % row + 1;int y = rand() % col + 1;if (mine[x][y] == '0'){mine[x][y] = '1';mine_num--;}}
}

4.GetMine函数(统计方格四周雷的个数)

        统计一个坐标为(x,y)位置周围雷的个数,就是统计其周围8个位置的内容有多少个字符'1'。其余8个位置的坐标如下图:

由于字符1和字符0的差距就是1,所以我们统计八个位置的累计地雷数,就是减8个字符0的ASCII值即可,具体代码如下:

int GetMine(char mine[ROWS][COLS], int x, int y)
{return mine[x - 1][y] + mine[x + 1][y] + mine[x][y + 1] + mine[x][y - 1] +mine[x - 1][y - 1] + mine[x + 1][y + 1] + mine[x - 1][y + 1] + mine[x + 1][y - 1] - 8 * '0';
}

5.StartGame函数(开始扫雷游戏,排查雷)

         如果玩家未将所有雷排查完,则需要继续排查,因此必然需要一个循环,且当排查的个数=总数 - 雷的个数时,循环结束。
        每次需要判断玩家输入的雷坐标是否合法,不合法则需重新输入,合法才继续判断。需要判断两个条件。(1)当前位置是否为雷,是雷则直接结束游戏。(2)若当前位置非雷,但是排查过了,需要提示玩家并重新输入排雷位置。(3)只有当前位置非雷,并且排查过,才可以。需要注意的是:输入的非法坐标不计入排查的次数中。具体代码如下:(本代码实现了大片排雷)

void StartGame(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{int x, y;int num = EASY_MODEL;int count = 0;while (count < row * col - num){printf("请输入你要扫雷的坐标:>");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (mine[x][y] == '0' && show[x][y] != '*'){printf("刚才排除此地咯,请重新输入坐标!\n");}else if (mine[x][y] == '1'){printf("你被炸了,游戏结束!\n");break;}else{//count++;SearchMine(mine,show,row,col,x,y,&count);//count = SearchMine(mine, show, row, col, x, y, count);DisPlayBoard(show, 9, 9);}}else{printf("你输入的坐标不对嗷,请重新输入!\n");}}if (count == row * col - num) {printf("恭喜你获胜啦!\n");}
}

6.SearchMine函数(排查雷,实现大片扫雷)

使用GetMine函数获取周围8个坐标中雷的数量:

(1)如果是0,即周围8个坐标没有雷,那么就将中间设置为空白,在棋盘范围内,对该八个坐标再次进行SearchMine(递归);递归时排除已经是空格的坐标,防止陷入死循环。直至遇到一个坐标,其范围为内有雷。

(2)如果不是零,将该坐标设置为雷的数量(注意是字符类型)

void SearchMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y, int* num)
{if (x < 1 || x > row || y < 1 || y > col)	return;//坐标不合法直接不继续(*num)++;//num变量传的是排查雷个数变量的位置,*num是取出该变量位置上的具体值char tmp = GetMine(mine, x, y) + '0';//查看当前位置有几个地雷if (tmp == '0'){show[x][y] = ' ';for (int i = -1; i <= 1; i++){for (int j = -1; j <= 1; j++){int nx = x + i;int ny = y + j;if (show[nx][ny] == '*') {SearchMine(mine, show, row, col, nx, ny, num);}}}}else{show[x][y] = tmp;//return;}
}

实现效果:

完整代码

1.test.c

#define _CRT_SECURE_NO_WARNINGS 1#include "game.h"void menu()
{printf("**************************\n");printf("********  1. play  *******\n");printf("********  0. exit  *******\n");printf("**************************\n");
}void game()
{char mine[ROWS][COLS];	//埋雷地图char show[ROWS][COLS];	//玩家窗口InitGame(mine, ROW, COL, '0');InitGame(show, ROW, COL, '*');//初始化棋盘InitMine(mine, show, ROW, COL);//埋雷DisPlayBoard(mine, ROW, COL);DisPlayBoard(show, ROW, COL);StartGame(mine, show, ROW, COL);}int main()
{int input = 0;srand((unsigned int)(time(NULL)));do {menu();scanf("%d", &input);switch (input){default:printf("输入错误嗷,请重新输入!\n");break;case 1:printf("扫雷游戏启动....\n");game();break;case 0:printf("扫雷游戏结束咯....\n");break;}} while (input);return 0;
}

 2.geme.h

#pragma once#include<stdio.h>
#include<stdlib.h>
#include<time.h>#define ROW 9
#define COL 9#define ROWS 11
#define COLS 11#define EASY_MODEL 10void InitGame(char board[ROWS][COLS], int row, int col, char set);
void DisPlayBoard(char board[ROWS][COLS], int row, int col);
void InitMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
void StartGame(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
int GetMine(char mine[ROWS][COLS], int row, int col);
//int SearchMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col,int x, int y,int count);
void SearchMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y, int* num);

3.game.c

#define _CRT_SECURE_NO_WARNINGS 1#include "game.h"void InitGame(char board[ROWS][COLS], int row, int col, char set)
{for (int i = 0; i < ROWS; i++){for (int j = 0; j < COLS; j++){board[i][j] = set;}}
}void DisPlayBoard(char board[ROWS][COLS], int row, int col)
{printf("------------------------------\n");printf("本场游戏,一共有%d颗地雷\n", EASY_MODEL);for (int i = 0; i <= col; i++){printf("%d ", i);//输出列号}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");}printf("\n");
}void InitMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{//初始化雷区int mine_num = EASY_MODEL;while (mine_num){int x = rand() % row + 1;int y = rand() % col + 1;if (mine[x][y] == '0'){mine[x][y] = '1';//show[x][y] = '#';mine_num--;}}
}int GetMine(char mine[ROWS][COLS], int x, int y)
{return mine[x - 1][y] + mine[x + 1][y] + mine[x][y + 1] + mine[x][y - 1] +mine[x - 1][y - 1] + mine[x + 1][y + 1] + mine[x - 1][y + 1] + mine[x + 1][y - 1] - 8 * '0';
}void SearchMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y, int* num)
{if (x < 1 || x > row || y < 1 || y > col)	return;(*num)++;char tmp = GetMine(mine, x, y) + '0';if (tmp == '0'){show[x][y] = ' ';for (int i = -1; i <= 1; i++){for (int j = -1; j <= 1; j++){int nx = x + i;int ny = y + j;if (show[nx][ny] == '*') {SearchMine(mine, show, row, col, nx, ny, num);}}}}else{show[x][y] = tmp;//return;}
}//int SearchMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y, int count)
//{
//	if (x < 1 || x > row || y < 1 || y > col || show[x][y] != '*')
//		return count;
//
//	int tmp = GetMine(mine, x, y);
//	count++;
//	show[x][y] = tmp + '0';
//
//	if (tmp == 0)
//	{
//		for (int i = -1; i <= 1; i++)
//		{
//			for (int j = -1; j <= 1; j++)
//			{
//				int nx = x + i;
//				int ny = y + j;
//				if (nx >= 1 && nx <= row && ny >= 1 && ny <= col)
//				{
//					count = SearchMine(mine, show, row, col, nx, ny, count);
//				}
//			}
//		}
//	}
//
//	return count;
//}void StartGame(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{int x, y;int num = EASY_MODEL;int count = 0;//排查的雷个数while (count < row * col - num){printf("请输入你要扫雷的坐标:>");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (mine[x][y] == '0' && show[x][y] != '*'){printf("刚才排除此地咯,请重新输入坐标!\n");}else if (mine[x][y] == '1'){printf("你被炸了,游戏结束!\n");break;}else{//count++;SearchMine(mine,show,row,col,x,y,&count);//count = SearchMine(mine, show, row, col, x, y, count);DisPlayBoard(show, 9, 9);}}else{printf("你输入的坐标不对嗷,请重新输入!\n");}}if (count == row * col - num) {printf("恭喜你获胜啦!\n");}
}

总结:

程序开发整体上不是流程和逻辑还是比较容易实现的,难点在于实现大片扫雷的功能。大片扫雷功能主要是递归的实现,容易使程序崩溃,还需多多练习递归实现。附上程序运行部分效果图:

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

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

相关文章

【网络安全】漏洞案例:提升 Self-XSS 危害

未经许可,不得转载。 文章目录 Self-XSS-1Self-XSS-2Self-XSS-1 目标应用程序为某在线商店,在其注册页面的First Name字段中注入XSS Payload: 注册成功,但当我尝试登录我的帐户时,我得到了403 Forbidden,即无法登录我的帐户。 我很好奇为什么我无法登录我的帐户,所以我…

如何破解 AI 聊天机器人让它们吐露秘密!窥探 AI 系统指令的 10 种技巧

​ 有时&#xff0c;为了确保 AI 的安全性和透明性&#xff0c;用户需要自己动手&#xff0c;揭开系统指令的面纱。 如果人工智能现在已经成为生活中的事实&#xff0c;并影响着我们的福祉&#xff0c;人们理应知道它的运作原理。 对一些人来说&#xff0c;科幻电影中的经典…

新装ubuntu22.04必做两件事,不然可能没法用

一、换服务源 在全部里面找到软件和安装&#xff1b;打开后 在更多里面匹配一下最适合自己的软件源&#xff1b;这个过程比较漫长&#xff1b;要耐心等待 二、换软件安装中心 先执行&#xff1a; sudo apt upgrade 后执行&#xff1a; sudo apt install plasma-discover…

初级网络工程师之从入门到入狱(四)

本文是我在学习过程中记录学习的点点滴滴&#xff0c;目的是为了学完之后巩固一下顺便也和大家分享一下&#xff0c;日后忘记了也可以方便快速的复习。 网络工程师从入门到入狱 前言一、Wlan应用实战1.1、拓扑图详解1.2、LSW11.3、AC11.4、抓包1.5、Tunnel隧道模式解析1.6、AP、…

【AIF-C01认证】亚马逊云科技生成式 AI 认证正式上线啦

文章目录 一、AIF-C01简介二、考试概览三、考试知识点3.1 AI 和 ML 基础知识3.2 生成式人工智能基础3.3 基础模型的应用3.4 负责任 AI 准则3.5 AI 解决方案的安全性、合规性和监管 四、备考课程4.1 「备考训练营」 在线直播课4.2 「SkillBuilder」学习课程 五、常见问题六、参考…

Flutter技术学习

以下内容更适用于 不拘泥于教程学习&#xff0c;而是从简单项目入手的初学者。 在开始第一个项目之前&#xff0c;我们先要了解 两个概念。 Widget 和 属性 Widget 是用户界面的基本构建块&#xff0c;可以是任何 UI 元素。属性 是 widget 类中定义的变量&#xff0c;用于配…

【IEEE独立出版 | 厦门大学主办】第四届人工智能、机器人和通信国际会议(ICAIRC 2024)

【IEEE独立出版 | 厦门大学主办】 第四届人工智能、机器人和通信国际会议&#xff08;ICAIRC 2024&#xff09; 2024 4th International Conference on Artificial Intelligence, Robotics, and Communication 2024年12月27-29日 | 中国厦门 >>往届均已成功见刊检索…

深入理解Transformer的笔记记录(精简版本)NNLM → Word2Vec

文章的整体介绍顺序为&#xff1a; NNLM → Word2Vec → Seq2Seq → Seq2Seq with Attention → Transformer → Elmo → GPT → BERT 自然语言处理相关任务中要将自然语言交给机器学习中的算法来处理&#xff0c;通常需要将语言数学化&#xff0c;因为计算机机器只认数学符号…

Node.js管理工具NVM

nvm&#xff08;Node Version Manager&#xff09;是一个用于管理多个 Node.js 版本的工具。以下是 nvm 的使用方法和一些常见命令&#xff1a; 一、安装 nvm 下载 nvm&#xff1a; 地址&#xff1a;https://github.com/coreybutler/nvm-windows/releases访问 nvm 的 GitHub 仓…

稳字诀! 洞见 强者的社交格局:从不恋战——早读(逆天打工人爬取热门微信文章解读)

都是文字 引言Python 代码第一篇 洞见 强者的社交格局&#xff1a;从不恋战第二篇 稳字诀结尾 引言 今天很奇怪 一直都挺烦造的 好像有很多事情忙 但是就是忙着找不定 不能定下心来 主要还是在股市 其他方面应该没啥 计划表还是不够给力 没办法把心在约定住 稳字诀 勤燃香,奋…

GPT和BERT

GPT和BERT都是基于Trm的应用&#xff0c;可以理解为GPT是decoder的应用&#xff0c;BERT可以说是encoder的应用 GPT 如图&#xff0c;就是GPT的原理&#xff0c;GPT是做生成式的任务的&#xff0c;没有办法进行下游任务改造&#xff0c;训练也是针对生成式的任务进行训练 BE…

云开发 | 微信小程序云开发无法获取数据库数据

1.我在我的云数据库中创建了一个数据表&#xff08;即collection数据集&#xff09;userList,并且存入了两条用户信息数据 2. 想要通过按钮触发事件拿取数据库中数据并且打印在控制台时&#xff0c;获取数据失败&#xff0c;控制台无输出 3. 初始化 | 在开始使用数据库 API 进…

“医者仁术”再进化,AI让乳腺癌筛查迎难而上

世卫组织最新数据显示&#xff0c;我国肿瘤疾病仍然呈上升趋势&#xff0c;肿瘤防控形势依然比较严峻。尤其是像乳腺癌等发病率较高的疾病&#xff0c;早诊断和早治疗意义重大&#xff0c;能够有效降低病死率。 另一方面&#xff0c;中国地域广阔且发展不平衡&#xff0c;各地…

Qt-界面优化盒子模型(71)

目录 描述 相关属性 使用 描述 盒子模型 例如下面房子模型 • Content 矩形区域: 存放控件内容.⽐如包含的⽂本/图标等. • Border 矩形区域: 控件的边框. • Padding 矩形区域: 内边距. 边框和内容之间的距离. • Margin 矩形区域: 外边距. 边框到控件 geometry 返回的矩形…

Qt5.14.2 安装详细教程(图文版)

Qt 是一个跨平台的 C 应用程序开发框架&#xff0c;主要用于开发图形用户界面&#xff08;GUI&#xff09;程序&#xff0c;但也支持非 GUI 程序的开发。Qt 提供了丰富的功能库和工具&#xff0c;使开发者能够在不同平台上编写、编译和运行应用程序&#xff0c;而无需修改代码。…

【病毒分析】DevicData家族扩散:全球企业和机构成为勒索病毒头号攻击目标!

1.背景 本文聚焦于勒索病毒家族 DevicData 的最新变种&#xff0c;命名为 .DevicData-P a2a9e9c勒索病毒。自2023年1月首次被发现以来&#xff0c;DevicData 家族一直对多个高价值目标展开攻击&#xff0c;包括企业用户、医疗机构和教育机构。这些目标通常持有大量敏感数据&a…

初始爬虫13(js逆向)

为了解决网页端的动态加载&#xff0c;加密设置等&#xff0c;所以需要js逆向操作。 JavaScript逆向可以分为三大部分&#xff1a;寻找入口&#xff0c;调试分析和模拟执行。 1.chrome在爬虫中的作用 1.1preserve log的使用 默认情况下&#xff0c;页面发生跳转之后&#xf…

MySQL学习(五):数据类型与约束

MySQL学习&#xff08;五&#xff09;&#xff1a;数据类型与约束 文章目录 MySQL学习&#xff08;五&#xff09;&#xff1a;数据类型与约束1. 数据类型与属性1.1 所有的数据类型1.2 所有属性 2. 数据类型详解2.1 整型2.2 浮点类型2.3 定点数类型2.4 位类型2.5 日期与时间2.6…

Linux环境基础开发工具的使用

vim编辑器的基本操作: 在linux环境下输入vim 文件名就可以进入编辑模式. 上述四种模式必须退到命令模式才能进行下一个模式. 在编辑器中写完之后,输入ESC进入命令模式,然后再输入shift:进入低行模式并输入wq保存并退出. 在命令模式下的操作: 光标所在行:1.输入yy进行复制, 输…

ubuntu24 root用户修改密码 ubuntu新系统没有创建root用户

ubuntu 系统在虚拟机新建一个ubuntu24&#xff0c;但是在配置系统时候&#xff0c;并没有配置root密码&#xff0c;只是新增了一个自定义账号于密码&#xff0c;在创建好后&#xff0c;可以登录系统&#xff0c;设置root密码~ 1. ubuntu系统初始化后&#xff0c;登录自建账号 …