Last active
February 3, 2022 15:37
-
-
Save tinarskii/0554d5e24bd19735dd2b9e65c4b0d097 to your computer and use it in GitHub Desktop.
Simple MineSweeper Game
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
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