minesweeper

1.0.5 • Public • Published

Minesweeper

A collection of objects that provide the logic needed to create a Minesweeper clone.

All you need to do in your project is write the UI.

Dependencies

Minesweeper is written in vanilla JS and has no dependencies. Works with node and in the browser.

Why

With so many front-end frameworks and view layer libraries to choose from, I am able to use this library to play around with them without needing to write a lot of irrelevant logic code.

How

Step 1: Include the library

Available as an npm package using

npm install minesweeper

or a bower package using

bower install minesweeper-lib

Alternatively, you can just download the file from the dist directory and manually include it in your project using

<script src="minesweeper.js"></script>

Step 2: Access the library

If you're using modules in your project, you'll need to

var minesweeper = require('minesweeper');

or the equivalent using an AMD style script loader such as require.js.

If you're directly including the source file using a script tag, it will be accessible at

window.minesweeper

Step 3: Create a mine array

Create a mine array by passing some options to minesweeper.generateMineArray.

All properties are optional, and will use the defaults specified below if not provided.

var mineArray = minesweeper.generateMineArray({
    rows: 10,
    cols: 10,
    mines: 15
});

Step 4: Create a new board using the mine array

Create a board using the mine array you just created.

var board = new minesweeper.Board(mineArray);

Step 5: Render the board

Get a copy of the board grid with a call to board.grid()

var grid = board.grid();

This will return a two-dimensional array filled with minesweeper.Cell objects that you can use to render the board.

Each cell has the following properties:

  • x The zero-based column index that this cell belongs to
  • y The zero-based row index that this cell belongs to
  • isMine Boolean that specifies if this cell is a mine or not
  • numAdjacentMines The number of adjacent mine cells (0 - 8)
  • state Type of minesweeper.CellStateEnum which determines whether this cell has been opened by the user or not. Can be one of:
    • minesweeper.CellStateEnum.CLOSED
    • minesweeper.CellStateEnum.OPEN
  • flag Type of minesweeper.CellFlagEnum which determines if the user has flagged this cell with an exclamation or question mark. Can be one of:
    • minesweeper.CellFlagEnum.NONE
    • minesweeper.CellFlagEnum.EXCLAMATION
    • minesweeper.CellFlagEnum.QUESTION

Assuming you know the rules of Minesweeper, that's all the information you need to render the board. For example, you could now render the board to the browser console with the following code

var BoardStateEnum = minesweeper.BoardStateEnum;
var CellStateEnum = minesweeper.CellStateEnum;
var CellFlagEnum = minesweeper.CellFlagEnum;
var Board = minesweeper.Board;
var Cell = minesweeper.Cell;
var generateMineArray = minesweeper.generateMineArray;

var printBoard = function (board) {
  var i,
      strColHead = '   ',
      grid = board.grid();

  // print a header that shows the column numbers 
  for (i = 0; i < board.numCols(); i++) {
    strColHead += '   ' + i + '   ';
  }
  console.log(strColHead);

  // print all the rows on the board
  for (i = 0; i < board.numRows(); i++) {
    printRow(grid[i], i);
  }
};

var printRow = function (rowArray, rowNum) {
  var i,
      cell,
      strRow = '';

  // Start the row with the row number
  strRow += rowNum !== undefined ? ' ' + rowNum + ' ' : '';

  // Add each cell in the row to the string we will print
  for (i=0; i<rowArray.length; i++) {
    cell = rowArray[i];
    if (cell.state === CellStateEnum.CLOSED) {
      if (cell.flag === CellFlagEnum.NONE) {
        strRow += getCellString(' ');
      } else if (cell.flag === CellFlagEnum.EXCLAMATION) {
        strRow += getCellString('!');
      } else if (cell.flag === CellFlagEnum.QUESTION) {
        strRow += getCellString('?');
      }
    } else if (cell.state === CellStateEnum.OPEN) {
      if (cell.isMine) {
        strRow += getCellString('*');
      } else {
        strRow += getCellString(cell.numAdjacentMines);
      }
    }
  }

  // Print this row to the console
  console.log(strRow);
};

var getCellString = function (content) {
  return ' [ ' + content + ' ] ';
};

var mineArray = minesweeper.generateMineArray({
    rows: 5,
    cols: 5,
    mines: 5
});

var board = new Board(mineArray);

printBoard(board);

Step 6: Playing the game

There are two methods on the Board object that you use to play the game:

board.openCell(x,y)
board.cycleCellFlag(x,y)

x represents the column number, and y represents the row number. Both are zero-based indexes.

After each move, the internal state of the board and grid will update according to the rules of Minesweeper.

You can get the latest version of the grid by calling board.grid() again and re-rendering to the screen.

Step 7: Check the game state

You can check the state of the board at anytime by calling

board.state()

which returns an enum of type BoardStateEnum

  • BoardStateEnum.PRISTINE Before any interaction (open cell, flag cell) the board is in this state
  • BoardStateEnum.IN_PROGRESS The board has been interacted with, and is not in a winning or losing state
  • BoardStateEnum.LOST The board is in a losing state, meaning that a mine cell has been opened
  • BoardStateEnum.WON The board is in a winning state, meaning that all non-mine cells have been opened, and all mine cells have been flagged with an exclamation

Once the board enters either BoardStateEnum.LOST or BoardStateEnum.WON, any further attempts to modify the board using board.openCell(x,y) or board.cycleCellFlag(x,y)` will not be successful.

Learn

The code is free and open-source under the MIT license, so feel free to use it in any way you like. Whether that be in your own learning projects, in learning materials you put together for others, or in a published Minesweeper clone.

Contributing

Any contributions to the code or this documentation are more than welcome. For bug fixes make sure you write new test cases that will prevent regression, and all existing tests should still be passing. Then submit your PR.

For breaking changes or new features, please raise an issue first. But I'm very friendly and will be receptive to your suggestions!

Author

Feel free to connect with me on Twitter (@binaryluke), or learn more about me at lukehoward.name

Readme

Keywords

none

Package Sidebar

Install

npm i minesweeper

Weekly Downloads

16

Version

1.0.5

License

MIT

Last publish

Collaborators

  • binaryluke