JavaScript扫雷游戏数组匹配问题:判断雷位恒返回false
嘿,我明白你碰到的麻烦了!在JavaScript里直接用==或者===比较两个数组根本行不通——因为数组是引用类型,这类比较判断的是两个数组是否指向内存里的同一个地址,而不是它们的内容是否一致。哪怕两个数组的元素完全一样,只要是不同的实例,结果就会是false,这就是你当前问题的根源。
先拆解你代码里的问题
在Mine构造函数的循环中,你每次用bombs[iter] == [this.x,this.y]做判断,右边的[this.x,this.y]是一个全新创建的数组,它和bombs里存储的数组肯定不是同一个引用,所以这个判断永远会返回false。而且循环最后一次如果不匹配,this.isBomb会被设为false,覆盖之前可能的true,导致所有Mine实例的isBomb全是false。
另外,你的炸弹生成逻辑还有个小漏洞:如果随机生成的位置重复了,bombs[i] = position不会执行,但i依然会递增,这会导致bombs数组里出现undefined的元素,后续判断也会出错。
三种可行的解决方案
1. 写个辅助函数比较数组内容
创建一个函数来检查两个数组的长度和对应元素是否完全一致:
function arraysEqual(arr1, arr2) { if (arr1.length !== arr2.length) return false; for (let i = 0; i < arr1.length; i++) { if (arr1[i] !== arr2[i]) return false; } return true; }
然后修改Mine构造函数里的判断逻辑:
function Mine(x,y) { this.x = x; this.y = y; this.neighbors = findNeighbors(this.x,this.y); this.isBomb = false; // 默认不是炸弹 for (var iter = 0; iter < bombs.length; iter++) { if (arraysEqual(bombs[iter], [this.x, this.y])) { this.isBomb = true; break; // 找到匹配后直接跳出循环,提升效率 } } this.show = function() { return 'show' } this.setValue = function(value) { this.value = value; return value; } }
2. 用JSON.stringify()转成字符串比较
把数组转换成字符串后再比较,适合元素都是简单类型(比如数字)的场景:
function Mine(x,y) { this.x = x; this.y = y; this.neighbors = findNeighbors(this.x,this.y); this.isBomb = false; const currentPosStr = JSON.stringify([this.x, this.y]); for (var iter = 0; iter < bombs.length; iter++) { if (JSON.stringify(bombs[iter]) === currentPosStr) { this.isBomb = true; break; } } // 其他方法... }
3. 改进炸弹存储方式(推荐)
把炸弹的坐标从数组改成字符串(比如"x,y"格式),这样直接用includes()就能判断,代码更简洁高效:
首先修改setup里的炸弹生成逻辑(同时修复重复位置的问题):
function setup() { // create bombs bombs = []; // 先清空避免重复 for (var i = 0; i < 45; ) { // 这里不先递增i,避免出现undefined var x = floor(random(0,15)); var y = floor(random(0,15)); var position = `${x},${y}`; // 用字符串存储坐标 if (!bombs.includes(position)) { bombs.push(position); i++; } } // create board board = []; for (var y = 0; y < 15; y++) { board[y] = new Array(); for (var x = 0; x < 15; x++) { board[y][x] = new Mine(y,x); } } }
然后Mine构造函数里的判断就可以简化成一行:
function Mine(x,y) { this.x = x; this.y = y; this.neighbors = findNeighbors(this.x,this.y); this.isBomb = bombs.includes(`${this.x},${this.y}`); // 直接判断 this.show = function() { return 'show' } this.setValue = function(value) { this.value = value; return value; } }
额外提示
推荐第三种方法,不仅代码更简洁,字符串查找的效率也比循环比较数组要高,同时还修复了原炸弹生成逻辑里的undefined问题。
内容的提问来源于stack exchange,提问作者Jackson Long

