Minesweeper in SPFx

Who doesn’t need more fun in SharePoint?! Check out this SPFx v1.10 web part I created from scratch & shared with the M365 PnP open source community. It’s basically the classic Minesweeper game in SPFx built using Fluent UI icons & components.

The functionalities include:

  • Difficulties
  • Timer
  • High scores (using localStorage)
  • Remaining number of mines
  • Chording
  • Game mode (mine / flag)
  • Reset game

Chording is present in the game as is the case in the original game. When a  tile with a number has exactly the correct number of adjacent tiles flagged, performing a click on it will uncover all unmarked tiles. This is called a chord. Just be careful not to make any mistakes when adding flags!

The game can be played in two modes: mine mode & flag mode. These modes simply swap the left / right click behavior. By default (mine mode) a regular left click uncovers a tile, while the right click adds a flag. This makes it easy on mobile to combine flagging & chording for the best high scores!

The web part itself is pretty vanilla SPFx, however the game logic comes with certain challenges as you might imagine. In particular, I want to highlight what happens when you click on a square that has no surrounding mines. A recursive method keeps traversing squares that have no surrounding mines at all. This method also needs to know when to stop e.g. when a grid boundary has been reached or when a square was found with at least one mine next to it.

To this end, I added delta coordinates as a constant. It represents the 8 squares adjacent to the current square:

public static readonly DeltaCoords: Coords[] = [
    {row:-1, col:-1},
    {row:0, col:-1},
    {row:1, col:-1},
    {row:-1, col:0},
    {row:1, col:0},
    {row:1, col:1},
    {row:0, col:1},
    {row:-1, col:1}

The recursive traverseEmptyTiles method is surprisingly compact. For each delta coordinate, we first check if the coordinate is valid. We only continue for unknown squares or squares that contain a flag. If that adjacent square has no surrounding mines, we set its FieldType property to ‘Empty’ and invoke the very method we are in, only with the coordinates of the adjacent square (this is where the recursion happens). On the other hand, if there are surrounding mines, we simply set the number of closeMines found and set the FieldType property to ‘Number’. This recursive method will keep spreading out to tiles that have no surrounding mines, as well as come to a halt for tiles that have a number already. Here’s the method:

private traverseEmptyTiles(grid: TileInfo[][], coord: Coords){
  Globals.GeneralSettings.DeltaCoords.forEach(dc => {
    if(this.isValidCoord(coord, dc)){
      let tile = grid[coord.row + dc.row][coord.col + dc.col];

      if(tile.fieldType === FieldType.Unknown || tile.fieldType === FieldType.Flag){
        let closeMines =
            this.getSurroundingMines(grid, {row: coord.row + dc.row, col: coord.col + dc.col});

        if(closeMines === 0){
          tile.fieldType = FieldType.Empty;
          this.traverseEmptyTiles(grid, {row: coord.row + dc.row, col: coord.col + dc.col});
          tile.fieldType = FieldType.Number;
          tile.closeMines = closeMines;

I’ve recently learned about the VS code extension called CodeTour, which allows you to create a walk-through experience for your project. Please check the CodeTour link to see how easy it is to get started with it. Very interesting to allow newcomers to get to know your code in an easy way. PnP uses this extension to add the steps required to upgrade your SPFx version !

I went ahead and added a code tour to the minesweeper sample. The result is something like this:

I like how you can add terminal commands in the markdown (e.g. npm install). Newcomers can get set up quickly by merely clicking the commands one by one. They are automatically executed in the terminal, no copy pasting skills required !

You can self reference the different steps in your tour. I did this to quickly get around the different game logic methods. Referencing a step can be done as follows:

[game logic overview][#11]

This has the obvious drawback that adding a step before step 11 messes up the reference (step 11 became step 12 when inserting a new step)…

If you are interested, please check out the code to see how the game logic and event handlers all click together.

That’s all for now. There’s more ! I added a social component to the game which should bring more interaction to the func / social channels in Teams once the game is added as a tab there:

I’m curious to see how the web part will be used or where it will wind up, so do not hesitate to reach out to me on Twitter !

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Create a website or blog at WordPress.com

Up ↑

Create your website at WordPress.com
Get started
%d bloggers like this: