Skip to content

Instantly share code, notes, and snippets.

@phuctvt
Last active January 30, 2020 09:34
Show Gist options
  • Save phuctvt/5491af7c5f1187547450504d05e41eb7 to your computer and use it in GitHub Desktop.
Save phuctvt/5491af7c5f1187547450504d05e41eb7 to your computer and use it in GitHub Desktop.
Minesweeper
function Board(size) {
this.x = 0;
this.y = 0;
this.offset = 5;
this.size = size;
this.cells = [];
this.numOfCells = 10;
this.cellSize = this.size / this.numOfCells;
this.numOfBombCells = 10;
this.setup = function() {
for (var i = 0; i < this.numOfCells; i++) {
let rowOfCells = [];
for (var j = 0; j < this.numOfCells; j++) {
rowOfCells.push(new Cell(
i * this.cellSize + this.offset,
j * this.cellSize + this.offset,
this.cellSize
));
}
this.cells.push(rowOfCells);
}
this.randomBombs();
this.generateValuesAroundBombs();
}
this.draw = function(ctx) {
ctx.save();
ctx.fillStyle = 'gray';
ctx.fillRect(this.offset, this.offset, this.size, this.size);
for (var i = 0; i < this.numOfCells; i++) {
for (var j = 0; j < this.numOfCells; j++) {
this.cells[i][j].draw(ctx);
}
}
ctx.restore();
}
this.randomBombs = function() {
let options = [];
for (var i = 0; i < this.numOfCells; i++) {
for (var j = 0; j < this.numOfCells; j++) {
options.push([i, j]);
}
}
for (var i = 0; i < this.numOfBombCells; i++) {
let index = random(0, options.length - 1);
let choice = options[index];
let cell = this.cells[choice[0]][choice[1]];
cell.value = cell.BombValue;
options.splice(index, 1);
}
}
this.generateValuesAroundBombs = function() {
for (var i = 0; i < this.numOfCells; i++) {
for (var j = 0; j < this.numOfCells; j++) {
let cell = this.cells[i][j];
if (cell.isBomb()) {
continue;
}
cell.value = this.countBombAround(i, j);
}
}
}
this.countBombAround = function(_i, _j) {
let count = 0;
for (var i = -1; i <= 1; i++) {
for (var j = -1; j <= 1; j++) {
if (
(i === 0 && j === 0) ||
i + _i < 0 || j + _j < 0 ||
i + _i >= this.numOfCells ||
j + _j >= this.numOfCells
) continue;
let cell = this.cells[_i + i][_j + j];
if (cell.isBomb()) {
count++;
}
}
}
return count;
}
this.isInBoard = function(mouseX, mouseY) {
return this.offset <= mouseX &&
this.offset <= mouseY &&
mouseX < this.offset + size &&
mouseY < this.offset + size;
}
this.onClick = function(mouseX, mouseY) {
if (this.isInBoard(mouseX, mouseY)) {
let i = Math.floor(mouseX / (this.size / this.numOfCells));
let j = Math.floor(mouseY / (this.size / this.numOfCells));
let cell = this.cells[i][j];
if (cell.marked) return;
cell.revealed = true;
if (cell.isBomb()) {
setTimeout(() => alert('Game over!!'), 100);
}
if (cell.value === 0) {
this.dominoRevealEmpty(i, j);
}
if (this.numofRevealed() === this.numOfCells * this.numOfCells - this.numOfBombCells) {
setTimeout(() => alert('WIN!!'), 100);
}
}
}
this.numofRevealed = function() {
let count = 0;
for (var i = 0; i < this.numOfCells; i++) {
for (var j = 0; j < this.numOfCells; j++) {
let cell = this.cells[i][j];
if (cell.revealed) {
count++;
}
}
}
return count;
}
this.dominoRevealEmpty = function(_i, _j) {
for (var i = -1; i <= 1; i++) {
for (var j = -1; j <= 1; j++) {
if (
(i === 0 && j === 0) ||
i + _i < 0 || j + _j < 0 ||
i + _i >= this.numOfCells ||
j + _j >= this.numOfCells
) continue;
let cell = this.cells[_i + i][_j + j];
if (cell.revealed) continue;
cell.revealed = true;
if (cell.value === 0) {
this.dominoRevealEmpty(_i + i, _j + j);
}
}
}
}
this.onRightClick = function(mouseX, mouseY) {
if (this.isInBoard(mouseX, mouseY)) {
let i = Math.floor(mouseX / (this.size / this.numOfCells));
let j = Math.floor(mouseY / (this.size / this.numOfCells));
let cell = this.cells[i][j];
if (!cell.revealed) {
cell.marked = !cell.marked;
}
}
}
}
function Cell(x, y, size) {
this.x = x;
this.y = y;
this.size = size;
this.revealed = false;
this.BombValue = 'Bomb';
this.value;
this.marked = false;
this.draw = function(ctx) {
ctx.save();
if (this.revealed) {
ctx.fillStyle = 'lightgray';
ctx.fillRect(this.x, this.y, this.size, this.size);
if (this.value === this.BombValue) {
ctx.fillStyle = 'red';
ctx.textAlign = 'center';
ctx.font = '30px sans';
ctx.fillText('B', this.x + 20, this.y + 30);
} else if (this.value > 0) {
ctx.fillStyle = 'black';
ctx.textAlign = 'center';
ctx.font = '30px sans';
ctx.fillText(this.value, this.x + 20, this.y + 30);
}
} else if (this.marked) {
ctx.beginPath();
ctx.arc(this.size / 2 + this.x, this.size / 2 + this.y, 10, 0, Math.PI * 2);
ctx.fillStyle = 'orange';
ctx.fill();
}
ctx.strokeStyle = 'black';
ctx.strokeRect(this.x, this.y, this.size, this.size);
ctx.restore();
}
this.isBomb = function() {
return this.value === this.BombValue;
}
}
<!DOCTYPE html>
<html>
<head>
<title>Minesweeper</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<canvas id="canvas"></canvas>
<script type="text/javascript" src="tool.js"></script>
<script type="text/javascript" src="cell.js"></script>
<script type="text/javascript" src="board.js"></script>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
let c, ctx, board;
const width = 500;
const height = 500;
const boardSize = 400;
function setup() {
c = document.querySelector('#canvas');
c.width = width;
c.height = height;
ctx = c.getContext('2d');
board = new Board(boardSize);
board.setup();
c.onclick = (e) => board.onClick(e.offsetX, e.offsetY);
c.onmousedown = (e) => {
if (e.which === 3) {
board.onRightClick(e.offsetX, e.offsetY);
}
}
c.oncontextmenu = () => { return false; }
}
function draw() {
board.draw(ctx);
window.requestAnimationFrame(draw);
}
setup();
window.requestAnimationFrame(draw);
canvas {
/*border: 5px solid;*/
}
function random(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment