Skip to content

Instantly share code, notes, and snippets.

@tinarskii
Last active February 3, 2022 15:37
Show Gist options
  • Save tinarskii/0554d5e24bd19735dd2b9e65c4b0d097 to your computer and use it in GitHub Desktop.
Save tinarskii/0554d5e24bd19735dd2b9e65c4b0d097 to your computer and use it in GitHub Desktop.
Simple MineSweeper Game
class Cell {
constructor (x, y) {
this.x = x;
this.y = y;
this.isMine = false;
this.isFlagged = false;
this.isRevealed = false;
this.neighborMines = 0;
}
}
class MineSweeper {
constructor (rows, cols, mines) {
this.rows = rows;
this.cols = cols;
this.mines = mines;
this.board = this.createBoard();
this.gameOver = false;
this.startTime = null;
this.endTime = null;
this.placeMines();
this.setNeighborsMineCount();
}
createBoard () {
let board = [];
for (let i = 0; i < this.rows; i ++) {
board.push([]);
for (let j = 0; j < this.cols; j ++) {
board[i].push(new Cell(i, j));
}
}
return board;
}
placeMines () {
if (this.mines > this.rows * this.cols) {
this.mines = this.rows * this.cols;
}
let minesPlaced = 0;
while (minesPlaced < this.mines) {
let randomRow = Math.floor(Math.random() * this.rows);
let randomCol = Math.floor(Math.random() * this.cols);
if (!this.board[randomRow][randomCol].isMine) {
this.board[randomRow][randomCol].isMine = true;
minesPlaced ++;
}
}
}
setNeighborsMineCount () {
for (let i = 0; i < this.rows; i ++) {
for (let j = 0; j < this.cols; j ++) {
let cell = this.board[i][j];
if (cell.isMine) {
continue;
}
let neighbors = this.getNeighbors(cell);
let neighborMines = 0;
for (let neighbor of neighbors) {
if (neighbor.isMine) {
neighborMines ++;
}
}
cell.neighborMines = neighborMines;
}
}
}
getNeighbors (cell) {
let neighbors = [];
let row = cell.x;
let col = cell.y;
for (let i = row - 1; i <= row + 1; i ++) {
for (let j = col - 1; j <= col + 1; j ++) {
if (i < 0 || i >= this.rows || j < 0 || j >= this.cols) {
continue;
}
if (i === row && j === col) {
continue;
}
neighbors.push(this.board[i][j]);
}
}
return neighbors;
}
printBoard () {
for (let i = 0; i < this.rows; i ++) {
let row = '';
for (let j = 0; j < this.cols; j ++) {
let cell = this.board[i][j];
if (cell.isRevealed) {
if (cell.isMine) {
row += '* ';
} else {
row += cell.neighborMines + ' ';
}
} else if (cell.isFlagged && !this.gameOver) {
row += 'F ';
} else if (this.gameOver) {
if (cell.isMine && cell.isFlagged) {
row += 'X ';
} else if (cell.isMine) {
row += '* ';
} else {
row += '- ';
}
} else {
row += '? ';
}
}
console.log(row);
}
}
revealCell (cell) {
if (this.gameOver) {
return;
}
if (cell.isMine) {
this.endTime = new Date().getTime();
this.gameOver = true;
cell.isRevealed = true;
console.log('Game over!');
console.log('Play time: %s', this.getPlayTime());
return;
}
if (cell.neighborMines === 0) {
let neighbors = this.getNeighbors(cell);
for (let neighbor of neighbors) {
if (!neighbor.isRevealed) {
neighbor.isRevealed = true;
this.revealCell(neighbor);
}
}
}
cell.isRevealed = true;
if (this.isGameWon()) {
this.endTime = new Date().getTime();
this.gameOver = true;
this.printBoard();
console.log('You won!');
console.log('Play time: %s', this.getPlayTime());
}
}
isGameWon () {
for (let i = 0; i < this.rows; i ++) {
for (let j = 0; j < this.cols; j ++) {
if (!this.board[i][j].isRevealed && !this.board[i][j].isMine) {
return false;
}
}
}
return true;
}
flagCell (cell) {
if (this.gameOver) {
return;
}
if (cell.isRevealed) {
return;
}
cell.isFlagged = !cell.isFlagged;
}
startGame () {
this.startTime = new Date().getTime();
this.gameOver = false;
const prompt = require('prompt-sync')();
console.log('Welcome to Minesweeper!');
console.log('(Type \'q\' to quit.)');
this.printBoard();
while (!this.gameOver) {
let [row, col] = prompt(`Enter row and col (Split by spaces): `)
.split(' ');
let isFlag = prompt('Is this a flag? (y/n):') === 'y';
if (row === 'q' || col === 'q') {
break;
}
if (col <= 0 || col > this.cols || row <= 0 || row > this.rows) {
console.log('Invalid row or col!');
break;
}
if (!row || !col) {
continue;
}
let cell = this.board[row - 1][col - 1];
if (cell.isRevealed) {
console.log('Cell already revealed!');
continue;
}
if (isFlag) {
this.flagCell(cell);
} else {
if (cell.isFlagged) {
this.flagCell(cell);
} else {
this.revealCell(cell);
}
}
this.printBoard();
}
}
getPlayTime () {
const moment = require('moment');
return moment.duration(this.endTime - this.startTime, 'milliseconds')
.humanize();
}
}
new MineSweeper(5, 5, 5).startGame();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment