数据结构课程设计------扫雷游戏(升级版,可展开)

本程序由团队中的一个人所写,本人看懂并写下此文章

题目:扫雷

3.1问题描述

扫雷游戏
[基本要求]
(1)完成棋盘的初始化并在标准显示器中显示
(2)通过输入行列值确定用户输入
(3)游戏进行给出提示信息
(4)给出游戏的测试程序。

3.2.算法设计与分析

3.2.1设计思路分析
首先定义一个二维数组的棋盘,用伪随机数在棋盘上生成地雷。通过从键盘上输入坐标,判断此位置是不是存在地雷,存在则游戏结束,不存在则展开棋盘。展开的周围显示出附近存在的地雷个数。依次类推,直到找出所有地雷。
3.2.2设计程序流程图(要求图文并茂)
在这里插入图片描述
首先进入菜单,选择开始游戏,生成棋盘与地雷,然后显示棋盘,用户输入相应的位置坐标,程序进行判断该位置是否为地雷,是的话游戏结束,不是的话则展开棋盘,继续输入并统计地雷个数,依次类推,直到地雷数统计完则游戏结束。
3.2.3数据结构定义

#define COUNT 10
#define ROW 9
#define CLO 9
#define ROWS 11
#define CLOS 11
char arr[ROW][CLO] = { 0 };    //显示棋盘
char arrs[ROWS][CLOS] = { 0 };   //真正操作的棋盘

3.2.4算法的时间复杂度分析
棋盘初始化模块的算法,对定义好的二维数组元素进行定义,时间复杂度为O(1)。
模拟棋盘初始化算法,对定义好的二维数组元素进行定义,时间复杂度为O(1)。
打印棋盘的算法,通过依次遍历二维数组打印数据元素,时间复杂度为O(n)。
地雷生成算法,通过伪随机数在棋盘上生成地雷,时间复杂度为O(n)。
判断是否为地雷算法,通过数据匹配的方式进行判断,时间复杂度为O(1)。
统计地雷个数的算法,通过数据匹配的方式进行统计,时间复杂度为O(n)。
棋盘展开算法,每次输入坐标展开棋盘,时间复杂度为O(1)。

3.3源程序清单(带注释)

Game.h
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#define COUNT 10
#define ROW 9
#define CLO 9
#define ROWS 11
#define CLOS 11
void printbroad(char arr[ROW][CLO], int row, int clo);
void arr_init(char arr[ROW][CLO], int row, int clo);
void menu();
void arrs_randinit(char arrs[ROWS][CLOS], int row, int clo);     //生成随机雷
void arrs_init(char arrs[ROWS][CLOS], int row, int clo);
void print(char arrs[ROWS][CLOS], int row, int clo);
void sweep(char arrs[ROWS][CLOS], char arr[ROW][CLO], int row, int clo);  //扫雷
int is_thunder(char arrs[ROWS][CLOS], char arr[ROW][CLO], int row, int clo);
int count(char arrs[ROWS][CLOS], int row, int clo);         //计算周围雷的数目
void movefirst(char arrs[ROWS][CLOS], int row, int clo);
void open(char arrs[ROWS][CLOS], char arr[ROW][CLO], int i, int j);
Game.c
#pragma warning(disable:4996)
#include"game.h"
int num = ROW*CLO - COUNT;
void menu()
{printf("****************************************\n");printf("***************  1.play   **************\n");printf("***************  0.exit   **************\n");printf("****************************************\n");}
//打印扫雷棋盘
void printbroad(char arr[ROW][CLO], int row, int clo)
{int i = 0;int j = 0;printf("   ");//打印扫雷棋盘的横坐标for (i = 1; i <= row; i++){printf("%d ", i );}printf("\n");for (i = 1; i <= row; i++){printf("--");}printf("--");printf("\n");for (i = 0; i < row; i++){//打印扫雷棋盘的纵坐标printf("%d| ", i+1);for (j = 0; j < clo; j++){printf("%c ", arr[i][j]);}printf("\n");}printf("\n");
}void arr_init(char arr[ROW][CLO], int row, int clo)
{//这个函数的功能是将该数组所有置*memset(&arr[0][0], '*', row*clo*sizeof(arr[0][0]));
}
void arrs_init(char arrs[ROWS][CLOS], int row, int clo)
{memset(&arrs[0][0], '0', row*clo*sizeof(arrs[0][0]));
}//生成随机地雷,1代表地雷,0代表没有地雷;
void arrs_randinit(char arrs[ROWS][CLOS], int row, int clo)
{int count = COUNT;int i = 0;int j = 0;do{//生成随机横纵坐标i = rand() % 9+1;  //生成1~9的横坐标j = rand() % 9+1;  //生成1~9的纵坐标if (arrs[i][j] != '1') //如果此处有地雷,则继续循环{arrs[i][j] = '1';count--;}} while (count);}
void print(char arrs[ROWS][CLOS], int row, int clo)
{int i = 0;int j = 0;printf("   ");for (i = 1; i < row - 1; i++){printf("%d ", i);}printf("\n");for (i = 1; i < row - 1; i++){printf("--");}printf("--");printf("\n");printf("1|");for (i = 1; i < row-1; i++){printf(" ");for (j = 1; j < clo-1; j++){printf("%c ", arrs[i][j]);}printf("\n");if (i == 9){continue;}printf("%d|", i+1);}//int i = 0;//int j = 0;//printf("   ");打印扫雷棋盘的横坐标//for (i = 1; i <= row-2; i++)//{//	printf("%d ", i);//}//printf("\n");//for (i = 1; i <= row-2; i++)//{//	printf("--");//}//printf("--");//printf("\n");//for (i = 0; i < row-2; i++)//{//	//打印扫雷棋盘的纵坐标//	printf("%d| ", i + 1);//	for (j = 0; j < clo-2; j++)//	{//		printf("%c ", arrs[i][j]);//	}//	printf("\n");//}//printf("\n");
}int is_thunder(char arrs[ROWS][CLOS],char arr[ROW][CLO], int row, int clo)
{if (arrs[row][clo] == '1'){return 0;}else{return 1;}
}//计算周围一圈(8个数)有多少个地雷
int count(char arrs[ROWS][CLOS], int row, int clo)
{int count = 0;return ((arrs[row - 1][clo - 1] +arrs[row - 1][clo] +arrs[row - 1][clo + 1] +arrs[row][clo - 1] +arrs[row][clo + 1] +arrs[row + 1][clo - 1] +arrs[row + 1][clo] +arrs[row + 1][clo + 1])-'0'*8);}
//当玩家第一次就点到地雷时,得把地雷移走
void movefirst(char arrs[ROWS][CLOS], int row, int clo)
{int x = 0;int y = 0;while (1){x = rand() % 9 + 1;y = rand() % 9 + 1;if (arrs[x][y] != '1'){arrs[x][y] = '1';break;}}arrs[row][clo] = '0';
}void sweep(char arrs[ROWS][CLOS], char arr[ROW][CLO], int row, int clo)
{//判断是否为第一次扫雷的标志位int first = 0;int x = 0;int y = 0;int flag = 1;int ret = 0;while (flag){printf("请输入坐标>\n");scanf("%d%d", &x, &y);//如果是雷,则返回0,否则返回1;ret = is_thunder(arrs, arr, x, y);if (x >= 1 && x <= 9 && y >= 1 && y <= 9){first++;switch (ret){case 1:if (count(arrs, x, y) == 0){open(arrs, arr, x - 1, y - 1);}else {arr[x - 1][y - 1] = count(arrs, x, y) + '0';num--;}printbroad(arr, ROW, CLO);//printf("\n%d\n", num);break;case 0://如果第一次就碰到了雷,就将雷移走,提升游戏体验if (first == 1){movefirst(arrs, x, y);if (count(arrs, x, y) == 0){open(arrs, arr, x - 1, y - 1);}else {arr[x-1][y-1] = count(arrs, x, y) + '0';num--;}printbroad(arr, ROW, CLO);break;}printf("你被炸掉了\nGAMEOVER!!!!!!!!\n");print(arrs, ROWS, CLOS);flag = 0;break;}if (0 == num){printf("游戏结束,玩家赢!!!\n");break;}}else{printf("输入错误,请重新输入:\n");}}
}
int right(int i, int j)
{if (  (i + 1)>=1 && (i + 1)<=9 && (j + 1)>=1 &&(j + 1)<= 9  ){return 1;}return 0;
}void open(char arrs[ROWS][CLOS], char arr[ROW][CLO], int i, int j)
{//如果当前位置没有地雷,而且当前位置在棋盘上没有被显示,则显示出周围一圈雷的数量;if (arrs[i+1][j+1] == '0' && arr[i][j] == '*'&&right(i,j)){arr[i][j] = count(arrs, i+1, j+1) + '0';num--;}//左一位置if (arrs[i + 1][j] == '0' && arr[i][j - 1] == '*'&&right(i, j-1)){arr[i][j-1] = count(arrs, i+1, j) + '0';num--;if (count(arrs, i+1, j) == 0){open(arrs, arr, i, j-1);}}//右一位置if (arrs[i + 1][j + 2] == '0' && arr[i][j + 1] == '*'&&right(i, j+1)){arr[i][j + 1] = count(arrs, i+1, j + 2) + '0';num--;if (count(arrs, i+1, j + 2) == 0){open(arrs, arr, i, j + 1);}}//上一位置if (arrs[i][j + 1] == '0' && arr[i - 1][j] == '*'&&right(i-1, j)){arr[i - 1][j] = count(arrs, i, j+1) + '0';num--;if (count(arrs, i, j+1) == 0){open(arrs, arr, i-1, j);}}//左上位置if (arrs[i][j] == '0' && arr[i - 1][j - 1] == '*'&&right(i-1, j-1)){arr[i - 1][j - 1] = count(arrs, i, j) + '0';num--;if (count(arrs, i, j) == 0){open(arrs, arr, i - 1, j - 1);}}//右上if (arrs[i][j + 2] == '0' && arr[i - 1][j + 1] == '*'&&right(i-1, j+1)){arr[i - 1][j + 1] = count(arrs, i, j + 2) + '0';num--;if (count(arrs, i, j + 2) == 0){open(arrs, arr, i-1, j + 1);}}//右下if (arrs[i + 2][j + 2] == '0' && arr[i + 1][j + 1] == '*'&&right(i+1, j+1)){arr[i + 1][j + 1] = count(arrs, i + 2, j + 2) + '0';num--;if (count(arrs, i + 2, j + 2) == 0){open(arrs, arr, i + 1, j + 1);}}//下if (arrs[i + 2][j + 1] == '0' && arr[i + 1][j] == '*'&&right(i+1, j)){arr[i + 1][j] = count(arrs, i + 2, j+1) + '0';num--;if (count(arrs, i + 2, j+1) == 0){open(arrs, arr, i + 1, j);}}//左下if (arrs[i + 2][j] == '0' && arr[i + 1][j - 1] == '*'&&right(i+1, j-1)){arr[i + 1][j - 1] = count(arrs, i + 2, j) + '0';num--;if (count(arrs, i + 2, j) == 0){open(arrs, arr, i + 1, j - 1);}}
}
Test.c
#pragma warning(disable:4996)
#include"game.h"
void playgame()
{char arr[ROW][CLO] = { 0 };    //显示棋盘char arrs[ROWS][CLOS] = { 0 };   //真正操作的棋盘arr_init(arr, ROW, CLO);arrs_init(arrs, ROWS, CLOS);arrs_randinit(arrs, ROWS, CLOS);printbroad(arr, ROW, CLO);print(arrs, ROWS, CLOS);sweep(arrs, arr, ROW, CLO);}
int main()
{srand((unsigned int)time(NULL));int key = 0;do{menu();scanf("%d", &key);if (key == 1)playgame();else if (key == 0)printf("退出游戏\n");elseprintf("输入有误,请重新输入:\n");} while (key);return 0;
}

3.4执行结果

在这里插入图片描述
生成棋盘与地雷
在这里插入图片描述
输入坐标进行判断
在这里插入图片描述
输入坐标进行判断
在这里插入图片描述
游戏结束
在这里插入图片描述

3.5存在问题分析

(1)没有实现插旗的功能。
(2)不能统计以往的游戏信息,没有实现数据保存。
(3)没有排行榜功能。
(4)不能进行游戏难度的设定。

3.6结论

这次的扫雷程序代码量比较大,一开始给我们小组造成了一些困难,但经过我们的查找资料,相互交流,将这些困难一一克服,其中的展开函数经过我们的不断调试,终于将正确的参数确定。完成了这项代码,我觉得我的代码能力提高了很多,对问题的分析有了进一步的提升,即使出现问题,经过不断的调试,耐心的对待,最后总会成功的。在以后的学习中更要脚踏实地,不怕困难。

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

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

相关文章

C语言的编译链接过程的介绍

发布时间: 2012-11-08 10:17 作者: 未知 来源: 51Testing软件测试网采编 字体: 小 中 大 | 上一篇 下一篇 | 打印 | 我要投稿 | 推荐标签&#xff1a; DotNet 软件开发 | 感言十年 C语言的编译链接过程要把我们编写的一个c程序&#xff08;源代码&#x…

技术与技巧札记

Linux常用命令及技巧&#xff1a; &#xff08;1&#xff09;cat /proc/version 查看当前内核的版本 (2) 挂载nfs文件夹&#xff1a;需要先确认在&#xff0f;etc&#xff0f;exports文件&#xff0c;可以用于开发板挂载的文件夹 mount -o nolock 10.0.22.30:/root/sharednfs …

从0开始python学习-35.allure报告企业定制

目录 1. 搭建allure环境 2. 生成报告 3. logo定制 4. 企业级报告内容或层级定制 5. allure局域网查看 1. 搭建allure环境 1.1 JDK&#xff0c;使用PyCharm 找到pycharm安装目录找到java.exe记下jbr目录的完整路径&#xff0c;eg: C:\Program Files\JetBrains\PyCharm Com…

系统架构札记

什么是高内聚、低耦合&#xff1f; 起因&#xff1a;模块独立性指每个模块只完成系统要求的独立子功能&#xff0c;并且与其他模块的联系最少且接口简单&#xff0c;两个定性的度量标准――耦合性和内聚性。 耦合性也称块间联系。指软件系统结构中各模块间相互联系紧密程度的一…

c++中的继承--1(引出,继承方式,继承的对象模型)

继承的引出 概念&#xff1a; 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特 性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。继承呈现了面向对象程序设计的层次结构…

c++中的多态---1(多态概念,静态联编和动态联编,多态原理解析,重载,重写,重定义的对比)

多态的基本概念 多态是面向对象设计语言数据抽象和继承之外的第三个基本特征多态性(polymorphism)提供接口与具体实现之间的另一层隔膜&#xff0c;从而将“what”和“how”分离开来&#xff0c;多态性改善了代码的可读和组织性&#xff0c;同时也使创建的程序具有可扩展性&am…

Ubuntu下各种服务搭建及操作技巧

Ubuntu下搭建TFTP 1、安装软件包 sudo apt-get install tftpd tftp xinetd 2、建立配置文件 在/etc/xinetd.d/下建立一个配置文件tftp sudo vi /etc/xinetd.d/tftp 内容如下 service tftp { socket_type dgram protocol udp wait yes user root …

使用Automake和Autoconf生成Makefile

automake 所产生的 Makefile 除了可以做到程序的自动编译和链接 外&#xff0c;还可以用来生成各种文档&#xff08;如manual page、info文件&#xff09;&#xff0c;可以将源代码文件包装起来以供发布。所以程序源代码所存放的目录 结构最好符合GNU的标准惯例。下面以hello.…

c++中多态---3(虚析构和纯虚析构,向上类型转化和向下类型转化)

虚析构和纯虚析构 虚析构virtual ~类名(){}类内声明&#xff0c;类内实现解决问题&#xff1a;通过父类指针指向子类对象释放时候不干净的问题 纯虚析构 写法 virtual ~类名(){}0; 类内声明 类外实现 如果出现了纯虚析构函数&#xff0c;这个类也算是抽象类&#xff0c;不可…

嵌入式开发硬件知识札记

三态逻辑 1. 概念 三态指其输出既可以是一般二值逻辑电路&#xff0c;即正常的高电平&#xff08;逻辑1&#xff09;或低电平&#xff08;逻辑0&#xff09;&#xff0c;又可以保持特有的高阻抗状态。高阻态相当于隔断状态&#xff08;电阻很大&#xff0c;相当于开路&#xff…

《凡人修仙传》中打斗场景(c++多态实现)

我们 要实现打斗场景&#xff0c;第一&#xff0c;我们需要有打斗的双方&#xff0c;一个是英雄&#xff0c;一个是怪物&#xff0c;他们都有自己的属性&#xff0c;比如攻击&#xff0c;防御&#xff0c;血量。其次我们的英雄还会有武器。武器上有一些加成属性&#xff0c;可以…

c++中的文件读写的操作

写文件 ofstreamopen指定打开方式isopen判断是否打开成功ifs<<“数据”ofs.close&#xff08;&#xff09; 读文件 ifstream ifs 指定打开方式ios::in isopen判断是否打开成功 读取有三种方式 #include<iostream>using namespace std;//文件读写头文件#incl…

c++的STL--1概念通述

STL的概念 什么是STL? STL(standard template libaray-标准模板库)&#xff1a;是C标准库的重要组成部分&#xff0c;不仅是一个可复用的组件库&#xff0c;而且 是一个包罗数据结构与算法的软件框架。 STL从广义上分为&#xff1a;容器(container)&#xff0c;算法(algorit…

c++的vector容器

vector容器概念 vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素 进行访问&#xff0c;和数组一样高效。但是又不像数组&#xff0c;它的大小是可以动态改变的&#xff0c;而且它…

新一代数据库技术

新一代非关系型数据库有以下5个主要类型&#xff1a; 面向文件存储&#xff1a;适用于存储海量文件&#xff0c;代表产品MongoDb 列存储(wide column store/column-family)数据库&#xff1a;快速查找相关数据&#xff0c;相关数据被放在同一列中&#xff0c;代表产品Cassandra…

c++中stack容器

Stack 简介 stack 是堆栈容器&#xff0c;是一种“先进后出”的容器。stack 是简单地装饰 deque 容器而成为另外的一种容器。#include stack没有迭代器 Stack所有元素的进出都必须符合“先进后出”的条件&#xff0c;只有stack顶端的元素&#xff0c;才有机会被外界取用&am…

c++中的queue容器

queue容器 队列是一种容器适配器&#xff0c;专门用于在FIFO上下文(先进先出)中操作&#xff0c;其中从容器一端插入元素&#xff0c;另一端 提取元素。 队列作为容器适配器实现&#xff0c;容器适配器即将特定容器类封装作为其底层容器类&#xff0c;queue提供一组特定的 成员…

c++中list容器

list概念 list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向 其前一个元素和后一个元素。list与for…

c++中容器(STL)的共性与使用的时机

容器的共通能力 C模板是容器的概念 理论提高&#xff1a;所有容器提供的都是值&#xff08;value&#xff09;语意&#xff0c;而非引用&#xff08;reference&#xff09;语意。容器执 行插入元素的操作时&#xff0c;内部实施拷贝动作。所以 STL 容器内存储的元素必须能够被…

Qt Creator 窗体控件自适应窗口大小布局

常见的软件窗口大小改变&#xff08;最大化、手动改变时&#xff09;需要窗口的部件能够自适应布局&#xff0c;而在Qt的应用程序界面设计中&#xff0c;对于像我一样的初学者如何实现窗口自适应调整还是要绕点弯路的。网上百度了很多&#xff0c;多数说的很含糊&#xff0c;还…