Señor Smiley says, "deal with it" |
Introduction
Your head a splode |
The two right-most squares on the bottom row have a 50% chance of containing a mine. |
I'm interested in creating an algorithm that will track the probability of containing a mine for each element in the grid. Primarily, I want to explore whether or not I can utilize Bayes' rule to calculate subsequent probability distributions by leveraging the current distribution. More explicitly, if the game is split into a sequence of choices and their resulting game states, I want to find out whether or not I can leverage the probability distribution at state n along with the measurement (the number of mines adjacent to the latest revealed element) in order to calculate the distribution at n+1. I believe that I can do this by framing the question in terms of conditional probability. After a measurement is made, the probability of a particular element containing a mine conditioned on the measurement can be computed using Bayes rule.
Bayes' Rule |
This is not necessarily an efficient approach to solving games of Minesweeper. Depending on the mine density, some games can be solved without ever relying on guessing. Therefore, one strategy that would be more efficient than this one would be to apply deductive elimination whenever possible and calculate the probability distribution (as needed) directly from the current game state. My hope is that, if I develop the probabilistic approach correctly, the deductive methods will emerge organically.
Python Tkinter Minesweeper
The solver needs access to a few pieces of information to start: the total number of mines and the dimensions of the grid. In addition, at every step of the game, it needs the location of the latest revealed element and the measurement at that position.In order to make this information available, I decided to create my own version of Minesweeper in Python using Tkinter. While I could have borrowed an open-source implementation or written an interface for the Windows version that could interpret the current state of the board visually, I was compelled to write my own version because it seemed relatively fun and straightforward. I chose to use Python because the Tkinter package is available with the default installation and is useful for quick and easy GUI development.
Señor Smiley |
Silly win condition |
The game must also guarantee that the first user-selected element is not a mine. This can be done by waiting to generate the random mine distribution after the first selection is made, excluding the current selection.
Empty elements reveal adjacent squares. |
Implementation Overview
I encapsulated everything in a single minesweeper class which inherits from the tkinter.Tk class. On initialization, a grid of buttons are created and stored in a list, the solver is initialized, and all of the other GUI features are initialized. When tkinter buttons are initialized, the "command" callback function can be defined as a lambda function with constant arguments indicating the location of the button.In that way, a general callback function is defined for all of the grid buttons which will uniquely address their location in the grid. When the user makes the first selection, the game generates a random distribution of mines, always excluding the selected square.
First choice never results in a mine. |
Right-click callback functions are assigned to grid buttons with tkinter's "bind" function. This callback function cycles the text parameter in the referenced button object through a sequence of symbols: an empty string, a flag "F", and a question mark.
Currently, game parameters (width, height, number of mines) are defined as command line arguments when running minesweeper.py. There is no way of modifying these parameters in the game. Additionally a minesweeperSolver is instantiated within the minesweeper class; whether or not it is allowed to make selections in the grid is optional, but the solver is always running in the background. This might cause problems when trying to play a particularly large game manually. The user may also choose to allow the solver to highlight the recommended square in green.
Ideally, for the sake of organization, there would be a container or parent application which would instantiate both minesweeper and the minesweeperSolver. I don't intend to change these organizational things as they aren't really part of my focus.
In later posts, I will describe my process for developing the minesweeperSolver class using Bayes' rule. As of this post, there are still issues with the solver. I'm trying to determine whether or not the problem is with my theoretical approach or in the implementation. Somewhere along my quest for a purely probabilistic solver, I ended up creating a constraint-based algorithm. I am starting to wonder if I would be better off abandoning the current measurement-update model; more on that next time.
No comments:
Post a Comment