JavaScript扫雷游戏拓展问题导致计数器错误。

6
我用JavaScript做了一个扫雷游戏,一直运行得非常顺畅,直到我添加了“expand()”函数(见下文)。我有3个问题:
  1. 当它扩展时,会向“flippedCount”添加太多内容(请参见下面的代码)-在下面的图像中,右侧的div显示“flippedCount”,它是39而不是35。
  2. 因此,如果玩家在“expand()”期间超过90个方块(获胜数量),则获胜屏幕不会显示。
  3. 它也无法正确地扩展(请参见下面的图像)。
相关代码和链接位于下面这两张图片之下。

Image showing a partly completed minesweeper field

Image showing an 'empty' minesweeper field

var flippedCount = 0;
var alreadySetAsZero = [];
var columnAmount = 10;

function processClick(clicked) { //i use a "(this)" to pass as "(clicked)"
  nextToBombCheck( parseInt(clicked.id) );
  checkWin();
}

nextToBombCheck( boxNum ) { 
  flippedCount++;
  document.getElementById("flipped").innerHTML = flippedCount;  
  //long function setting "bombCount" to # bombs around clicked square goes here
  if ( bombCount !== 0 ) { 
    //blah blah blah
  } else {
    alreadySetAsZero[ boxNum ] = "yes";
    expand(boxNum);
  } 
}

function expand( emptyBoxId ) {
  checkRightOfEmpty( emptyBoxId + 1 );
  checkLeftOfEmpty( emptyBoxId - 1 );
  checkAboveEmpty( emptyBoxId - columnAmount );
  checkBelowEmpty( emptyBoxId + columnAmount );
} 

function checkRightOfEmpty( boxToTheRightId ) {
  //check if already marked as zero
  if ( alreadySetAsZero[ boxToTheRightId ] === "yes" )
    return;
  //if box is at the edge
  if ( boxToTheRightId % columnAmount === ( 0 ) ) {
    //do nothing
  } else {
    nextToBombCheck( boxToTheRightId );
  }
}

//and the rest are 3 similar functions

我无法找到与扩展缺乏或翻转计数中添加数字有关的模式。 这里放链接 附言:对于标题我很抱歉,我不知道该怎么称呼它。

如果我可以提个建议:请正确格式化你的代码(适当缩进),并注意短语的语法(例如,一个短语以大写字母开头,通常以句号结束)。如果问题易于阅读,人们更有可能回答它。 - Sumurai8
3个回答

4
你得到了错误的计数,因为你的算法没有考虑已经翻转过的方块——导致某些方块被重复计数。

保持精确计数的最简单方法是利用“getElementsByClassName”返回一个实时节点列表的事实。

注意:getElementsByClassName具有相当好的浏览器支持,但如果你的浏览器要求不同,你需要稍微进行调整。

进入时,初始化该列表(变量名只是为了区分之前的名称):

var newFlippedCount = document.getElementsByClassName('flipped');

每次更新带有炸弹计数类的方格时,请改用以下内容(同时添加翻转类):

document.getElementById(boxNum).className = classList[bombCount] + ' flipped';

当您使用新的翻转计数更新UI时,请使用:
document.getElementById("flipped").innerHTML = newFlippedCount.length;

你的计数现在神奇地正确了 :)

注意:你也可以通过检查盒子是否已经翻转来增加flippedCount来解决这个问题。

你还会定期在控制台中收到一个错误:

Uncaught TypeError: Cannot set property 'className' of null

在这一行(大约在第298行):
document.getElementById(boxNum).className = classList[bombCount];
你应该保护它,要么通过检查边界,要么只是在使用之前检查返回值:
您应该通过检查边界或仅检查返回值来保护它。
var ele = document.getElementById(boxNum);
if(!ele) return;

ele.className = classList[bombCount] + ' flipped';

演示

编辑:如果您有兴趣,这里是扫雷级联算法的高级概述

更新-发现级联错误

级联在连续重播时无法正常工作的原因之一是,用于跟踪已设置为零的单元格的变量在新游戏中没有被重置。 要修复此问题:

function start() {
   …
   // Reset to empty array
   alreadySetAsZero = [];
   ...
}

我更新了一个包含额外调试语句的 fiddle,以帮助找到问题:

演示


我认为 "document.getElementById("flipped").innerHTML = newFlippedCount.length;" 不会起作用,请编辑答案或解释一下这段代码,感谢您的帮助。 - Math chiller
我并没有声称这些是唯一需要更改的地方,也没有说你的代码已经完全调试好了。逻辑检查中有几个地方涉及到翻转计数(flippedCount)- 这些地方也需要进行更改。不过这应该能让你开始着手处理了... - dc5
我根据其他答案修复了翻转计数的问题,但似乎仍存在一些错误。不过现在偏差小了很多,但仍然存在未能翻转所有方框的问题。 - Math chiller
谢谢,运行得很完美,我要去比较一下并尝试理解这些更改。 - Math chiller
那个版本中存在一个大写错误 - 请查看fiddle v3。当点击已经翻转的单元格时,它会被触发。现在大写问题已经修复,但是它会像你最初的代码一样导致你输掉游戏。注意,在这个版本中,炸弹最初显示是为了方便调试。 - dc5
我已经为点击已翻转的方块做了处理,代码在第116行(在“process(clicked)”函数中)"if (gameOn && clicked.className == "box")" = 如果您点击已翻转的方块,则该函数不会运行。这一定是其他问题,但我不知道是什么。 - Math chiller

1
虽然您使用“alreadySetAsZero”来防止将方块计数多次,但这没有考虑到具有炸弹计数的方块。在您的扩展方法中,这些方块将被多次计数。

谢谢另一个回答者,他没有指出我的代码导致问题的原因。 - Math chiller

0

我找到了困扰我的问题(计数器),它将“-1”和“100”的方块算上了。

然后我在checkRightOfEmpty中添加了|| boxToTheRightId > ( cellAmount - 1 ),并在checkLeftOfEmpty中添加了|| boxToTheRightId < 0(在它们的if语句中),现在一切都好了,还是谢谢大家。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接