I have written Minesweeper in JavaScript. Using OO-Approach.
Cell
class describes a cell in the grid.
Cell.t
property tells whether the cell is a mine or not.
Cell.count
property stores the number of mines in the cell's vicinity.
Cell.state
property stores whether the cell is used / unused / flagged.
Grid
class provides an abstraction from the game's flow.
My main concerns are Grid.init
and Grid.click
functions.
Grid.init
assigns the number of mines in a cell's vicinity to Cell.count
.
Grid.click
recursively clears out the neighbor cells (without mines) when a cell is clicked.
The conditions in Grid.init
and Grid.click
seem quite redundant. Is there any way to fix that? Is there any other change that I should make to improve the code.
function Cell(type) {
if (!(this instanceof Cell)) {
throw new Error("Invalid call to constructor");
}
this.t = type;
this.count = 0;
this.state = 1;
}
function Grid(length, width, mines) {
var i, j, rc, rr;
if (!(this instanceof Grid)) {
throw new Error("Invalid call to constructor");
}
this.l = length;
this.w = width;
this.m = mines;
this.grid = [];
for (i = 0; i < this.l; i += 1) {
this.grid.push([]);
for (j = 0; j < this.w; j += 1) {
this.grid[i].push(new Cell("n"));
}
}
for (i = 0; i < this.m; i += 1) {
rr = parseInt(Math.random() * this.l);
rc = parseInt(Math.random() * this.w);
if (this.grid[rr][rc].t === "n") {
this.grid[rr][rc].t = "m";
} else {
i -= 1;
}
}
}
Grid.prototype.init = function() {
var i, j, n;
for (i = 0; i < this.l; i += 1) {
for (j = 0; j < this.w; j += 1) {
n = 0;
if (i - 1 >= 0 && j - 1 >= 0 && this.grid[i - 1][j - 1].t === "m") {
n += 1;
}
if (j - 1 >= 0 && this.grid[i][j - 1].t === "m") {
n += 1;
}
if (i + 1 < this.l && j - 1 >= 0 && this.grid[i + 1][j - 1].t === "m") {
n += 1;
}
if (i - 1 >= 0 && this.grid[i - 1][j].t === "m") {
n += 1;
}
if (i + 1 < this.l && this.grid[i + 1][j].t === "m") {
n += 1;
}
if (i - 1 >= 0 && j + 1 < this.w && this.grid[i - 1][j + 1].t === "m") {
n += 1;
}
if (j + 1 < this.w && this.grid[i][j + 1].t === "m") {
n += 1;
}
if (i + 1 < this.l && j + 1 < this.w && this.grid[i + 1][j + 1].t === "m") {
n += 1;
}
this.grid[i][j].count = n;
}
}
};
Grid.prototype.click = function(i, j) {
this.grid[i][j].state = 0;
if (this.grid[i][j].t === "m") {
return 0;
}
if (this.grid[i][j].count === 0) {
if (i - 1 >= 0 && j - 1 >= 0 && this.grid[i - 1][j - 1].state === 1) {
this.click(i - 1, j - 1);
}
if (j - 1 >= 0 && this.grid[i][j - 1].state === 1) {
this.click(i, j - 1);
}
if (i + 1 < this.l && j - 1 >= 0 && this.grid[i + 1][j - 1].state === 1) {
this.click(i + 1, j - 1);
}
if (i - 1 >= 0 && this.grid[i - 1][j].state === 1) {
this.click(i - 1, j);
}
if (i + 1 < this.l && this.grid[i + 1][j].state === 1) {
this.click(i + 1, j);
}
if (i - 1 >= 0 && j + 1 < this.w && this.grid[i - 1][j + 1].state === 1) {
this.click(i - 1, j + 1);
}
if (j + 1 < this.w && this.grid[i][j + 1].state === 1) {
this.click(i, j + 1);
}
if (i + 1 < this.l && j + 1 < this.w && this.grid[i + 1][j + 1].state === 1) {
this.click(i + 1, j + 1);
}
}
return this.check();
};
Grid.prototype.check = function() {
var i, j;
for (i = 0; i < this.l; i += 1) {
for (j = 0; j < this.w; j += 1) {
if (this.grid[i][j].t === "n" && this.grid[i][j].state) {
return 1;
}
}
}
return 2;
};
Note: I haven't provided the code which links these functions as event handlers to forms controls.