Minesweeper in TypeScript and React
One of the games that I occasionally play to relax is Minesweeper.
In this post I will try to explain how I did it and maybe encourage or learn you how to implement your clone of this or maybe some other game.
Before we start
You will need to have installed (or install) on your machine:
Creating React Application
We will bootstrap the React project with using the option
--script-version=react-script-ts that would instruct
create-react-app to use Create React App (with TypeScript) configuration.
In my previous experience with Angular I find TypeScript a real joy to work. And having daily experience with statically typed languages (Java, Kotlin) I was not interested in using pure ES6. On the other side, learning and investing time in Flow was not worth it having a previous (great) experience with TypeScript. Read this great article to find out more about using TypeScript + React.
npx create-react-app --scripts-version=react-scripts-ts minesweeper
To start the application just execute:
# or yarn start
Structuring the React app
One of the important steps in implementing any React application is how to brake down the UI in components and how to compose them. On the following image is the structure of the React components that we will need to implement for Minesweeper.
The final design was to brake down the game in three separate components:
MineSquare- will host a single square that is a possible mine, number indicating of neighbour bombs or just empty square if no bombs around
MineField- will host the game container as a grid (rows x columns) of mines
Timer- will be an external component that will show the elapsed time since the game started.
Next create a directory
components in your
src directory and create a separate file for each of the listed components.
This is how an empty component should look like:
In React you can create components as class that extends the
React.Componentclass or as functions (possibly arrow) for functional (stateless) components.
Minesweeper game domain
The game domain are the classes and data structures used to represent the state of the game.
The game Minesweeper is represented as two-dimensional array (matrix) of mines
position(x,y coordinates) in the matrix of mines
isOpeneda boolean field which is true when a mine field is opened
bombsa number which encodes if there is a bomb (-1) or positive number representing the count of bombs around that mine.
isFlaggedwhich represents if the mine is marked (flagged) by the user as potential bomb.
It was really hard to get the naming right for the game domain, having to deal with mines/bombs, mine field as single field with mine or field of mines :).
Game class represents the state of the Minesweeper game which is the two dimensional array of mines. Also it contains auxiliary fields for the count of total bombs and state if there is exploded bomb (game is finished).
MineSquare is a functional (stateless) component. That means that it should render the property
field: Mine and just propagate an event when interaction happens. It can not keep or mutate any state.
Mine will be rendered as HTML
button element since the click is the natural interaction for this HTML element. Depending on the state of the
field: Mine we will render the different content inside the
button element. The function
renderField(field: Mine) does exactly that. So when the field is opened (user explored that field) it can be:
bombs == -1so we render a bomb (using FontAwesome bomb icon for this)
bombs == 0the field is just empty
bombs > 0we render the number of bombs in that field.
When the field is opened and flagged we render a flag icon.
The component propagates the mouse
onClick event to indicate user interaction with this field.
In minesweeper there are two types of interaction user can have with a field, to explore it or to flag it as potential mine. Maybe better choice is to represent these with different events such as mouse left and right click. But because of a buggy behaviour of the right click, my final choice was to encode these two different events with only left click and a pressed state of a certain keyboard key (ctrl in my case).
MineField component is also functional and is responsible of rendering the full state of the game (the two-dimensional array of mines). Each
field is rendered as a separate
MineSquare component. It will also propagate the click event from each
This component is very simple, it should just render the two-dimensional array of mines as grid. Each row is grouped in a separate HTML container
divelement and with CSS it is all aligned. To uniquely identify each row we can use the row index
i as a React
key property, and for each
MineSquare component the
key would be the combination of indices
j (the current row and column).
Timer is another stateless component responsible for rendering the elapsed seconds since the game started. To render the
seconds in appropriate format
00:00 it uses a custom function
secondsToString from our utility module named
Here is the implementation of the
secondsToStringI think it’s better to just implement them.
So far we have implemented the simple (stateless) components of the game. To make the game alive we need to implement initialization of new game state (new game action) and all possible modifications.
Most of the simple games are following some kind of game loop as shown in the image above. The users through the UI are having interactions with the game and are generating actions. Sometimes actions are generated automatically as the time passing, but in Minesweeper that is not the case. On each action, the state of the game is modified and then rendered back on the UI.
In the case of Minesweeper, the user can make three possible actions on not opened field (mine square):
- mark it as potential bomb
- open it
and if the field is already opened the user can explore neighbours.
Generating new game state
Generating new game state means initializing the two-dimensional array of
Mine objects. Some of these mines need to be bombs and we make this decision by using pseudo-random number generator to implement sort of uniform distribution of a mine being a bomb. The
BOMBS_PROBABILITY (by default 0.15 or 15%) is the probability of a mine having a bomb. While we create mines we generate a pseudo-random number using
Math.random() which has generates a double with uniform distribution in the range of
After we have initialized the game state with
Array<Array<Mine>> we need to update the
bombs count of all mines that are neighbouring a bomb. The function
fillBombsCount does just that, by traversing all the neighbours of a mine and incrementing the bombs count for each neighbour that is a bomb.
traverseNeighbours is the utility function that iterates all eight (top left, top, top right, left, right, bottom left, bottom, bottom right) of the neighbours of a given mine.
Updating game state
update is a generic function for updating the game state without modifying it. It iterates all of the game state mines and applies a function
f that should apply the actual transformation for a mine. This function is used in all functions that need to update the game state in any way.
Mark mine field
markMine is used for two user actions. The first action is when user wants to mark a mine field as a potential bomb. We do that, only when the current state of the field is not opened by updating the game state where we set that field as flagged and not opened. The second possible action for a user is to explore already opened field that has a count of bombs.
Exploring opened field
To explore open field is a potentially game ending action that needs to explore all neighbour fields of that field. The opened field that a user explores must have all its neighbour bombs flagged right. If a neighbour field that is a bomb is not flagged, the game ends.
To implement this function we use the generic
traverseNeighbours and for each neighbour field that is not opened and not flagged:
- if it’s a mine we should end the game
- if it’s not we should set as opened and if we open a zero-bomb field we should open all other connected zero-bomb fields.
Traversing connected zero-bomb fields
updateZeros traverses using a recursive DFS (Depth-First Search) algorithm all connected zero-bomb fields.
Check if game is completed
On each state modifying action we need to check if the state of game has reached an end state. For the game Minesweeper that state is when all the fields are explored correctly. That means that a mine field that contains a bomb is flagged and otherwise it’s opened.
checkCompleted checks for the end state by iterating all fields and mapping them in to a
boolean value. The
true value means field is explored correctly and
false means not explored correctly. Combining all these values using logical AND would yield final
true only if all fields are explored correctly, which would mean the end state is reached.
Count flagged fields
countFlagged is used to count all the flagged fields in the game state to show the current progress of flagged/total bombs.
Putting all together in App component
Once we have implemented all the game state modifications and checks we can put it all together. The actual game state is initialized and modified in the component
The final piece of the puzzle, the
App component is the only stateful component that keeps and modifies the game state. The state of the component contains:
- the number of
columnsof the Minesweeper grid
- the game state
- the elapsed seconds since the game started
- the number of flagged fields (computed from the game state)
- and a boolean flag indicated if the game is completed (also computed from the game state).
The state is initialized at the beginning of the component on a new game state. We use the React lifecycle method
componentDidMount to bind two keyboard events
setTimeout function that we use to modify the elapsed seconds state.
updateState is used to update the state of the React component using
this.setState. This is a HOF (higher-order function) that accepts the actual game state modification function as
updateFn as argument. Once the game state is modified, the final state of the component is updated and the UI should be rendered. This function is called on the user generated event
onSquareLeftClick. When the
ctrl button is down a mine is opened and otherwise mine is marked (or explored).
The actual rendering of the UI is pretty simple. We render a simple menu of three links that allow to start new game with the chosen difficulty. Then we render the
MineField component with the current game state and the
Timercomponent showing the elapsed seconds. Finally, we render a information on the current status of the game, such as is it completed and number of flagged fields vs total bombs.
Implementing any simple game is an interesting programming challenge. Many times a challenging part is to implement the game state and functions (algorithms) that mutate the state. Favouring functional programming I tried to implement most of these functions as mostly pure functions by using functional constructs such as
reduce. Also, three out of four React components are functional (stateless or pure functions).
Hopefully sharing my solution and explaining it in this post was interesting and learning experience. If you feel inspired to start learning these technologies by implementing your own Minesweeper or other game, that would be great. And finally, it would be perfect if you also share your code and experience.