单击jQuery选择器数组中的1项应用于数组中的所有元素

时间:2014-07-30 03:25:47

标签: javascript jquery

我试图为扫雷游戏实施作弊功能,揭示1个随机非炸弹方(第279行),以及其安全的相邻方块(周围没有炸弹的8个方格中的任何一个) 。

出于某种原因,执行此$(this.nonBombCells.random()[0]).click()会触发所有非炸弹方块(第260行),而不仅仅是随机的和安全的邻居,直到遇到附近的炸弹。

如果我在第279行注释并单击非炸弹单元格,则按预期工作。

我这里有一个傻瓜:http://plnkr.co/edit/OyC8LbFdsAFPn709pUiw?p=preview

如何让这个功能正常工作,就像人类点击那个方格一样?

相关代码:

(function($){

    // I am the controller for the mine sweeper game.
    function MineSweeper(selector, columnCount, rowCount, bombCount){
        var self = this;
        this.table = $(selector);
        this.columnCount = (columnCount || 30);
        this.rowCount = (rowCount || 30);

        // Check to see if the bomb count contains a percent sign.
        if ((typeof(bombCount) == "string") && (bombCount.indexOf("%") > 0)){
            // The bomb count is a percentage of the total number
            // of cells.
            this.bombCount = Math.floor(
                (this.columnCount * this.rowCount) *
                (parseInt(bombCount) / 100)
           );
        } else {
            // The bomb count is just a standard number.
            this.bombCount = (bombCount || 15);
        }

        // Bind the click handler for the table. This way, we
        // don't have to attach event handlers to each cell.
        this.table.click(
            function(event){
                // Pass off to the table click handler.
                self.onClick(event);
                // Cancel default event.
                return(false);
            }
       );

        // Initialize the table.
        this.initTable();
    };


    // I build the actual markup of the table using the
    // given number of columns and rows.
    MineSweeper.prototype.buildTable = function(){
        // Build the markup for a given row.
        var rowHtml = ("<tr>" + duplicateContent("<td class=\"active\">&nbsp;</td>", this.columnCount) + "</tr>");

        // Build the markup for the table using the row
        // data the given number of times.
        var tableHtml = duplicateContent(rowHtml, this.rowCount);

        // Set the HTML of the table to fill it out.
        this.table.html(tableHtml);
    };


    // I check to see if an end-game has been reached.
    // If so, then I give the option to restart.
    MineSweeper.prototype.checkEndGame = function(){
        var message = "";
        var isEndGame = false;

        // Check to see if any of the bombs have exploded.
        if (this.bombCells.filter(".bomb-revealed").size()){
            // Set the message.
            message = "You LOSE - Play Again?";
            // Flag the end game.
            isEndGame = true;
        // Check to see if there are any more active
        // non-bomb cells. If not, then the user has
        // successfully clicked all non-bomb cells.
        } else if (!this.nonBombCells.filter(".active").size()){
            // Set the message.
            message = "You WIN - Play Again?";
            // Flag the end game.
            isEndGame = true;
        }

        // Check to see if the game is over.
        if (isEndGame){
            // Prompt for replay.
            if (confirm(message)){
                // Restart the game.
                this.restart();
            }

        }
    };


    // I clear the table of any markup.
    MineSweeper.prototype.clearTable = function(){
        this.table.empty();
    };


    // I initialize the table.
    MineSweeper.prototype.initTable = function(){
        var self = this;
        // Clear the table if there is any existing markup.
        this.clearTable();

        // Now that we have ensured that the table is
        // empty, let's build out the HTML for the table.
        this.buildTable();

        // Gather the cells of the table.
        this.cells = this.table.find("td");
        // Set the "near bombs" data for each cell to
        // zero. This is the number of bombs that the cell
        // is near.
        this.cells.data("nearBombs", 0);

        // For each cell, keep a collection of the cells
        // that are near this cell.
        this.cells.each(function(index, cellNode){
            var cell = $(this);

            // Store the near cells.
            cell.data("near", cell.near());
        });

        // Randomly select and gather the bomb cells.
        this.bombCells = this.cells.randomFilter(this.bombCount).addClass("bomb");

        // Now that we've selected the bomb cells, let's
        // get teh non-bomb cells.
        this.nonBombCells = this.cells.filter(
            function(index){
                // If this cell does NOT appear in the bomb
                // cells collection, then it's a non-bomb
                // cell.
                return(self.bombCells.index(this) == -1);
            }
        );
        this.cheat();

        // Now that we have the bomb cells, let's go through
        // each of them and apply its "nearness" to the
        // cells around it.
        this.bombCells.each(
            function(index, node){
                var cell = $(this);
                var nearCells = cell.data("near");

                // For each near cell, increment the near
                // data counter.
                nearCells.each(function(){
                    var nearCell = $(this);

                    // Get the current near data and
                    // increment it.
                    nearCell.data("nearBombs", (nearCell.data("nearBombs") + 1));
                });
            }
        );
    };

    // I handle the clicks at the table level.
    MineSweeper.prototype.onClick = function(event){
        // Get the trigger for the event.
        var target = $(event.target);
        // Check to make sure the target is an active cell.
        // If it is not, then we are not interested.
        if (target.is("td.active")){ 
            // Check to see if the ALT key was pressed. If it
            // was, then we are handling the caution toggle.
            // If not, then we are going to process a normal
            // click event.
            if (event.altKey){

                // Toggle the caution nature of this cell.
                this.toggleCaution(target);

            } else {

                // Check to see if the target was a bomb cell.
                if (target.hasClass("bomb")){

                    // The user clicked on a bomb, which will end
                    // the game. Reveal the whole board (end-game
                    // check comes below).
                    this.revealBoard();

                } else {

                    // The target was not a bomb, so show it.
                    this.revealCell(target);

                }

                // Check end game.
                this.checkEndGame();

            }
        }


    };


    // I restart the game.
    MineSweeper.prototype.restart = function(){
        // Re-initialize the table.
        this.initTable();
    };


    // I reveal the entire board.
    MineSweeper.prototype.revealBoard = function(){
        // Remove the transient classes.
        this.cells.removeClass("active").removeClass("caution");

        // Add the bomb-revealed classes to the bombs.
        this.bombCells.addClass("bomb-revealed");

        // Set the cell contents.
        this.cells.each(
            function(index, cellNode){
                var cell = $(this);

                // Check to see if this is a bomb cell.
                if (cell.hasClass("bomb")){

                    // Show an *.
                    cell.html("*");

                } else if (cell.data("nearBombs")){

                    // Show the count.
                    cell.html(cell.data("nearBombs"));

                }
            }
       );
    };


    // I reveal the given cell.
    MineSweeper.prototype.revealCell = function(cell){
        var self = this;

        // Remove the active nature of the cell.
        cell.removeClass("active").removeClass("caution");
        // Check to see if the current cell is near any
        // bombs. If it is, then we'll just show the
        // current cell and it's nearness. If not, then
        // we'll continue to show the surrounding cells.
        if (cell.data("nearBombs")){
            // Set the content of the cell.
            cell.html(cell.data("nearBombs"));
        } else {
            // Make sure the cell has no markup.
            cell.html("");
            // This cell was not near any bombs. Therefore,
            // it is reasonable to assume the user would
            // quickly reveal all cells around it. As such,
            // we will do that for them.
            cell.data("near").filter(".active").each(
                function(index, cellNode){
                    if(!$(this).hasClass('bomb'))
                        self.revealCell($(this));
                }
           );
        }
    };

    // Toggle a cell with the caution symbol ("?")
    MineSweeper.prototype.toggleCaution = function(cell){
        if (cell.hasClass("caution")){
            cell.removeClass("caution");
            cell.html("&nbsp;");
        } else {
            cell.addClass("caution");
            cell.html("?");
        }
    }

    // Just don't have the patience? Me neither.
    MineSweeper.prototype.cheat = function() {
        var reveal = $(this.nonBombCells.random()[0]);
        reveal.click();
    }

    function duplicateContent(content, count){
        return new Array(count + 1).join(content);
    }

    $.fn.random = function() {
        return this.eq(Math.floor(Math.random() * this.length));
    }   

    // ------------------------------------------------------ //
    // ------------------------------------------------------ //


    // Store the mine sweeper class in the window scope so
    // that people can reach it ouside of this bubble.
    window.MineSweeper = MineSweeper;

})(jQuery);

如果您遇到了Plunker的问题,因为它会弹出&#34;您赢了&#34;因为问题的原因:

按ESC键,因为第279行(问题)导致它点击所有非炸弹单元格,因此触发胜利条件。

2 个答案:

答案 0 :(得分:0)

我刚将第260行更改为$(this).revealCell();它似乎运作良好。不确定这是不是你想要的,但我想是的。

答案 1 :(得分:0)

终于找到了问题所在。当我使用this.cheat时,cell.data("nearBombs")始终为零。所以我的猜测是你在附加数据之前调用了this.cheat

所以我将this.cheat()移到第155行,一切运作良好。