1. How to play minesweeper?

Oct 3, 2006 — Uploaded by Llamallover

The user will be able to click the cell, to select size of the grid, or to restart the game. If the user clicked the bombed-cell, the game will be over. Or, the user can mark the cell by right-clicking it, if they assume it is a bombed-cell. If the user an open all the non bombed-cell, they win the game.

2. Why Vuex?

As i want to build an app that has some components, (for scalable and efficiency sake), it is pretty hard to maintain the state of each component. What makes Vuex so powerful is that the components get their state from the Vuex store and can reactively and efficiently update whenever the store’s state changes.

3. Why Vuetify?

Vuetify is a material design framework built on Vue environment. It has decent and subtle user interface components and readily available on Vue.

4. Setup the app

Vue provides standard tooling for development called Vue CLI. It can easily set the app by a simple command.

vue create minesweeper-vue

If you have not installed Vue CLI in your pc, install it as a global package.

npm install -g @vue/cli

# OR

yarn global add @vue/cli

5. Add Vuex

As already discussed, i am using Vuex as store management pattern of our app. Simply type

yarn add vuex

# OR

npm install vuex

6. Add Vuetify

It’s slightly different from Vuex, as i setup Vuetify by Vue CLI. I can add Vuetify to the app by typing

vue add vuetify

After installation, our root app structure will be like image on the left.

7. Structure of the app

I built the app from two components:

Main Grid Component

Timer Component

The main grid components built with Vuetify material v-hover that has v-card inside. The v-hover then wrapped inside v-row.

The timer component contains information about time the user spent to play the game. It will be updated as a real time when the player first click the cell.

8. Setup Main Grid component

First, you can delete HelloWorld.vue from components folder, as it won’t be used. Then, you have to create new component, for example MainGrid.vue .

TIPS:

Use VSCode IntelliSense to load Vue template faster

Now, i want to build main grid that has “multidimensional array” like, which has row and column with same number. In this example, the app is using 8 as a row and column. For this, i can use v-row and v-col from Vuetify. To add hover effect, i used v-hover .

Register MainGrid.vue to components on App.vue

To see the result of our grid, you can run command

yarn run serve

Now, our app will look like this:

9. Setup Main Grid store module

I use Vuex as a state management for our app. First, i setup state management for main grid.

Create folder store inside src folder In this app, i am using modules system. So, i created file named vuex.js which register Vuex to the app and also export the module within the Vuex store itself. Create folder modules Create file mainGrid.js to configure it’s own getters , state , actions , and mutations. Includes our vuex.js to our entry point file, usually main.js

10. Main grid: setPattern

There are some states that main grid component depends on. First, i need to set the grid pattern for our main grid. So, i know how and where to place number and bombs randomly inside each cell.

To create the pattern, declare state, actions, and mutations for set the pattern in the store.

Then, how to initiate the component to set the pattern? i use map from Vuex. map connects the store to the component, and then initiate set pattern asynchronously.

The first step is import mapActions from Vuex using destructuring assignment. And assign setPattern actions to component’s methods.

As you can see, i execute setPattern when the component get into the created lifecycle hook. In the created hook, you will be able to access reactive data and events are active, but templates and Virtual DOM have not yet been mounted or rendered.

To check the pattern, you can easily check at the Vue devtools.

11. Main grid: getPattern

After created the pattern, the template have to communicate with the store. So, the template can render the pattern passed from the store. It can be done using mapGetters from Vuex.

First, add getters and create method named getPattern to our main grid store and include it in the export object.

Like before, import mapGetters from Vuex using destructuring assignment, and assign getPattern actions to component’s computed property.

After mapped, use the getPattern on computed property for being component’s data source. You can show each cell’s data, by put each iteration into v-card text.

Now, our app will look like this

12. Main grid: Hide and show cell’s data

We need to think about how to open a cell that was closed via a left click. First to do is to set a state in each cell that represent as a “closed” state and changed that state when we left-clicked the cell.

Add show key to the cell that have been created before and modify some code to keep the cell’s data defined.

Next, “hide” the cell’s data with Vue conditional rendering v-if . And to show the cell’s data, assign method called openCell and passing the cell’s row_idx and col_idx .

Add openCell method handler in the store. Put it in the actions property and then pass the cell target to mutations property. I have to pass to mutations because i want to change the pattern state. Only mutations property is allowed to do that.

Try it.

Let’s say thanks again to Vue’s reactivity. Do you already fall in love?

13. Main grid: Flood Fill algorithm

Flood fill is an algorithm mainly used to determine a bounded area connected to a given node in a multi-dimensional array. It is a close resemblance to the bucket tool in paint programs.

In this case, i am using Flood Fill algorithm to find connected cell which have “0” value and reveal it. This recursion started when the designated cell is clicked. To do that, there are some things to be noticed:

Operate only on covered cell Operate only in range of the grid Find number of adjacent cells If there any, reveal the numbered cell (more than 0) If not, reveal a blank cell (0) and continue the recursion Skip the reveal process if the cell has been revealed Stop the recursion if the cell is numbered or the cell is at array’s end

I added some conditional statement inside openCell method to handle the recursion. First, to stop the recursion if it reaches the end of array. And the second one is to handle if cell’s data is equal to “0” or has been revealed.

Next is define floodFill method inside actions property. Inside the method, i reveal the cell’s data and call again openCell method, but with passing different row and column index. I call with four direction, N, W, E, and S.

14. Flag the cell

In minesweeper game, the cell can be flagged or marked if we assume it is a bomb by right-clicking on it. There are things to be noticed:

The cell cannot be flagged if has been revealed Put flag icon in cell If flagged, the cell cannot be opened unless it has been un-flagged by right-clicking it again

In the component file, insert method for handling the right click at the cell’s attribute. I used prevent handler to prevent right click dialog box from showing.

Then, register the right click handler to the component’s method by mapping it from the store.

In the main grid store module, i did three parts:

flag key on the state property to register flag icon to the web. flag property on getters to get the flag icon and communicate the state with the component. flagged key on each cell property in the pattern. I do that because this one resemble the show key where it used boolean value to be reactive rendered by the components. Conditional statement inside the openCell method to skip if the cell is flagged.

And the last, configure the component to show the flag if user right-clicking the cell.

15. Setup timer component and store module

It’s like usual timer where ticks based on seconds. The timer will start to tick when user click the cell. The steps are almost the same as main grid:

Create file component, for example Timer.vue Import the component, add into App.vue registered components, and write down the custom tag below <main-grid> tag Create timer store module file, for example timer.js Import the module and add into Vuex store’s module in vuex.js file

16. Timer: setTimer

If all ingredients has been set, the next step is to make a trigger to initiate the timer. The time is ticking by seconds and will start to tick whenever the user clicked the cell. It can be done by setup a state as a “main control” for timer telling when to start the time. It can be put on main grid store as a new state property.

To enable the change of that state, i also add a mutation on mutations property. From that code we know that the timerInit state property will be mutated into current time when the user first clicked it in milliseconds format. I set the initial time because i want to calculate the different between that initial time and actual time that ticking by second.

The timer value actually is processed in the timer store that i have been created before. Lets create state property in the timer store to accept hours, minutes, and seconds value; also create time divider based on milliseconds.

On the actions property i added setInterval method to handle the timer initiate.

On the setTimer actions, it will be working whenever the timerInit state on the main grid store is set to current time value. I have set the timerInit will be mutated if the user clicked the cell in the explanation before.

To connect between the store, i used rootState property from Vuex. It serves all Vuex modules that registered in app initiation. Then the main grid store can be accessed simply using dot notation or bracket notation.

Next is to handle hours, minutes, and seconds whenever the timer is ticked; then set those value in the state property via mutations. So our timer.js store file will look like this:

You can check the mutation of the timer state in Vuex bar menu on Vue devtools.

The setTimer actions then connected to the app by adding it in timer component, and placed in created hook.

17. Timer: getTimer

To get the time value, i used getters property. The time is made of hours, minutes, and seconds state. First, we got each hours, minutes, and seconds value respectively by using getter. I also added conditional return value for seconds and minutes to return two digits if those value is below 10.

The time getter then mapped on the Timer component using mapGetters

And there is it!

I hope you enjoyed following along. Please leave claps and comments if you liked the content and would like to discuss further!

There are some additional features you can add to the game:

Stop the timer and pop a notification whenever the user clicked the bomb Giving some style to the number and the bomb Restart button Grid size select Information about mines left. It can be decreased when the user put a flag on the cell and vice versa

I also made the minesweeper with some features. You can check it out and i am very welcoming the feedback!

GitHub: https://github.com/naufaliqbal/minesweeper-vue

LinkedIn: https://www.linkedin.com/in/muhamad-iqbal-naufal/