扫雷器的JQuery网格递归(单击相邻的瓦片)

JQuery Grid Recursion for Minesweeper (click adjacent tiles)

本文关键字:单击 JQuery 网格 递归 扫雷      更新时间:2023-09-26

我已经为一个项目创建了一个javascript版本的扫雷器,但我正在尝试引入一项额外的功能,以更好地模仿我记得玩过的桌面版本。

我的完整代码可以在以下位置找到:jsfiddle

我遇到困难的一个特殊函数是"clickTile()"函数。基本要求是将"选定"类以及相邻矿的数量添加到单击的瓦片的html中。我试图解决的另一个要求是递归自动舔舐没有相邻地雷的瓷砖。

目前的功能是:

function clickTile($tile) {
if ($tile.hasClass('mine')) {
    alert('game over');
    $('.mine').css("background", "red");
} else if (!$tile.hasClass("selected")){
    mines = getNumberOfAdjacentMines($tile);
    $tile.addClass("selected");
    $tile.html(mines);
    //recursively call clickTile function as long as there are no adjacent mines
    if (mines <= 0) {
        height = $('#field .row').length;
        width = $('#field .row .tile').length / height;
        rowNum = $tile.parent().prevAll('div').length
        colNum = $tile.prevAll('div').length
        $above = $tile    // td
        .parent()      // tr
        .parent()      // table or tbody
        .children('.row')
        .eq(rowNum - 1) // the row above this one
        .children('.tile')
        .eq(colNum)    // in the same column as this
        ;
        $below = $tile    // td
        .parent()      // tr
        .parent()      // table or tbody
        .children('.row')
        .eq(rowNum + 1) // the row below this one
        .children('.tile')
        .eq(colNum)    // in the same column as this
        ;
        if (rowNum > 0) {
            if (!$above.hasClass('mine') && !$above.hasClass('selected')){
                clickTile($above);
            }
        }
        if (colNum < (width-1)){
            if(!$tile.next().hasClass('selected')) {
                clickTile($tile.next());
            }
        }
        if (rowNum < (height-1)){
            if(!$below.hasClass('mine') && !$below.hasClass('selected')) {
                clickTile($below);
            }
        }
        if (colNum > 0){
            if (!$tile.prev().hasClass('selected')) {
                clickTile($tile.prev());
            }
        }
    }
}

}

对我来说,这应该可以递归地点击所有有0个相邻地雷的瓦片,但事实并非如此。有人能帮我理解这件事哪里出了问题吗?这种行为非常挑剔。

代码的问题在于,变量的定义没有var关键字,因此它们是在全局范围内定义的。

在单击平铺功能中,您应该替换

// rowNum is defined in the global scope, 
// Its value is overwritten with each recursive call
rowNum = $tile.parent().prevAll('div').length

带有

// rowNum has the function as a scope, 
// its keeps different rowNum values for each recursive function call
var rowNum = $tile.parent().prevAll('div').length

rowNum(和其他变量)值被递归调用覆盖,因此进一步的条件将错误地执行

if (rowNum > 0) { // rowNum can be anything at this point
    // The condition is randomly met
}

var关键字添加到变量中,代码就可以按预期工作了。

有关javascript作用域的更多信息,请点击此处。

好吧,选择器出现了一些问题,导致了太多的递归错误,有时这是一个无休止的循环。我试图找到错误,在某些情况下,您向递归单击函数发送了一个空选择器,因此它无法正常工作。我不喜欢那些选择器,所以我用自己的方式获取上面、下面、下一个和上一个元素,效果很好!这是代码:

function clickTile($tile) {
var tiles=$(".tile");
var rows=8;
var columns=8;
var index=tiles.index($tile);    
if($tile.length ==0) return false;
if ($tile.hasClass('mine')) {
    alert('game over');
    $('.mine').css("background", "red");
} else if (!$tile.hasClass("selected")){
    mines = getNumberOfAdjacentMines($tile);
    $tile.html(mines);
    $tile.addClass("selected");
    //recursively call clickTile function as long as there are no adjacent mines
    if (mines <= 0) {
        if (index >= rows) {
            $above=$(tiles.get(index-rows));
            if (!$above.hasClass('mine') && !$above.hasClass('selected')){
                clickTile($above);
            }
        }
        if ((index+1)%columns !=0 ){
            $next=$(tiles.get(index+1))
            if(!$next.hasClass('selected')) {
                clickTile($next);
            }
        }
        if (index+rows < (rows*columns) ){
            $below=$(tiles.get(index+rows));
            if(!$below.hasClass('mine') && !$below.hasClass('selected')) {
                clickTile($below);
            }
        }
        if ((index+1)%columns != 1){
            $prev=$(tiles.get(index-1))
            if (!$prev.hasClass('selected')) {
                clickTile($prev);
            }
        }
    }
}

}

这里有一个适用于旅行邻居的较短版本:

        if (mines <= 0) {
            var posInRow=(index+1)%columns;
            var neighbours=[];
            if(index >= rows) neighbours.push(index-rows);//up
            if(index+rows < (rows*columns) ) neighbours.push(index+rows);//down
            if(posInRow != 0) neighbours.push(index+1);//right
            if(posInRow != 1) neighbours.push(index-1);//left
            for(var i=0;i<neighbours.length;i++){
                var neighbour=$(tiles.get(neighbours[i]));
                if (!neighbour.hasClass('mine') && !neighbour.hasClass('selected')){
                    clickTile(neighbour);
                }
            }
        }