A Minesweeper Clone in JavaScript

The JavaScript code below implements a simple clone of the classic Windows game Minesweeper. To see it in action, copy it into an .html file, and open that file in a web browser that runs JavaScript. Or you can play an online version by visiting http://thiscouldbebetter.neocities.org/minesweeper.html.

Minesweeper

<html>
<body>
<script type='text/javascript'>

// main

function Minesweeper()
{
	this.main = function()
	{
		var field0 = new Field
		(
			new Coords(10, 10), // sizeInCells
			10 // numberOfMines	
		);

		Globals.Instance.initialize
		(
			field0
		);
	}
}

// classes

function Coords(x, y)
{
	this.x = x;
	this.y = y;
}
{
	Coords.prototype.clone = function()
	{
		return new Coords(this.x, this.y);
	}

	Coords.prototype.isWithinRange = function(range)
	{
		var returnValue = 
		(
			this.x >= 0
			&& this.x < range.x
			&& this.y >= 0
			&& this.y < range.y
		);

		return returnValue;
	}
}

function Field(sizeInCells, numberOfMines)
{
	this.sizeInCells = sizeInCells;
	this.numberOfMines = numberOfMines;
	this.numberOfCellsHidden = this.sizeInCells.x * this.sizeInCells.y;

	this.buildCells();
}
{
	// static methods

	Field.buttonCellClicked = function(event)
	{
		var buttonForCell = event.target
		var cellPos = buttonForCell.cellPos;
		var field = Globals.Instance.field;
		var cell = field.getCellAtPos(cellPos);

		if (cell.isMinePresent == true)
		{
			buttonForCell.innerHTML = "!";
			alert("You clicked on a mine!  You lose!");
		}		
		else if (cell.isHidden == true)
		{
			cell.isHidden = false;
			buttonForCell.innerHTML = cell.numberOfMinesInNeighbors;
			field.numberOfCellsHidden--;

			if (field.numberOfCellsHidden == field.numberOfMines)
			{
				alert("You found all the mines!  You win!");
			}			
		}
	}

	// instance methods

	Field.prototype.buildCells = function()
	{
		this.cells = [];

		var cellPos = new Coords(0, 0);

		for (var y = 0; y < this.sizeInCells.y; y++)
		{
			cellPos.y = y;

			for (var x = 0; x < this.sizeInCells.x; x++)
			{
				cellPos.x = x;

				var cellToSet = new FieldCell();
				cellToSet.isHidden = true;
				cellToSet.isMinePresent = false;

				this.setCellAtPos(cellPos, cellToSet);
			}
		}

		var numberOfMinesPlaced = 0;

		while (numberOfMinesPlaced < this.numberOfMines)
		{
			var posRandom = new Coords
			(
				Math.floor(this.sizeInCells.x * Math.random()),
				Math.floor(this.sizeInCells.y * Math.random())
			);

			var cellAtPosRandom = this.getCellAtPos(posRandom);

			if (cellAtPosRandom.isMinePresent == false)
			{
				cellAtPosRandom.isMinePresent = true;
				numberOfMinesPlaced++;
			}
		}

		for (var y = 0; y < this.sizeInCells.y; y++)
		{
			cellPos.y = y;

			for (var x = 0; x < this.sizeInCells.x; x++)
			{
				cellPos.x = x;

				var cellAtPos = this.getCellAtPos(cellPos);
				if (cellAtPos.isMinePresent == false)
				{
					cellAtPos.numberOfMinesInNeighbors = 0;
					var neighborPos = new Coords(0, 0);

					for (var j = -1; j <= 1; j++)
					{
						neighborPos.y = cellPos.y + j;

						for (var i = -1; i <= 1; i++)
						{
							neighborPos.x = cellPos.x + i;

							if (neighborPos.isWithinRange(this.sizeInCells) == true)
							{
								var neighborCell = this.getCellAtPos(neighborPos);

								if (neighborCell.isMinePresent == true)
								{
									cellAtPos.numberOfMinesInNeighbors++;
								}
							}
						}
					}
				}
			}
		}
	}

	Field.prototype.getCellAtPos = function(cellPos)
	{
		return this.cells[this.getIndexOfCellAtPos(cellPos)];
	}

	Field.prototype.getIndexOfCellAtPos = function(cellPos)
	{
		return cellPos.y * this.sizeInCells.x + cellPos.x;
	}

	Field.prototype.setCellAtPos = function(cellPos, cellToSet)
	{
		this.cells[this.getIndexOfCellAtPos(cellPos)] = cellToSet;
	}

	// html

	Field.prototype.toHTMLElement = function()
	{
		var tableForField = document.createElement("table");

		var cellPos = new Coords(0, 0);

		for (var y = 0; y < this.sizeInCells.y; y++)
		{
			cellPos.y = y;

			var trForRow = document.createElement("tr");

			for (var x = 0; x < this.sizeInCells.x; x++)
			{
				cellPos.x = x;

				var cellAtPos = this.getCellAtPos(cellPos);

				var tdForCell = document.createElement("td");

				var buttonForCell = document.createElement("button");
				buttonForCell.innerHTML = "?";
				buttonForCell.cellPos = cellPos.clone();
				buttonForCell.onclick = Field.buttonCellClicked;

				tdForCell.appendChild(buttonForCell);

				trForRow.appendChild(tdForCell);
			}

			tableForField.appendChild(trForRow);
		}

		tableForField.field = this;
		this.htmlElement = tableForField;

		return tableForField;
	}
}

function FieldCell()
{}

function Globals()
{}
{
	Globals.Instance = new Globals();

	Globals.prototype.initialize = function(field)
	{
		this.field = field;
		var fieldAsHTMLElement = this.field.toHTMLElement();
		document.body.appendChild(fieldAsHTMLElement);	
	}
}

// run

new Minesweeper().main();

</script>
</body>
</html>
Advertisements
This entry was posted in Uncategorized and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s