当前位置:网站首页>扫雷pro版2021-08-19
扫雷pro版2021-08-19
2022-07-26 10:36:00 【竹某】
#1代码
//头文件 game.h
#pragma once
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <time.h>
struct oneGame {//一次游戏所需要的数据,game()中的任何子函数都是围绕它修改
char* mineField = NULL;//雷区数组,考虑到计算数字和展示,以及节约空间(防止内存泄漏),所以使用char*。为了简化计算,所以实际行列数目要+2。
//元素为'#',表示雷;元素为‘0’或‘1’,表示数字区。‘0’说明未被展开,‘1’说明已被展开。用于减少递归算法的开销。
char* sweptField = NULL;//已扫雷区数组,根据后续的函数决定使用什么数据类型。
int row = 0;//雷区行数
int col = 0;//雷区列数
int mines = 0;//需要雷的数目
int mineNum = 0;//剩余雷的数目
};
int menu(void);//游戏起始菜单,从外部输入模式,并将之返回
void game(int mode);//根据输入的游戏模式(int),进行一次游戏。
/*
game函数有两个部分:
1、根据形参mode,生成不同的雷区。generateMineField。
2、用户扫一次雷(x,y外部输入),根据不同的条件,产生不同的结果。sweepOnce
失败:本次扫到的是雷===》打印死亡信息;展示雷区;退出game()
正确:本次扫到的不是雷===》打印正确信息;计算本格的数字compute;以本格为中心展开expansion;返回循环开头要求输入
成功:本次正确且已扫完===》打印完成信息;展开已扫雷区;退出游戏
至少需要记录:
1、雷区(答案)(二维数组,雷的数目,雷的分布,雷区长,雷区宽)
2、已扫区域(可以展示给玩家看的)(扫过的区域)
*/
void generateMineField(oneGame*);//生成指定长,指定宽,指定雷数,雷随机分布的雷区;生成已扫雷区并初始化。
/*实现上:生成雷区并初始化--》生成已扫雷区并初始化。
*/
int sweepOnce(oneGame*);//一次扫雷,返回结果。-1为失败,1为成功,0为正确。
int compute(oneGame*, int, int );
//计算给定坐标处的数字(在不是雷的前提下),写入sweptField,同时返回之。
void expansion(oneGame*, int, int);
void display(char*, oneGame*);
//打印二维数组
//1.将设计思路转化为流程图
//2.根据流程图分析出函数和使用的数据(只是停留在功能的层面,没有考虑如何实现)
//3.考虑函数的实现,同时也可以考虑使用的数据该用什么方式进行存储(根据使用方式决定存储方式)
//4.实现函数,可能还需要设计子函数
//源文件game.cpp
#include "game.h"
int menu() {
int mode = 0;
printf("###################################\n");
printf("###########请选择游戏难度##########\n");
printf("###########1、初级难度#############\n");
printf("###########2、中级难度#############\n");
printf("###########3、高级难度#############\n");
printf("###########你的选择>: ");
scanf("%d", &mode);
while (getchar() != '\n')
;//不做任何事情,用于情况输入缓冲区
return mode;
}
void game(int mode) {
int isDead = 0;
oneGame thisGame;
//根据mode选择模式
if (mode == 1) {//初级模式
thisGame.col = thisGame.row = 9 + 2;
thisGame.mines = 2;
thisGame.mineNum = 2;
}
if (mode == 2) {//中级模式
thisGame.col = thisGame.row = 16 + 2;
thisGame.mines = 40;
thisGame.mineNum = 40;
}
if (mode == 3) {
thisGame.col = 30 + 2;
thisGame.row = 16 + 2;
thisGame.mines = 99;
thisGame.mineNum = 99;
}
generateMineField(&thisGame);
display(thisGame.sweptField,&thisGame);
//display(thisGame.mineField,&thisGame);
while (isDead == 0) {
isDead = sweepOnce(&thisGame);
}
free(thisGame.mineField);
free(thisGame.sweptField);
return;
}
void generateMineField(oneGame* thisGame) {
//初始化雷区和已扫雷区
thisGame->mineField = (char*)malloc(thisGame->col*thisGame->row);
thisGame->sweptField = (char*)malloc(thisGame->col*thisGame->row);
for (int i = 0; i < thisGame->col*thisGame->row; ++i) {
*(thisGame->mineField + i) = '0';
*(thisGame->sweptField + i) = '#';
}
for (int i = 0; i < thisGame->row - 2; ++i) {
for (int j = 0; j < thisGame->col - 2; ++j) {
*((thisGame->sweptField + thisGame->col + 1) + j + i * (thisGame->col)) = ' ';
}
}
//随机分布的雷,分布在雷区中间,四周没有
srand((unsigned long)time(NULL));
for (int i = 0; i < thisGame->mines;) {
int x = rand() % (thisGame->row - 2);
int y = rand() % (thisGame->col - 2);
if (*((thisGame->mineField + thisGame->col + 1) + y + x * (thisGame->col)) == '#') {
;//不干什么
}
else {
*((thisGame->mineField + thisGame->col + 1) + y + x * (thisGame->col)) = '#';
++i;
}
}
}
int sweepOnce(oneGame* thisGame) {
//要求输入
printf("输入坐标>: ");
int x = 0;
int y = 0;
int choice = 0;
scanf("%d%d%d", &x, &y, &choice);
while (getchar() != '\n')
;//不做任何事情,用于情况输入缓冲区
//如果错误/失败
if (choice == 0) {
if (*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col)) == '#') {
printf("扫雷失败,游戏结束!\n");
display(thisGame->mineField, thisGame);
return -1;
}
//如果正确
if (*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col)) != '#') {
printf("本次成功,继续游戏!\n");
compute(thisGame, x, y);
expansion(thisGame, x, y);
system("cls");
display(thisGame->sweptField, thisGame);
}
}
if (choice == 1) {
if (*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col)) != '#') {
printf("扫雷失败,游戏结束!\n");
display(thisGame->mineField, thisGame);
return -1;
}
//如果正确
if (*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col)) == '#') {
--thisGame->mineNum;
printf("本次成功,继续游戏!\n");
*((thisGame->sweptField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col)) = '#';
system("cls");
display(thisGame->sweptField, thisGame);
}
//如果成功
if (thisGame->mineNum == 0) {
printf("扫雷成功,游戏结束!\n");
display(thisGame->sweptField, thisGame);
return 1;
}
}
return 0;
}
int compute(oneGame* thisGame, int x, int y) {
int count = 0;
if (*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) + 1) == '#')
++count;
if (*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) - 1) == '#')
++count;
if (*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) + thisGame->col) == '#')
++count;
if (*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) - thisGame->col) == '#')
++count;
if (*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) + thisGame->col + 1) == '#')
++count;
if (*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) - thisGame->col + 1) == '#')
++count;
if (*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) + thisGame->col - 1) == '#')
++count;
if (*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) - thisGame->col - 1) == '#')
++count;
*((thisGame->sweptField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col)) = count + '0';
return count;
}
void expansion(oneGame* thisGame, int x,int y) {
*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col)) = '1';
//使用递归算法导致栈溢出,所以进行了反复修改,加了很多条件,尽量减少空间复杂度
if (*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) + 1) != '#') {
if(*((thisGame->sweptField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) + 1) != '#'){
if(*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) + 1) != '1')
if(compute(thisGame, x, y + 1) == 0)
expansion(thisGame, x, y + 1);
}
}
if (*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) - 1) != '#') {
if(*((thisGame->sweptField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) - 1) != '#')
if(*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) - 1) != '1')
if(compute(thisGame, x, y - 1) == 0)
expansion(thisGame, x, y - 1);
}
if (*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) + thisGame->col) != '#') {
if(*((thisGame->sweptField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) + thisGame->col) != '#')
if(*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) + thisGame->col) != '1')
if(compute(thisGame, x + 1, y) == 0)
expansion(thisGame, x + 1, y);
}
if (*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) - thisGame->col) != '#') {
if(*((thisGame->sweptField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) - thisGame->col) != '#')
if(*((thisGame->mineField + thisGame->col + 1) + y - 1 + (x - 1) * (thisGame->col) - thisGame->col) != '1')
if(compute(thisGame, x - 1, y) == 0)
expansion(thisGame, x - 1, y);
}
return;
}
void display(char* thisArray,oneGame* thisGame){
for (int i = 0; i < thisGame->col - 1; ++i) {
printf("%2d ", i);
}
printf("\n");
for (int i = 0; i < thisGame->row - 2; ++i) {
printf("%2d ", i + 1);
for (int j = 0; j < thisGame->col - 2; ++j) {
printf("%2c ", *((thisArray + thisGame->col + 1) + j + i * (thisGame->col)));
}
printf("\n");
}
}//主函数test.cpp
#include "game.h"
int main() {
int choice = 0;
again:
int mode = menu();
game(mode);
printf("#########你想再完一把吗?\n");
printf("#########1.再玩一把\n");
printf("#########0.不玩了\n");
printf("你的选择>: ");
scanf("%d",&choice);
while (getchar() != '\n')
;//不做任何事情,用于情况输入缓冲区
if (choice == 0)
;//不做任何事情
else
goto again;
return 0;
}
#2游戏规则
按照提示进入游戏。之后输入x y choice。x代表横坐标,y代表纵坐标,choice表示选择(1表示此处有雷,0表示此处没有雷)。容错机制没有做,谨慎输入。
边栏推荐
- Some cutting-edge research work sharing of SAP ABAP NetWeaver containerization
- C语言计算日期间隔天数
- [leetcode每日一题2021/8/31]1109. 航班预订统计【中等】差分数组
- 干货likeshop外卖点餐系统开源啦100%开源无加密
- 异常的概念与处理
- Issue 6: which mainstream programming language should college students choose
- Inheritance method of simplified constructor (II) - class inheritance in ES6
- [leetcode每日一题2021/4/23]368. 最大整除子集
- 并行、并发及对于高并发优化的几个方向
- .NET操作Redis Hash对象
猜你喜欢
随机推荐
[leetcode每日一题2021/4/29]403. 青蛙过河
Analysis of the transaction problem of chained method call
数据库函数
kali 查看ip地址
[leetcode每日一题2021/2/13]448. 找到所有数组中消失的数字
Okaleido ecological core equity Oka, all in fusion mining mode
putty的使用教程
父类对子类的引用(父类引用指向子类对象)
.net operation redis sorted set ordered set
事务的传播性propagation
并行、并发及对于高并发优化的几个方向
Navicat15连接本地虚拟机的Mysql(Centos7)
超图 影像 如何去除黑边(两种方法)
Mlx90640 infrared thermal imager temperature sensor module development notes (VI) pseudo color coding of infrared images
Using native JS to realize custom scroll bar (click to reach, drag to reach)
.NET5WTM(ASP.NET Core) PGSql开箱操作
[转]ArcGIS中判断两个Geometry之间的关系
10 令 operator= 返回一个 reference to *this
js 获得当前时间,时间与时间戳的转换
Controller返回JSON数据









