I am looking for some review of a Minesweeper game that I made as my first JavaScript program. What I have here is simply the prototype for the minesweeper game while I handle the actual grid in a separate section, and I could care less about that. I'm just looking for a few pointers in the right direction in case I am using any bad practices.
As for the game itself, I store two 2D arrays. board
is a 2D array I use to keep track of what values the hidden tiles have, 0-9 being the number of adjacent mines and 9 being a mine itself. visibleBoard
is the tiles that the player can see, and it uses the same values as board
except an additional value of 10 being a tile that is still hidden.
"use strict";
//Javascript Prototype for a Minesweeper Game Object
function MinesweeperGame(rows = 8, cols = 8, mines = 10) {
//Initialize Game State Variables
this.rows = rows;
this.cols = cols;
this.mines = mines;
this.gameover = false;
this.score = 0;
this.board = null;
this.visibleBoard = null;
this.initBoard = function() {
this.board = [];
this.visibleBoard = [];
this.gameover = false;
//If the tile is inside the boundaries of the board and is not a bomb, increment by 1
function increment(r, c, board) {
if(typeof board[r] !== "undefined" && typeof board[r][c] !== "undefined" && board[r][c] != 9) {
board[r][c]++;
}
}
//initializes the board with 0s and the visibleBoard with 10s
for(var i = 0; i < this.rows; i++) {
var arr1 = [];
var arr2 = [];
for(var j = 0; j < this.cols; j++) {
arr1.push(0);
arr2.push(10);
}
this.board.push(arr1);
this.visibleBoard.push(arr2);
}
//Retrieve all squares in the board
var squares = []
for(i = 0; i < this.rows * this.cols; i++) {
squares.push(i);
}
//Place bombs in a few squares
for(i = 0; i < this.mines; i++) {
var sq = squares.splice(Math.floor(Math.random() * squares.length), 1)[0];
var r = Math.floor(sq / this.cols);
var c = sq % this.cols;
this.board[r][c] = 9;
}
//Increment all tiles adjacent to bombs
for(var r = 0; r < this.rows; r++) {
for(var c = 0; c < this.cols; c++) {
//If a board sqaure is a bomb
if(this.board[r][c] == 9){
//Add 1 to all non-bomb adjacent tiles
increment(r - 1, c - 1, this.board);
increment(r - 1, c, this.board);
increment(r - 1, c + 1, this.board);
increment(r, c - 1, this.board);
increment(r, c + 1, this.board);
increment(r + 1, c - 1, this.board);
increment(r + 1, c, this.board);
increment(r + 1, c + 1, this.board);
}
}
}
},
this.makeMove = function(row, col) {
if(this.gameover) {
throw 'Game Over';
}
//If you choose an empty space, it flood fills out the rest of the empty squares
function flood(r, c, board, visibleBoard) {
if(typeof visibleBoard[r] !== "undefined" && typeof visibleBoard[r][c] !== "undefined" && visibleBoard[r][c] == 10) {
if(board[r][c] == 0) {
visibleBoard[r][c] = 0;
flood(r - 1, c - 1, board, visibleBoard);
flood(r - 1, c, board, visibleBoard);
flood(r - 1, c + 1, board, visibleBoard);
flood(r, c + 1, board, visibleBoard);
flood(r, c - 1, board, visibleBoard);
flood(r + 1, c - 1, board, visibleBoard);
flood(r + 1, c, board, visibleBoard);
flood(r + 1, c + 1, board, visibleBoard);
} else {
visibleBoard[r][c] = board[r][c]
}
}
}
//Will update the gameover variable if the user wins the game
function checkGameOver(visibleBoard) {
var count = 0;
for(var r = 0; r < rows; r++) {
for(var c = 0; c < cols; c++) {
if(visibleBoard[r][c] == 10) {
count++;
}
}
}
return count == mines;
}
//Updates the visible board
if(this.visibleBoard[row][col] == 10) {
var val = this.board[row][col];
if(val == 9) {
this.gameover = true;
this.visibleBoard[row][col] = 9;
return 10;
} else if(val > 0 && val < 9) {
this.visibleBoard[row][col] = val;
this.gameover = checkGameOver(this.visibleBoard);
return val;
} else if(val == 0) {
flood(row, col, this.board, this.visibleBoard);
this.gameover = checkGameOver(this.visibleBoard);
return 0;
}
} else {
throw 'Invalid Tile';
}
}
}
Primary Concerns:
- Nested functions (e.g.
increment
,flood
, andcheckGameOver
) - Appropriate use of variable scopes (I feel like I use
this
too often) - Efficient implementation of algorithms
- Should I break some functionality down more or less?
- Is there a better way to place down mines?