这是经过「扫雷与算法」小程序来说解算法的第一章:如何随机化的进行布雷,主要介绍了三种不那么好的方法,但愿经过这些很差的方法能让你们明白第二章要讲解的「洗牌算法」有多牛逼。javascript
补充:「扫雷与算法」小程序会在写完后进行开源,发布在个人 GitHub 上面。java
最想固然的方法就是随机的在二维区间寻找一个点布雷便可,代码以下:算法
for (var i = 0; i < mineNumber; i++) {
var row = this.rangeRandom(0, this.rowCount - 1);
var col = this.rangeRandom(0, this.colCount - 1);
//使用数字 9 表示该区域有雷
tmpMineMap[row][col] = 9;
}
复制代码
这种实现逻辑的一个弊端就是会在已经布雷的位置再度布雷,进而致使整个区域的布雷数量与要求不符合。编程
如上图所示,须要布雷的个数为 5 ,但在最后一次的随机布雷过程当中只埋了 4 颗雷。小程序
方法二是对方法一的改善:既然会重复埋雷,那么只须要再埋雷的过程当中判断一下该位置是否已经埋雷便可。dom
代码以下:优化
for (var i = 0; i < mineNumber; i++) {
//经过死循环来实现不停的寻找,直到安置好雷
while (true) {
var row = this.rangeRandom(0, this.rowCount - 1);
var col = this.rangeRandom(0, this.colCount - 1);
//用数字 9 表示该区域有雷,若是该位置没有布雷,那么则放置
if (tmpMineMap[row][col] != 9) {
tmpMineMap[row][col] = 9;
//跳出循环
break;
}
}
}
复制代码
使用效果以下:ui
效果貌似挺好的,但小伙伴们可能已经注意到了,上面的代码中有一段 死循环 代码,这就意味着若是棋盘很大,雷区不少,而且你的运气还不够好的话,那么就有可能一直在执行这段 死循环 代码,进而致使程序的卡死崩溃。this
第三种方法是先将雷布置在最前面,而后再不停的打乱。spa
实现代码以下:
//先按顺序排列
for (var i = 0; i < mineNumber; i++) {
var row = parseInt(i / this.colCount);
var col = i % this.colCount;
//使用数字 9 表示该区域有雷
tmpMineMap[row][col] = 9;
}
//定义交换的次数,次数越多越混乱随机
var swapTime = 100;
for (var i = 0; i < swapTime; i++) {
//随机位置1
var row1 = this.rangeRandom(0, this.rowCount - 1);
var col1 = this.rangeRandom(0, this.colCount - 1);
//随机位置2
var row2 = this.rangeRandom(0, this.rowCount - 1);
var col2 = this.rangeRandom(0, this.colCount - 1);
//交换两个位置
var temp = tmpMineMap[row1][col1];
tmpMineMap[row1][col1] = tmpMineMap[row2][col2];
tmpMineMap[row2][col2] = temp;
}
复制代码
这种方法的一个弊端就是对于 swapTime 的依赖程度很高,若是设置的交互次数少了,大部分雷都仍是按照一开始的顺序安置,都在最前面的位置,所有的雷并非随机排放。
最重要的一点是:每一个位置安置雷的几率并非等可能的,也就意味着它不能作到随机化。
我尝试过在小程序上进行几率模拟,但每次都会卡死了,后续发现能优化继续模拟出几率来的话再补上。
在大部分状况下,方法二 与 方法三 是能够知足咱们随机化处理的过程的,但方法二有可能运行卡死崩溃,方法三中每一个位置安置雷的几率并非等可能的。
若是你以为这篇内容对你挺有启发,我想邀请你帮我三个忙: