How an algorithm can solve MineSweeper

Did You enjoy Demine and want to know more about how can it help You solving the game ? Then continue to read as this will clarify the techniques it uses.

Terminology

First a little bit of terminology, tiles still to be discovered are called unstable to underline the fact that their content will change (when they'll be clicked or flagged), then there are flags and stable tiles i.e. the tiles whose content will not change as they are already clicked.

Obvious approach

The Obvious technique oh, well, it's pretty obvious as it proceeds as a human being would proceed. It considers each stable tile in turn and all the tiles around it; if all the tiles around are flags and other stable tiles then there is nothing to do, but if there is still an unstable tile around it then it sums up flags and still covered (unstable) tiles. If the expected number of bombs is equal to the flags' number then it's possible to click all unstable tiles around as there should be no more bombs around. If, instead, the expected number of bombs is equal to the sum of flags and unstable tiles then all unstable tiles around are bombs and can be flagged. And that's all. Simple, isn't it ?

More terminology 

The default technique is more complex as it requires a brute-force (namely try all possibilities) approach. First of all the algorithm identifies subsets of the stable tiles and of the unstable ones. It calls contour tiles the unstable tiles who have at least a stable tile around and checkable tiles the stable tiles who have at least a contour tile around. For example in the following image contour tiles are still covered tiles highlighted in yellow, while checkable tiles are every stable tile next to a contour tile.

Contour and checkable tiles are grouped together to form isles. In an isle all tiles are reachable starting from any of them, the only rule is that from a contour tile only checkable tiles can be visited and from a checkable tile only contour tiles can be visited. Isles are important 'cause they are independent from each other (i.e. they don't influence each other) so they can be solved independently. In the following image for example there are a 1-tile yellow isle, a 5-tile aqua isle and so on (note however that only the contour part of the isles is highlighted, but the checkable part is essential too), but the important thing is that no matter how a bomb is placed on a contour of an isle, it cannot influence other isles' checkable tiles.

Working by contradiction

I found this technique while surfing the net, I liked it and ported it to Demine. You can take a look at the original AI project developed by two students  here: http://universitopia.com/AI.html. The purpose of this technique is to put a bomb on every still covered tile and then to look carefully to see what happens: if such a choice produces problems i.e. a contradiction then the technique can be sure that the current covered tile cannot hide a bomb and so suggest to discover it.

For example in the above image if we try to put a bomb on the contour tile marked as 'A' we are in trouble because the checkable tile 1 marked with the little superscript '1' is satisfied and doesn't allow us to put a bomb on 'B'; but 'B' is the only contour tile that can satisfy the checkable tile '1' marked with the little superscript '2' so it's clear that putting a bomb on 'A' produced a contradiction: it follows that A cannot hide a bomb and so can be safely discovered.

Brute-force approach

When every isle has been recognized it's possible to try to solve each of them. Solving involves deciding if contour tiles hide a bomb or not. This is a binary condition bomb/empty, 0/1 so a contour with n tiles can be viewed as a n-bits integer where for every bit the condition can be interpreted as 0 == free of bombs, 1 == it hides a bomb. So to try every possible configuration is sufficient to start with value 0 for the n-bits integer (i.e. all bits set to 0) and increment it by one unit until the value with n bits set to 1 is reached.

Obviously when a candidate configuration has been prepared it must be checked to verify if it's acceptable/admissible or not. This is where checkable tiles come into play. For example in the previous image we can easily recognize an invalid configuration because for example the corner '1' tile at the right-bottom of the image isn't satisfied as its only contour neighbor holds a 0 (no bomb).

When an admissible configuration is found we must increase the number of admissible configurations found so far and the number of times a contour tile has been a bomb for every tile set to 1.

Weird things ... i.e. Huston we have problems !

At the end of the exploration phase, when all the possible configurations have been generated and checked it's time to go back to counters accumulated so far and to decide ! First of all if the number of admissible configurations (which we will call NAC from here onwards) found is 0 then we can say that either the starting configuration is not valid or a bug is lurking somewhere :-).

Normal course of things

If nothing strange happens and at least an admissible config has been found then it's really possible to produce suggestions ... yesss ! All contour tiles with a zero bomb count are then a safe place to jump on ... ehm ... to click on ! while all tiles with a bomb count equal to the NAC are a place waiting for a flag.

Need more information i.e. fuzzy outcome

Ok, ok am I just a little bit too optimistic ? Well there are situations where safe places and flags are nothing but far mirages; in such situations we cannot produce sound suggestions but only elaborate probabilities so for every contour tile Ci the probability to be bomb is pi=bomb_counti/NAC.

That's all. Goodbye.

But 'wait a minute' I hear some of You screaming, 'brute force approaches' are lengthy and time-consuming so how can be Demine so fast ?'. The most important thing is to break down the problem into isles (divide et impera) but this obviously isn't sufficient as even pieces can sometime require a lot of work to be completely explored. The very truth is that even using another 'dirty trick' there are configuration for which Demine takes a big amount of time. They have a little probability to appear in a 'normal' game session, but can be easily prepared by hand for example. In general in such situations using first of all the obvious approach and then brute-force helps, be however prepared to wait for a while in some situations.

The (not so) dirty trick.

Luckily the characteristics and the very nature of the game allow us to shorten the road to suggestions quite a bit sometimes. We saw earlier that to explore all the possible configurations we can add 1 to the binary representation of the contour tiles, i.e. we increment the least-significant bit of the representation. All configurations are then checked against the isle' set of checkable tiles. Every checkable must be satisfied for the configuration to be accepted. And precisely here is the key that let us 'visit implicitly' some configurations without having to actually/really generate them.

Consider in fact a situation where a checkable tile isn't satisfied by a configuration: the associated neighbor contour tiles holds wrong numbers/bits. If the associated bits are high in the bit representation of the configuration then it can take some time (remember we add only 1 each time to consider next config) before such bits will be changed, but we know every configuration generated before such bits will be changed will be surely rejected as the above checkable cannot be satisfied ! Eureka, now we can see the light at the end of the tunnel !

The right thing to do in such a situation is to consider the lowest associated bit of all dissatisfied/unhappy checkable tiles, then select among them the higher and increment the configuration's representation at that level. Obviously, as said, high and low have a meaning with respect to the binary configuration. Also all bits lower the intervention point can be zeroed to avoid missing possible admissible configurations.

Surprised ? Just You don't believe what I am saying ? Do You think I am joking just to detect who fell asleep in the meanwhile ? Well this is how Demine works so this approach must deserve some attention from Your part.

Ah, now I understand it's just my explanation that sounds like an obscure voodoo spell ! :-). Well as You probably have already guessed I'm not good at explaining things, even less so, if possible, in a foreign language so, please be patient with me.

The goal is to change the configuration representation at the highest possible level without missing admissible configurations. In the equation the 'not missing good configurations' part is guaranteed by the fact we select the lowest associated bit of checkable tiles as the key bit and then we set to zero every bit lower the intervention point, while the 'highest possible level' part is guaranteed by the selection of the higher among the key bits.

This can seem not to be a great improvement, but as an example let's consider an isle with 27 contour tiles as the following.

The total number of different configurations that is possible to generate whit 27 binary digits is 2^27 = 134.217.728. The program explores all the configurations to find that the good ones are only 2 !!! The smarter version explores only 1498 configurations and it finds the same 2 good configurations i.e. the dumb brute-force approach visits about 89598 more times the configurations visited by the smarter algorithm to find the same 2 good configurations. Well, needless to say this is really a great improvement.

 

A different approach

Well all the above is interesting, but at the very end every configuration must be verified against checkable tiles, so why don't start from here ? For every checkable tile it's possible to calculate the set of admissible configurations considering only the neighboring contour tiles. For example considering the '2' at the lower, left corner of the above image, it has 5 neighboring contour tiles, so all the admissible configurations (from its point of view) are the following:

     00011, 00101, 00110, 01001, 01010,
     01100, 10001, 10010, 10100, 11000.

i.e. all the 10 configurations with 2 bombs. When all the admissible configurations for every checkable tile have been calculated it's time to try to somehow merge them together into an admissible config for the entire isle. As it appears clearly from even a rapid inspection of the above image a lot of the contour tiles (almost all of them to be true) are shared among many checkable tiles. So the real problem here is to cope with possible conflicts between different configurations of different tiles.

The algorithm can be sketched as follow:

If no admissible config is found for the isle then the isle is probably not correct.

Lets consider the following example:

There are 12 contour tiles (numbered from 0 to 11) and 8 checkable tiles (marked with the letters from A to H); the checkable tiles are considered following their order so tile A is considered first. Tile A chooses among the 10 admissible configurations saw earlier 1 configuration (10010 in the example) and set the 5 neighboring contour tiles. It's now tile B turn to move; its neighboring tiles are { 2, 3, 4, 5 } ant tile 2 is already set, so it selects among its admissible configurations a configuration that is compatible with the 0 in tile 2; for example it can choose 0011. The situation is now depicted in the following image and it's tile C turn to move.

Tile C has 3 neighbors namely { 1, 2, 3 } and they are all already set so it only has to verify if the 100 configuration is admissible as it is. It's now tile D turn to move: it has 2 neighbors { 10, 11 } and selects an admissible configuration that matches the 1 in tile 10, for example 10. The situation is shown by the following image:

It's now E turn; its 3 neighbors { 9, 10, 11 } are already set and the configuration is admissible as it places only 1 bomb around tile E. So the turn passes to tile F that has 4 neighbors { 5, 6, 7, 8 } and tile 5 is already set; it chooses an admissible configuration for example 1100 so to produce the following situation:

It's now tile G turn; it has only 1 neighbor namely { 5 } and its content matches the only admissible configuration for G, so the turn passes on to tile H. Tile H has 2 neighbors { 7, 8 }, but 00 is not an admissible configuration for it as it requires exactly a bomb around so it rejects the configuration and returns control to tile G; tile G should try next compatible configuration, but it has only one, so it too returns the control to tile F; tile F selects the next configuration compatible with the 1 in tile 5, for example 1010 or 1001 and pass the turn to tile G; the following image shows the current situation:

As before tile G is satisfied by contour tile 5, but this time tile H is satisfied too and it's the last checkable tile, so the current configuration (with 5 bombs) is good for the entire isle and it is stored: 010011001010.

The process then continues trying every combination of admissible configurations and it finds 10 admissible configurations using from 4 to 6 bombs for the isle.

Final Phase

No matter what approach has been used to solve all the isles, when the game is next to the end some more can be done if some preconditions are verified. In general when there is still a great number of bombs the above is all the program can do to guess bombs' positions, but when the number of bombs still to be located become little enough some more techniques can be used. As we saw earlier the bombs' number of the good configurations for an isle can vary from a min M to a max N. We don't know how many bombs an isle really uses, but we know for sure that it uses at least M bombs. So if the sum of the min number M of bombs used by each isle is equal to the number of bombs still to be discovered we know for sure that all the remaining bombs are on contour tiles. Now the next step is easy: if there are uncovered tiles that aren't part of the contour of some isle we can click them all as they are safe 'cause all the bombs are forced to stay on contour tiles.

But, as TPReal suggested, there is also more that we can do when there are few bombs around. Isles are usually independent and can be solved independently. But if the number of bombs still to be discovered is little enough they starts influencing each other in rather a surprising way i.e. in the final phase of the game the isles aren't so independent after all. 

Suppose, for example that the Solve phase found 2 isles, one with good configurations all using exactly 4 bombs and the other using from 3 to 5 bombs; suppose then that there are still 7 bombs around. It's now clear that all the configurations with 4 and 5 bombs for the 2nd isle must be rejected or the total number of bombs still around should be 8 or 9 respectively. Generalizing such technique Demine tries all possible combinations of bombs and rejects the combinations that requires more bombs than available.
Let 8 be the number of bombs still around, then suppose isle A has configurations with 2 bombs, isle B has configurations with 2, 3 or 4 bombs and isle C configurations with 3 or 4 bombs; Demine considers the following combinations:

A          B           C         Sum

2           2           3          7        OK this combination is accepted
2           2           4          8        OK
2           3           3          8        OK
2           3           4          9        KO this combination is rejected
2           4           3          9        KO
2           4           4          10      KO

From the above example is clear that all configurations with 2 bombs of isle A are accepted, then all configurations with 2 or 3 bombs of isle B are accepted, too and then all configurations with 3 and 4 bombs of isle C are accepted, too. Configurations with 4 bombs of isle B, however, are rejected 'cause they aren't used by any accepted combination. This added bit of information is sometimes enough to discover the position of a bomb or a safe tile.

Configurations can be discarded not only because they require too much bombs, but also because they require too less. Suppose for example that the unstable tiles (not counting contour tiles) are two, then they can hide at most two bombs, so if the still missing bombs number is N all isles must use at least N-2 bombs, not less. A special case of the previous situation is when all the unstable tiles remaining are contour tiles; in such a situation the total number of bombs used by the isles must be exactly equal to the number of still missing bombs. All the combinations that require a different number of bombs can be safely discarded. In the general case N-U (where N is the still missing bombs number and U is the number of the unstable, but not contour, tiles) is a lower limit (when valid) for the number of bombs all isles can use.

 

And that's really all Demine does just to help You !

 

Gianni Luciani

 

September 2006.