JQuery Grid Recursion для Сапер (щелкните по соседним плиткам)

0

Я создал javascript версию minesweeper для проекта, но я пытаюсь представить дополнительную функциональность, чтобы лучше подражать настольной версии, которую я помню.

Мой полный код можно найти по адресу: jsfiddle

С особой функцией, с которой я сталкиваюсь, является функция "clickTile()". Базовое требование состоит в том, чтобы добавить класс 'selected', а также количество соседних мин в 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 смежными минами, но это не так. Может ли кто-нибудь помочь мне понять, с чем я могу ошибиться? Поведение очень тонкое.

  • 0
    Кажется, это работает, как ожидалось, вы можете подробно описать проблему?
  • 0
    Попробуйте еще несколько раз, есть случаи, когда у него слишком много ошибок рекурсии, где-то есть ошибка
Показать ещё 1 комментарий
Теги:
recursion
minesweeper

2 ответа

1
Лучший ответ

Проблема с вашим кодом заключается в том, что переменные определены без ключевого слова var, поэтому они определены в глобальной области.

В функции clickTile вы должны заменить

// 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 здесь.

  • 0
    Это здорово. Как раз то, что мне было нужно. Я давно не кодировал javascript, поэтому совершенно забыл о его тенденциях.
1

Ну, у вас были проблемы с селекторами, которые вызывали слишком большую ошибку рекурсии, иногда это был бесконечный цикл. Я попытался найти ошибку, и в некоторых случаях вы отправили в функцию рекурсивного щелчка пустой селектор, поэтому он не работал должным образом. Мне не нравились эти селекторы, поэтому я сделал свой собственный способ получить выше, ниже, следующий и предыдущие элементы, и все получилось отлично! Вот код:

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);
                }
            }

        }

Ещё вопросы

Сообщество Overcoder
Наверх
Меню