
游戏实现完成的模样:

实现扫雷游戏的前提是要知道:>扫雷游戏的玩法(会玩的跳过这步)
扫雷游戏也就是排雷,让玩家点一个坐标,然后显示该坐标周围八个格子有多少个雷
如图所示:

如果踩到雷了就游戏结束,如图

那如果把全部非雷的位置找了出来那么游戏就胜利!
那么知道了游戏的规则,我们就可以大概知道要实现什么功能了!
还是老规矩,玩之前是不是得要把一个游戏画面打印出来给玩家看着进行排雷,那么游戏没有开始的时候我们的游戏画面该是怎么样的呢,你可以要一些字符来填充,比如“#”,“+”等等,我这就用字符“ * ”表示还没被点的坐标

那打印字符前是需要一个数组存放数据,这样子的话二维数组的选择是无可厚非的了!
我们用“ * ”来初始化的数组是用来展示给玩家看的,那么我们是不是还需要一个二维数组,用来存放地雷数据呀!
因为开两个二维数组,这样子才不会混乱,一个用来展示给玩家看,可以理解成前端,一个是用来控制雷的信息,可以理解成后端。
那么下一步,就是怎样去布置雷呢?
记不记得我们之前实现的三子棋游戏,让电脑下棋的时候是不是用随机值进行下棋的,那我们布置雷不也是随机放的吗!
那简直不要太简单,直接让随机值去完成即可
那么最后一步,就是玩家一直输入坐标,然后显示该坐标的周围八个格子有多少个雷,就一直判断玩家是否踩雷了,直至游戏胜利了或者失败!

游戏的大概思路知道了!我们就开始层层解剖啦!

实现棋盘我们是不是说过要用二维数组来存放“ * ”表示没有被排过雷的初始状态。
那么二维数组的行列该怎么确定呢?
其实我们也不知道具体要多少,是根据玩家来确定的嘛,玩家想玩20*20,就打印20*20,玩家想玩简单一点的9*9,我们就打印9*9,所以是不是需要一个宏定义来设定行列的大小呢,这样的方便了后续想修改多少行就多少行,多少列就多少列,灵活性就更高了!
#define ROW 10 //实际游戏的行
#define COL 10 //实际游戏的列
#define EASY_COUNT 30 //要布置多少个雷的设置(游戏难度)
//为什么要这样定义,下面排雷的时候会讲,别急
#define ROWS ROW+2 //方便后台处理的行
#define COLS COL+2//放后台处理的行
那行列确定好了,是不是就需要初始化数组了,那需要把二维数组传给函数,比如我这里的show数组是展示给玩家看的数组,那是不是需要初始化成“ * ”,这个mine就是存放雷信息的,为了避免和show数组重复我们可以先初始化成字符’0’
//模拟一下调用函数的过程
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化雷的棋盘
BoardInit(mine, ROWS, COLS, '0');
//初始化展现的棋盘
BoardInit(show, ROWS, COLS, '*');
//**************************************************//
void BoardInit(char board[ROWS][COLS], int rows, int cols, char set)
{
int i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols;j++)
{
board[i][j] = set;
}
}
}
初始化完成后就需要把它打印出来给玩家看,所以还需要一个打印数组的函数,打印的方式可以任意,你喜欢以什么样的方式打印就用什么方式(怎么好看怎么来),我这里就用我上面演示的那样!

注意:我们那里mine数组的内容是不用打印的,打印的话就可以知道雷的信息(开挂专用!)
void BoardPrint(char board[ROWS][COLS], int row, int col)
{
int i, j;
printf("********扫雷游戏*********\n");
for (i = 0; i <= col; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 0; i <= col; i++)
{
printf("--");
}
printf("\n");
for (i = 1; i <= row; i++)
{
if (i < 10)
printf("%d |", i);
else
printf("%d|", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("********扫雷游戏*********\n");
}
| 布置雷要用的就是随机数的获取,我们就保证获取的坐标在要展示二维数组的范围内即可,这里就给大家解释一下上面为什么要定义一个比游戏实现行列数多2行2列的原因,完全是为了我们在检测有多少个雷的时候,防止数组越界 |

所以我们是需要把雷放在中间要展示的区域,不要把雷放在边界的地方!!
而且我们的show数组,也就是展示给玩家看的数组也要定义多两行两列,因为这样就可以跟mine数组相对于,把玩家输入的坐标就可以直接进行判断对应位置是否有雷 前提是同样是把原来的行列打印出去给玩家看,比如玩家选择的是9*9的,我们后台就实现11*11的show,而打印就打印show中间9*9的格子 ,11*11只是为了和我们的mine数组的雷相对于
我们用字符’1’来表示是雷的标志,字符‘ 0 ’表示不是雷
void setmine(char board[ROWS][COLS], int row, int col)
{
//count为雷的数量
int count = EASY_COUNT;
while (count)
{
//确定坐标在合法范围内
int x = rand() % row + 1; //模row加一为了让它不要布置在边界的地方
int y = rand() % col + 1;
if (board[x][y] == '0')
{
//每布一个雷,就把count-1
count--;
board[x][y] = '1';
}
}
}
我们可以把存放雷信息的mine数组打印看一下:>

把上面的工作做完了,就要进行最后一步,也是这个游戏最重要的一步,玩家输入坐标,然后根据坐标判断游戏的情况
不管怎么样,玩家输入坐标后第一件事就是判断坐标是否合法,非法的话提醒玩家重新输入坐标。
合法之后就要判断输入的坐标是否踩雷,为了就直接结算游戏,非雷就把该坐标的周围8个格子检查有多少个雷,把雷数赋值给show数组,提示给玩家看周围分布有几个雷!
然后最后一步就是判断游戏胜利的条件了,我们可以定义一个变量win,而且的值就等于要排雷的次数,比如你是99行列的游戏,雷的数量为20,99-20就是剩下你要排雷的次数
达了这个次数就说明已经把全部非雷的区域确定好,游戏就胜利!
不过要注意的是因为我们是采用char字符数组,所以我们虽然是把雷初始化成"1",但它是一个字符‘1’,而非雷的格子为字符‘0’,它们的本质是ascll码,字符‘0’的ascll码为48,字符‘1’就为49,所以我们只需要要周围8个格子的字符加起来,然后减去8*字符‘0’就可以了。
比如你如果周围只有一个雷,那就是7 * 48 +1 * 49- 8 * 48=1
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
//win为要胜利排雷的总次数 比如你是9*9行列的游戏,雷的数量为20,9*9-20就是剩下你要排雷的次数
int win = row*col- EASY_COUNT;
while (win)
{
printf("输入坐标:>");
scanf("%d%d", &x, &y);
//判断坐标是否合法
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y]!='*')
{
printf("坐标已被占用,请重新输入\n");
}
else
{
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了\n");
//游戏结束前打印雷的布置位置给玩家看
BoardPrint(mine, ROW, COL);
break;
}
else
{
//没踩雷,就把win-1,直至win为0就胜利
win--;
//获取周围雷的个数
int count = get_mine_count(mine, x, y);//函数实现在下面
//加字符'0'是为了将数字变为字符表示
show[x][y] = count + '0';
BoardPrint(show, row, col);
}
}
}
else
{
printf("坐标非法,请重新输入\n");
}
}
if(win==0)
printf("恭喜你,游戏胜利!\n");
}
//获取坐标中心周围雷的个数
int get_mine_count(char mine[ROWS][COLS], int x, int y)
{
//检查坐标周围8个格子有多少个雷
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');
}
什么是带展开功能的扫雷呢,请看动画

就是一点就把所有为周围为零个雷的区域展开
最要思想就是下面的openshow函数实现的递归,如果对于坐标为零,就把改坐标该为显示‘ 0 ’,并就把周围8个坐标在传给openshow函数,非零就停止递归
int win = ROW * COL - EASY_COUNT;
//展开功能
void openshow(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
{
win--;
int count = get_mine_count(mine, x, y);
if (count == 0)
{
if (show[x][y] != '0')
{
show[x][y] = '0';
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
openshow(mine, show, x + i, y + j);
}
}
}
}
else
{
show[x][y] = count + '0';
return;
}
}
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
//win为要胜利排雷的总次数
while (win)
{
printf("输入坐标:>");
scanf("%d%d", &x, &y);
//判断坐标是否合法
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] != '*')
{
printf("坐标已被占用,请重新输入\n");
}
else
{
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了\n");
//游戏结束前打印雷的布置位置给玩家看
BoardPrint(mine, ROW, COL);
break;
}
else
{
openshow(mine, show, x, y);
BoardPrint(show, row, col);
}
}
}
else
{
printf("坐标非法,请重新输入\n");
}
}
if (win == 0)
printf("恭喜你,游戏胜利!\n");
}
| 看到这个游戏的基础功能就已经完成了,但有一些比标记雷的位置,这个功能还没实现,感兴趣的小伙伴可以自行实现,不出意外的话,后续会更新 |
| 这次扫雷和上一期的三子棋游戏其实都是对二维数组的理解,然后加上一些C语言的基础语法加以组装的实现,你们有get到吗? |

下面还是老规矩,分享一下我的源代码给你们玩玩!!
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
void menu()
{
printf("**********************\n");
printf("********1.play********\n");
printf("********0.exit********\n");
printf("**********************\n");
}
void game()
{
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化雷的棋盘
BoardInit(mine, ROWS, COLS, '0');
//初始化展现的棋盘
BoardInit(show, ROWS, COLS, '*');
BoardPrint(show, ROW, COL);
//布雷
setmine(mine, ROW, COL);
//BoardPrint(mine, ROW, COL); //作弊开关
//排查雷
FindMine(mine, show, ROW, COL);
//扫雷开始
//FindMine(mine, show, ROW, COL);
}
int main()
{
system("color 2");//改变字体颜色
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);
return 0;
}
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<windows.h>
#define ROW 10
#define COL 10
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 30
//初始化棋盘
void BoardInit(char board[ROWS][COLS], int rows, int cols, char set);
//打印棋盘
void BoardPrint(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);
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
void BoardInit(char board[ROWS][COLS], int rows, int cols, char set)
{
int i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols;j++)
{
board[i][j] = set;
}
}
}
void BoardPrint(char board[ROWS][COLS], int row, int col)
{
int i, j;
printf("********扫雷游戏*********\n");
printf(" ");
for (i = 0; i <= col; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 0; i <= col; i++)
{
printf("--");
}
printf("\n");
for (i = 1; i <= row; i++)
{
if (i < 10)
printf("%d |", i);
else
printf("%d|", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("********扫雷游戏*********\n");
}
void setmine(char board[ROWS][COLS], int row, int col)
{
//count为雷的数量
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0')
{
//每布一个雷,就把count-1
count--;
board[x][y] = '1';
}
}
}
int get_mine_count(char mine[ROWS][COLS], int x, int y)
{
//检查坐标周围8个格子有多少个雷
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;
// //win为要胜利排雷的总次数
// int win = row*col- EASY_COUNT;
// while (win)
// {
// printf("输入坐标:>");
// scanf("%d%d", &x, &y);
// //判断坐标是否合法
// if (x >= 1 && x <= row && y >= 1 && y <= col)
// {
// if (show[x][y]!='*')
// {
// printf("坐标已被占用,请重新输入\n");
//
// }
// else
// {
// if (mine[x][y] == '1')
// {
// printf("很遗憾,你被炸死了\n");
// //游戏结束前打印雷的布置位置给玩家看
// BoardPrint(mine, ROW, COL);
//
// break;
// }
// else
// {
// //没踩雷,就把win-1,直至win为0就胜利
// win--;
// //获取周围雷的个数
// int count = get_mine_count(mine, x, y);
// //加字符'0'是为了将数字变为字符表示
//
// show[x][y] = count + '0';
// BoardPrint(show, row, col);
// }
// }
// }
// else
// {
// printf("坐标非法,请重新输入\n");
// }
// }
// if(win==0)
// printf("恭喜你,游戏胜利!\n");
//}
//
//win为要胜利排雷的总次数
int win = ROW * COL - EASY_COUNT;
//展开功能
void openshow(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
{
win--;
int count = get_mine_count(mine, x, y);
if (count == 0)
{
if (show[x][y] != '0')
{
show[x][y] = '0';
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
openshow(mine, show, x + i, y + j);
}
}
}
}
else
{
show[x][y] = count + '0';
return;
}
}
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
while (win)
{
printf("输入坐标:>");
scanf("%d%d", &x, &y);
//判断坐标是否合法
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] != '*')
{
printf("坐标已被占用,请重新输入\n");
}
else
{
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了\n");
//游戏结束前打印雷的布置位置给玩家看
BoardPrint(mine, ROW, COL);
break;
}
else
{
openshow(mine, show, x, y);
BoardPrint(show, row, col);
}
}
}
else
{
printf("坐标非法,请重新输入\n");
}
}
if (win == 0)
printf("恭喜你,游戏胜利!\n");
}
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
通常,数组被实现为内存块,集合被实现为HashMap,有序集合被实现为跳跃列表。在Ruby中也是如此吗?我正在尝试从性能和内存占用方面评估Ruby中不同容器的使用情况 最佳答案 数组是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。Ruby语言规范只规定了Ruby数组的行为,并没有规定任何特定的实现策略。它甚至没有指定任何会强制或至少建议特定实现策略的性能约束。然而,大多数Rubyist对数组的性能特征有一些期望,这会迫使不符合它们的实现变得默默无闻,因为实际上没有人会使用它:插入、前置或追加以及删除元素的最坏情况步骤复
在ruby中,你可以这样做:classThingpublicdeff1puts"f1"endprivatedeff2puts"f2"endpublicdeff3puts"f3"endprivatedeff4puts"f4"endend现在f1和f3是公共(public)的,f2和f4是私有(private)的。内部发生了什么,允许您调用一个类方法,然后更改方法定义?我怎样才能实现相同的功能(表面上是创建我自己的java之类的注释)例如...classThingfundeff1puts"hey"endnotfundeff2puts"hey"endendfun和notfun将更改以下函数定
修改(澄清问题)我已经花了几天时间试图弄清楚如何从Facebook游戏中抓取特定信息;但是,我遇到了一堵又一堵砖墙。据我所知,主要问题如下。我可以使用Chrome的检查元素工具手动查找我需要的html-它似乎位于iframe中。但是,当我尝试抓取该iframe时,它是空的(属性除外):如果我使用浏览器的“查看页面源代码”工具,这与我看到的输出相同。我不明白为什么我看不到iframe中的数据。答案不是它是由AJAX之后添加的。(我知道这既是因为“查看页面源代码”可以读取Ajax添加的数据,也是因为我有b/c我一直等到我可以看到数据页面之后才抓取它,但它仍然不存在)。发生这种情况是因为
在Rails自动生成的功能测试(test/functional/products_controller_test.rb)中,我看到以下代码:classProductsControllerTest我的问题是:方法调用products()在哪里/如何定义?products(:one)到底是什么意思?看代码,大概意思是“创建一个产品”,但是它是如何工作的呢?注意我是Ruby/Rails的新手,如果这些是微不足道的问题,我深表歉意。 最佳答案 如果您查看test/fixtures文件夹,您会看到一个products.yml文件。这是在您创建