Last active
December 12, 2016 21:25
-
-
Save Prajjwal/9063b16f7124e7acf064fa43aecf4996 to your computer and use it in GitHub Desktop.
Canvas Minesweeper I wrote back in 2012.
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"> | |
<title>Canvas Minesweeper</title> | |
<style type="text/css"> | |
#container { width: 1250px; margin: 0 auto } | |
</style> | |
</head> | |
<body> | |
<script type="text/javascript" src="mines.js"></script> | |
<p>'n' starts a new game</p> | |
</body> | |
</html> |
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
(function (undefined) { | |
var d = document, | |
canvas = d.body.appendChild(d.createElement('canvas')), | |
c = canvas.getContext('2d'), | |
mf, | |
openCount, | |
marked, | |
isOpen, | |
colors = ['yellow', '#00f', 'green', 'red', 'blue', 'magenta', 'red', 'red', 'red', 'black']; | |
// Set canvas height and width | |
canvas.height = 700; | |
canvas.width = 1250; | |
c.font = '20px serif'; | |
addEventListener('contextmenu', function (e) { e.preventDefault(); }); | |
addEventListener('keypress', handleKeypress, false); | |
function build2dArray(rows, cols) { | |
// Constructs a 2d array | |
var arr = []; | |
for (var i = 0; i < rows; i++) | |
arr[i] = []; | |
return arr; | |
} | |
function getRandomInt(x, y) { | |
// Return random int in the range [x, y] | |
return Math.floor(Math.random() * (y - x + 1)) + x; | |
} | |
function surroundingCells(row, col) { | |
// Return the coords of all cells surrounding a cell | |
// eg surroundingCells(0, 0) should return [[0, 1], [1, 0] [1, 1]] | |
return [[row, col - 1], [row, col + 1], | |
[row - 1, col - 1], [row - 1, col], [row - 1, col + 1], | |
[row + 1, col - 1], [row + 1, col], [row + 1, col + 1]] | |
.filter(function (coords) { | |
return (coords[0] >= 0 && coords[0] < 16) && (coords[1] >= 0 && coords[1] < 30) | |
}); | |
} | |
function countSurroundingMines(row, col, x) { | |
var surrounding = surroundingCells(row, col), | |
surroundingCellCount = surrounding.length, | |
mines = 0; | |
for(var i = 0; i < surroundingCellCount; i++) { | |
if (x[surrounding[i][0]][surrounding[i][1]] === 9) { | |
mines++; | |
} | |
} | |
return mines; | |
} | |
function generateMinefield(rows, cols, mines, avoidRow, avoidCol) { | |
var x = build2dArray(rows, cols); | |
// Fill array with given number of mines | |
for(var i = 0; i < mines; i++) { | |
var col = getRandomInt(0, 29), | |
row = getRandomInt(0, 15); | |
if (x[row][col] || (row === avoidRow && col === avoidCol)) { | |
// Retry if it already is a mine or is the tile the user clicked on the first try | |
i--; | |
} else { | |
x[row][col] = 9; | |
} | |
} | |
// Fill in rest of array | |
for(var i = 0; i < rows; i++) { | |
for(var j = 0; j < cols; j++) { | |
if (x[i][j] !== 9) { | |
x[i][j] = countSurroundingMines(i, j, x); | |
} | |
} | |
} | |
return x; | |
} | |
function drawMinefield() { | |
// Draws minefield of a given size on the canvas | |
var left = 20, | |
top = 20; | |
// Original Color of Tiles | |
c.fillStyle = 'red'; | |
for (var i = 0; i < 16; i++) { | |
for (var j = 0; j < 30; j++) { | |
c.fillRect(left, top, 40, 40); | |
left += 41; | |
} | |
left = 20; | |
top += 41; | |
} | |
} | |
function openTile(row, col) { | |
// Clear Tile | |
var x = col * 41 + 20, | |
y = row * 41 + 20; | |
// Draw underlying number | |
if (!marked[row][col] && !isOpen[row][col]) { | |
c.clearRect(x, y, 40, 40); | |
if (mf[row][col] === 9) { | |
// If it is a mine | |
gameOver(false); | |
} else { | |
isOpen[row][col] = 1; | |
c.fillStyle = colors[mf[row][col]]; | |
if (mf[row][col] === 0) | |
openMultipleTiles(surroundingCells(row, col)); | |
else | |
c.fillText(mf[row][col].toString(), col * 41 + 33, row * 41 + 48); | |
openCount++; | |
if(openCount === (16 * 30) - 99) { gameOver(true) } | |
} | |
} | |
} | |
function openMultipleTiles(tiles) { | |
for(var i = 0; i < tiles.length; i++) { | |
openTile(tiles[i][0], tiles[i][1]); | |
} | |
} | |
function markTile(row, col) { | |
if (isOpen[row][col] === undefined) { | |
if (marked[row][col]) { | |
// Unmark if already marked | |
c.fillStyle = 'red'; | |
marked[row][col] = 0; | |
} else { | |
// Mark | |
c.fillStyle = 'blue'; | |
marked[row][col] = 1; | |
} | |
c.fillRect(col * 41 + 20, row * 41 + 20, 40, 40); | |
} | |
} | |
function showAllMines() { | |
for(var i = 0; i < 16; i++) { | |
for(var j = 0; j < 30; j++) { | |
if (!isOpen[i][j] && mf[i][j] === 9) { | |
c.fillStyle = colors[mf[i][j]]; | |
c.fillRect(j * 41 + 20, i * 41 + 20, 40, 40); | |
} | |
} | |
} | |
} | |
function firstClick(e) { | |
canvas.removeEventListener('mouseup', firstClick, true); | |
canvas.addEventListener('mouseup', handleClick, true); | |
mf = generateMinefield(16, 30, 99, Math.floor((e.layerY - 30) / 41), Math.floor((e.layerX - 30) / 41)) | |
handleClick(e); | |
} | |
function handleClick(e) { | |
/* Decides what to do when tile is clicked */ | |
var col = Math.floor((e.layerX - 30) / 41); | |
var row = Math.floor((e.layerY - 30) / 41); | |
if ((e.buttons === 1 || e.button === 0)) { | |
// Left Click | |
openTile(row, col); | |
} else { | |
// Any other click is to be treated as a right click | |
markTile(row, col); | |
} | |
return false; | |
} | |
function handleKeypress(e) { | |
if(e.charCode === 110) { | |
newGame(); | |
} | |
} | |
function gameOver(won) { | |
showAllMines(); | |
canvas.removeEventListener('mouseup', handleClick, true); | |
} | |
function newGame() { | |
canvas.addEventListener('mouseup', firstClick, true); | |
marked = build2dArray(16, 30); | |
isOpen = build2dArray(16, 30); | |
openCount = 0; | |
drawMinefield(); | |
} | |
newGame(); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment