扫雷代码 java伪代码_算法实现自动扫雷游戏

算法实现自动扫雷游戏

1.游戏的构思

2.算法伪代码的实现

3.算法的实现

1.首先需要建立起游戏的整个框架(棋盘的绘制,地雷的生成,基本函数的实现等)

2.构思AI算法的大概样貌(先尝试写伪码)

void AI() //AI算法

if(First)

SelectRandomPos()//游戏开始随机选择一处位置翻开

SelectPos()//根据已有条件选择最佳翻开位置

if(!GameOver)

AI()//递归继续进行选择,直到游戏结束

3.简单的伪码写好后,接下来应该来思考如何具体实现这一算法

3.1对于SelectRandomPos()实现随机位置,我们可以使用

Col = (rand())%ColNum;

Row = (rand())%RowNum;//Col,Row为随机翻开的行列坐标

//ColNum和RowNum为总的行列数

//注意这里的随机为伪随机,要想真正接近随机可以使用下面这段代码

srand((unsigned int)(time(NULL)));

int k = (rand())%25;

int l = (rand())%14;

参考:用时间做种子生成随机数

实现这一函数功能

3.2对于函数SelectPos(),这是我们的重头戏,这个函数我们的作用是实现选择最佳翻开位置,在我们不知道当前位置是否有雷的情况下,那么我们去选择呢?我们需要将问题数字化,定义一个指数来判断,是否应该翻开当前位置,而概率则可充当这一任务。

我们知道当第一次翻开时,我们是随机的,那么第二次我们就可以根据我们已知的条件来判断了,例如当前如图(1)

e15111b6aa0fbb4e154f6aa201388994.png

对于当前情况我们需要分析当前点周围出现地雷的概率如图(2)

d58dc9b045a056c515ac4781dd265d63.png

周围有Count个点未被翻开,而周围显示有N个地雷,所以我们可以知道

P=N%Count,得到概率为0.25,注意此处N,P,Count应该定义为浮点型。

现在我们应该翻开它周围点吗?我们还需要思考能不能翻开它周围以外的点,我称它为冒险博弈GetRisk();

由于我们已经知道,被掀开点周围有2个地雷Mine,(如果)地雷(MineNum)和行(Col)列(Row)数目是已知的,那我们就可以得到除了它周围以外的点是地雷Mine的风险risk,P=(MineNum-已知地雷数目)%(Col*Row-9)

将得到的概率相互一比较,得到最优选择。

当区域内多点被掀开,我们应该如何去考虑它的概率?如图(3)

81988158313144ff6822573de50fe2dc.png

但我们掀开周围点后,发现另一个点周围有三个地雷,那么如何确定这两个点周围点是地雷的概率呢?

首先我们需要确定新掀开的点周围有雷的概率,然后再更新前一个点的概率,注意概率的更新只影响到被掀开点周围的点。

然后将两掀开点周围的点纳入一个数组MineAround[]中,再计算被掀开点周围有雷的概率,注意,这一步的计算和前面不同,我们先将区域划分如图(4)

e8d348467afbeeb298a48ef40a1827d1.png

计算区域1的概率时,我们暂时不考虑区域2,区域1中右上角的点已经被掀开,那么说明确定那一点没有雷,那么剩下的点是雷的概率是P1=1%7;

同样对于区域二来说它中心点周围点为雷的概率是:P2=3%7;

然后我们来考虑两者结合的情况,对于两区域为被掀开的点来说它们是雷的概率由它周围点来确定,例如我们简单的举出两个点,如图(5)

4561afccc6bf67405e241f162ef94080.png

对于点b的区域来说,它自身是没有被掀开的,我们计算点b是雷的概率就需要通过它周围的被掀开的点来确定,对于b来说,在它周围只有左下角点被掀开,所以我们认为点b是雷的概率为Pb=P2=3%7,也就是显示3的点的周围点概率。

那么如何确定点a是雷的概率呢?

对于点a,它周围有两个点被掀开,我们就基于这两个点来确定它是雷的概率Pa:

Pa1一定是雷的概率 = (1%7)(3%7)

Pa2一定不是雷的概率 = (6%7)(4%7)

对于这里我们的目的是知道a不是雷的概率,所以我们取Pa = 1-Pa1;

(虽然对于该点来说只有是雷和不是雷的情况,但是这里只讨论可能性)

这样,当我们计算得到所有周围点的概率后,比较出一个最好的概率情况(概率相同时任意取),然后再与Risk比较,得出最后最优选择点位。

--------------------------------2020/12/17-机房-----------------------------------------------

显然在实际情况中,我们遇到的情况将不会只有这些,如果单纯应用上面的算法,那么你扫雷的效率(正确率)是不高的,这是为什么呢?我们需要结合实际情况来分析:

如图(6):

a7ab325a841bb2d33b479fa83e01a64e.png

当程序运行到这一步的时候,如图所示我标出的红色线框

,按照我们的逻辑,对于红色线框中的未被掀开点,我们可以确定它不是雷的(因为它周围的唯一一颗雷已经被发现-标上了旗帜),但是当程序实际运行的时候程序会怎么做呢?如图(7)

e8743b233e91c22436ca00a159307978.png

可以看到程序并没有选择我们认为的最优点,这是为什么呢?我们来尝试通过我们的算法计算一下最优点不是雷的概率:P 1= (3%4)1(1%3)=1%12

对于走错的那个点(踩到雷的点),我们计算一下它不是雷的概率:P2 = (1-2%7)=5%7>P1

程序走得没错,完全按照了我们的算法来执行,但是出现了错误,说明我们算法还有改进的空间,我们忽略了这一种特殊情况,所以我们将它添加上:

for i in MineAround[](已经被掀开的点组成的数组,不包括旗帜,空点和地雷)

if i.Prob==0(i周围为雷的概率为0)

then open i.around

#在这里,我们加入了一种特殊情况,当已经被掀开的点中,存在周围点是雷概率为0的特殊情况是,我们不再比较最优选择(概率),直接打开它的周围点。

添加代码后,实现效果如图(7)

28f3f7dededce85e5ffa467d6cbe17a5.png

笔者最近有点忙,更新可能会很慢。

未完待续。。。。。。。。

当然在实际调试情况中,我们不仅仅将只是遇到这些情况,例如:

1.当我们遇到确认是地雷的点该怎么办?

2.当我们遇到的所有点周围是雷的概率都很高(但不确定是雷或者不是雷)怎么办?

3.等等等等。。。还需要我们慢慢去探讨。

可视化程序设计,课程教师:ZZL

2020/12/15

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值