Last active
July 24, 2017 07:59
-
-
Save inDream/c622bb3ff5d36cfd832296278d82a945 to your computer and use it in GitHub Desktop.
Minesweeper ( modified from http://slicker.me/javascript/minesweeper/minesweeper.htm )
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | |
<style> | |
body { | |
font-family: "Segoe UI", Helvetica, Arial, sans-serif; | |
text-align: center; | |
} | |
input[type="number"] { | |
width: 50px; | |
} | |
#container { | |
margin: 0 auto; | |
line-height: 0; | |
} | |
#container div { | |
height: 30px; | |
width: 30px; | |
background: #ccc; | |
display: inline-block; | |
border: 1px solid #000; | |
} | |
#container div:after { | |
position: absolute; | |
font-size: 25px; | |
margin: 14px -12px; | |
} | |
.covered { | |
background: #888 !important; | |
} | |
.uncovered:after { | |
margin: 14px -6px !important; | |
content: attr(data-content); | |
} | |
.flag:after { | |
content: '🚩'; | |
} | |
.question:after { | |
content: '❓'; | |
} | |
.mine:after { | |
content: '💣'; | |
} | |
.incorrect:after { | |
content: '❌'; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>Minesweeper</h1> | |
<br><br><br> | |
<label>Mines: <input id="minesVal" type="number" value="10" /></label> | |
<label>Rows: <input id="rowsVal" type="number" value="8" /></label> | |
<label>Columns: <input id="columnsVal" type="number" value="8" /></label> | |
<pre id="message" onclick="init()"></pre> | |
<div id="container" oncontextmenu="return false;"></div> | |
<script> | |
var width = 30; | |
var border = 1; | |
var mines, rows, columns, remaining, revealed; | |
var tile = []; | |
var board = []; | |
// this function returns the value of the tile using the (x1,y1) coordinates. (0,0) is in the upper left corner. | |
function check(x1, y1) { | |
if ((x1 >= 0) && (y1 >= 0) && (x1 < columns) && (y1 < rows)) //Verify if coordinates do not fall outside of the board. | |
return board[x1 + y1 * columns]; | |
} | |
// This function returns the classname of the tile (uncovered/flag/question mark). | |
function getType(index) { | |
return tile[index].className; | |
} | |
var dir = [[0, 1], [-1, 1], [1, 1], [0, -1], [-1, -1], [1, -1], [-1, 0], [1, 0]]; | |
function loop(x, y, cb) { | |
var acc = 0; | |
dir.forEach(function(e, i) { | |
var v = check(x + e[0], y + e[1]); | |
if (v !== undefined) { | |
acc += cb(v, x + e[0], y + e[1]); | |
} | |
}); | |
return acc; | |
} | |
function init() { | |
message.textContent = 'Click on the tiles to reveal them\nClick here to reset'; | |
// Set the number of mines and the size of the board. | |
mines = minesVal.value; | |
rows = rowsVal.value; | |
columns = columnsVal.value; | |
remaining = mines; | |
revealed = 0; // The number of revealed tiles. | |
board = []; // Reset mine in previous round | |
// Create the tiles. | |
container.style.width = columns * (width + border * 2) + 'px'; | |
var fragment = document.createDocumentFragment(); | |
for (var i = 0; i < rows * columns; i++) { | |
tile[i] = document.createElement('div'); | |
tile[i].className = 'covered'; | |
tile[i].addEventListener('mousedown', click); // Function 'click' will be executed when player clicks on a tile. | |
tile[i].id = i; // The id of the tile is its index. | |
fragment.appendChild(tile[i]); // Add the tile to the DOM. | |
} | |
container.innerHTML = ''; | |
container.appendChild(fragment); | |
// Place the mines: | |
var placed = 0; | |
while (placed < mines) { | |
i = Math.floor(Math.random() * columns * rows); // Select a random tile. | |
// Make sure the tile doesn't already have a mine. | |
if (board[i] != 'mine') { | |
board[i] = 'mine'; // Set the mine | |
placed++; // and increase the count. | |
} | |
} | |
for (var x = 0; x < columns; x++) { | |
for (var y = 0; y < rows + 1; y++) { | |
// if the cell is not a mine: | |
if (check(x, y) != 'mine') { | |
board[x + y * columns] = loop(x, y, function(v) { | |
return +(v === 'mine'); | |
}); | |
} | |
} | |
} | |
} | |
function handleLeftClick(id, tileType) { | |
// if the tile is a mine: | |
if (board[id] == 'mine') { | |
for (var i = 0; i < rows * columns; i++) { | |
if (board[i] == 'mine') tile[i].className = 'mine'; // show all the mines, | |
if (board[i] != 'mine' && getType(i) == 'flag') tile[i].className = 'incorrect'; // show a strike-through mine where flags were placed incorrectly. | |
} | |
message.textContent = 'GAME OVER\nClick here to restart'; | |
} else if (tileType == 'covered') { | |
// otherwise reveal the tile. | |
reveal(id); | |
} | |
} | |
function handleRightClick(id, tileType) { | |
switch (tileType) { | |
case 'covered': // If the tile is uncovered, set a flag. | |
if (remaining) { | |
tile[id].className = 'flag'; | |
remaining--; | |
} | |
break; | |
case 'flag': // If it's a flag, set a question mark. | |
tile[id].className = 'question'; | |
remaining++; | |
break; | |
case 'question': // If it's a question mark, set it to uncovered. | |
tile[id].className = 'covered'; | |
break; | |
} | |
// Update the count of remaining mines. | |
message.textContent = "Mines remaining: " + remaining; | |
} | |
function click(event) { | |
var id = event.target.id; // The ID of the tile clicked by user. | |
var tileType = getType(id); | |
if (event.which == 1) { // On left click: | |
handleLeftClick(id, tileType); | |
} else if (event.which == 3) { // On right click: | |
event.preventDefault(); | |
handleRightClick(id, tileType); | |
} | |
// If all tiles revealed: | |
if (revealed == rows * columns - mines) { | |
message.textContent = 'YOU WIN!\nClick here to restart'; | |
} | |
} | |
// Uncover the tile | |
function reveal(index) { | |
if (tile[index].dataset.revealed) { | |
return; | |
} | |
// If it's covered and not a mine: | |
if (board[index] != 'mine' && getType(index) == 'covered') { | |
revealed++; // If it was uncovered, increase the count of revealed tiles. | |
} | |
tile[index].className = 'uncovered'; | |
tile[index].dataset.revealed = 1; | |
tile[index].dataset.content = board[index] || ''; // Uncover the tile. | |
var x = index % columns; // Convert index into (x,y) coordinates. | |
var y = Math.floor(index / columns); | |
// Reveal all the neighboring tiles: | |
loop(x, y, function(v, x, y) { | |
if (v === 0) { | |
loop(x, y, function(v, x, y) { | |
reveal(x + y * columns); | |
}); | |
} else if (v === 1) { | |
reveal(x + y * columns); | |
} | |
}); | |
} | |
init(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment