我试图为扫雷游戏实施作弊功能,揭示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\"> </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(" ");
} 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行(问题)导致它点击所有非炸弹单元格,因此触发胜利条件。
答案 0 :(得分:0)
我刚将第260行更改为$(this).revealCell();它似乎运作良好。不确定这是不是你想要的,但我想是的。
答案 1 :(得分:0)
终于找到了问题所在。当我使用this.cheat
时,cell.data("nearBombs")
始终为零。所以我的猜测是你在附加数据之前调用了this.cheat
。
所以我将this.cheat()
移到第155行,一切运作良好。