Minesweeper-Raspberry-Pi-Edition

by FrancisGauthier in Circuits > Raspberry Pi

1247 Views, 3 Favorites, 0 Comments

Minesweeper-Raspberry-Pi-Edition

_MG_3552.png
_MG_3547.png

My final project for the CSC 130 series at Louisiana Tech University is the Minesweeper Raspberry Pi Edition. In this project, I sought to recreate the classic game of minesweeper by utilizing the Tkinter library of the Python programming language. The grid that the minesweeper game encompasses is eight tiles in width and five tiles in height. The formatting of the project has been suited and perfected for the use of a Raspberry Pi installed with Python 2.7.

The code and images for the Minesweeper Raspberry Pi Edition final project can be downloaded at the following link:

Minesweeper-Raspberry-Pi-Edition

Supplies

x1 Raspberry Pi

Python 2.7 Installed on the Raspberry Pi

Microsoft Powerpoint (or another software to create images for buttons)

Create Button Images

Step 1.png

EXPLANATION:

Each button that makes up the GUI will need to be created. For this task, I used Microsoft Powerpoint to make the images I needed to display on the buttons.

First, I created the ten tile buttons needed to make the minesweeper grid (blank, bob, zero, one, two, three, four, five, six, seven, and eight) using Microsoft Powerpoint.

Second, I made the four images needed for the menu screen (menu display, easy difficulty button, medium difficulty button, and hard difficulty button) using Microsoft Powerpoint.

Third, I created the image needed for the restart button and the images needed for the other different display buttons (a "game over" display, a "you win" display, and a "rules" display) using Microsoft Powerpoint.

Fourth, you will have to resize your images to fit within your screen. For my Rasberry Pi, I used the following dimensions for the window (referring to pixels in length and width): 432x576.

Format Program

Step 2.png

EXPLANATION:

Before any actual programming can take place, we must import the libraries we need and write the main part of our program.

First, we will need to import * from the Tkinter library and shuffle from the random library. Secondly, we will need to complete the following steps in code within the main part of the program: create the window, set the title window, generate the GUI, and display the GUI and wait for user interaction. This code is written in proper formatting in respect to the Tkinter library (look at the code given in the instructable to see proper formatting).

Create the GUI (Menu & Minesweeper Grid)

Step 2 COLON Menu.png
Step 2 COLON Game Screen.png
Step 3 (1).png
Step 3 (2).png

EXPLANATION:

Upon the startup of the program, the menu screen shall be launched. After the difficulty is selected (by clicking one of the difficulty buttons on the menu screen), the GUI shall be refreshed with the minesweeper grid, a display, and a restart button. Since you are just starting on working on the GUI, we will only need to get the menu to launch, have the menu difficulty buttons become operational, and have the GUI refresh to the game screen with the minesweeper grid.

First, we can have the menu screen display itself upon the startup of the program by calling the "setupMenu" method within the constructor of the MainGUI class.

Second, we can have each of the menu's difficulty buttons execute certain lines of code whenever clicked by adding a "process" method (will also have to add command lambda: self.process("returnButtonName") within the parameters of the button function used in the creation of each difficulty button). Three if-else statements will be created in the "process" method and execute certain other methods and lines of additional code depending on what the button equals (button equals whatever the button name that was last registered).

Third, while the menu screen is up and if the user clicks on one of the difficulty buttons, then the program will save a certain value to the "difficulty" variable (difficulty equals "easy', "medium", or "hard" based off which difficulty button is clicked). This click of a button knows which if-else statement to follow based on what button name was last registered (what button equals). Additionally, to reassign the "difficulty" variable we will need to first instantiate it outside of the class. So we will set the "difficulty" variable as an empty string before the "MainGUI" class is created.

Fourth, clear the GUI of the buttons made by the "setupMenu" method by making a "clearMenu" method (using the button.destroy() function in multiple instances) and calling the "clearMenu" method in the "process" method (under each of the difficulty button registers after the difficulty variable assignment).

Fifth, refresh the GUI by making a "setSLASHresetGUI" method (buttons are made the same way as in the "setupMenu" method) and calling the "setSLASHresetGUI" method in the "process" method (under each of the difficulty button registers after the difficulty variable assignment and calling the "clearMenu" method).

Additionally, before all the buttons are assigned within the "setSLASHresetGUI" method we must configure the rows and columns within the grid and after all the buttons are assigned within the "setSLASHresetGUI" method we must pack all the contents within the grid (look at the code given in the instructable to see proper formatting).

Make the Buttons on the In-Game Screen Operational

Step 4 (1).png
Step 4 (2).png
Step 4 (3).png
Step 4 (4).png

EXPLANATION:

To make the buttons execute certain lines of code when clicked, we will have to execute methods within the "process" method. For this task, we will have to make multiple new methods, variables, and lists.

First, we will make two lists. There will be a list called "grid". This "grid" list will consist of only the integers 9 and 0. In this list, nines will represent bombs, and zeros will represent non-bombs. This is how the program will distinguish if a tile is a bomb or not. A second list will be made, and it will be called "status". This "status" list consists of only one character strings ("0", "1", "2", "3", "4", "5", "6", "7", "8", "b"). In this list, each one character string will correspond to a certain image. This is how the program will know what image to display on each button in the minesweeper grid. Each button in the minesweeper grid will have a corresponding index in each list based on its placement in the grid. The corresponding index will be assigned by the following procedure (button number - 1). For example, button one's corresponding index in each list is index zero. Lastly, these two lists will be executed before the "MainGUI" class is executed and will be created outside of the "MainGUI" class. The "grid" class will be created as an empty list (grid = []) and the "status" list will be created by a range function (adding forty single character strings of "n" to the "status" list).

Second, we will make various methods that can detect the number of mines surrounding it and that can be called upon when a button's clicked (the decision of which method that should be executed shall be determined by the placement of the button). These very methods will be called our mine analyzers. These methods will increment a counter called "NumOfMines" and will use certain indexes within the "grid" list to determine how many bombs surround the tile. The string that will be stored within the variable "NumOfMines" will be used to replace the same corresponding index in the "status" list. Now, you may wonder how the program will know which index to use. When a button is registered in the "process" method, then a variable "index" will be created/reassigned to a certain integer (based on what string the button registers). One of the methods created will use that assigned index in order to know the placement of the tile and the indexes of the tiles surrounding it (algorithm within the method will figure this out). Additionally, to reassign the "index" variable we will need to first instantiate it outside of the class. So we will preset the "index" variable as the integer zero before the "MainGUI" class is created.

Third, "operation" methods will be created. An "operation" method will be executed every time a button is registered. These "operation" methods will be executed in the "process" method. In the "process" method, multiple if-else statements will determine which button was clicked (based on what the button equals). This is where a certain "operation" method will be called upon (in the if-else statements).

Fourth, we will actually get into how the buttons become operational. As stated previously, multiple if-else statements are located in the "process" method and execute certain other methods and lines of additional code depending on what the button equals (button equals whatever the string was that was last registered). Within these if-else statements, the following will occur in order: index will be assigned globally, that corresponding index in the "status" list will be reassigned to the string "b" (if the corresponding index of the "grid" list equals the integer nine), a corresponding "operation" method will be executed (if the corresponding index of the "grid" list equals the integer zero), that corresponding index in the "status" list will be reassigned to a string that equals the variable "NumOfMines" (if the corresponding index of the "grid" list equals the integer zero), and the GUI will be refreshed by calling the "setSLASHresetGUI" method.

"setDifficulty" Method & "restart" Method

Step 5 (1).png
Step 5 (2).png

EXPLANATION:

Next, a "setDifficulty" method will need to be created and the restart button located at the bottom of the in-game screen will need to become operational (by creating a "restart" method for it to execute when it is clicked by the user).

First, the "setDifficulty" method will need to be implemented in the if-else statements of the difficulty buttons in the "process" method and in the "restart" method. The lines of code and methods executed in this method are quite simple. In the "setDifficulty" method, we will append a certain quantity of zeros (non-bombs) and nines (bombs) to the "grid" list (via two range functions within each if-else statement), and then we will shuffle the "grid" list (with the random library's shuffle function) within the "setDifficulty" method (after the if-else statements are executed). The ratio of zeros to nines will be determined by what string the variable "difficulty" is set to ("easy": 34-6, "medium": 28-12, "hard": 16-24).

Second, in the "restart" method, we will set the variables "index" and "NumOfMinesLEFT" to zero globally, empty both the "status" and "grid" lists globally, reset the "status" list with a range function (adding forty single character strings of "n" to the "status" list), and call upon the "setDifficulty" method.

Game-Ending Scenarios

You_Win.png
GameOver.png
Step 6 (1).png
Step 6 (2).png

EXPLANATION:

Every minesweeper game has two game-ending scenarios: win and loss. Within this program, we will implement these two game-ending scenarios with two new methods: a "You_A_Winner_Son" method and a "GameOver" method. Before the GUI is refreshed within the "process" method and based on the indexes changed by the two game-ending scenario methods, the display button will be changed to properly represent the outcome.

First, when the user clicks on the last hidden non-bomb tile, then the "You_A_Winner_Son" method must be executed. We will complete this task by calling upon the "You_A_Winner_Son" method every time a tile is clicked and the tile is found to be a non-bomb tile (within the "operation" methods executed in the "process" method). If the winning conditions are met, then two if-else statements within the "You_A_Winner_Son" method will be executed. The first if-else statement will always execute regardless if the player won or not when this method is called upon. Based on what the variable "difficulty" is equal to, a certain algorithm that will determine how many mines/bombs are left hidden. The integer that is found by this algorithm will be saved in the variable "NumOfMinesLEFT". Next, inbetween the two if-else statement another algorithm will be executed to find the number of starting tiles left (unclicked tiles). The integer that is found by this algorithm will be saved in the variable "NumOfStartingTilesLEFT". The second if-else statement will always execute regardless if the player won or not when this method is called upon. Based on what the variable "difficulty" is equal to, one of three if-else statements may be executed if their conditions are met. The conditions will be based what the two variables "NumOfMinesLEFT" and "NumOfStartingTilesLEFT" equal to. Within these three if-else statements, an algorithm will be executed that will render each button useless (the game is over).

Second, when the user clicks on one of the hidden bomb tiles, then the "GameOver" method must be executed. We will complete this task by calling upon the "GameOver" method every time a tile is clicked and the tile is found to be a bomb tile (within the "operation" methods executed in the "process" method). When the "GameOver" method is called upon, an algorithm will be executed that will render each starting tile useless (the game is over) and the hidden bomb tiles will be revealed (based on the corresponding indexes within the "grid list, certain indexes in the "status" list will be reassigned to the single-character string "b").

Third, the display of the in-game screen will be updated every time the GUI is refreshed by making very few minor edits to the "setSLASHresetGUI" method. After the grid of the GUI is configured, we will place three if-else statements where the current display button assignment is placed. One of the three if-else statements will execute based on what the following variables are equal to: "GameOverDETECTOR", "difficulty, "NumOfMinesLEFT", and "NumOfStartingTilesLEFT". As you may be wondering, the variable "GameOverDETECTOR" is a new variable. This variable will be created right before the if-else statements are executed within the "setSLASHresetGUI" method. The "GameOverDETECTOR" variable will be equal to the integer that is found using an algorithm that finds how many indexes within the "grid" list have reassigned to the integer ninety-nine (how the buttons are rendered useless). Based on which if-else statement's conditions are met, a corresponding reassignment to the display will occur.

Making the Restart Button Operational

Step 5.png

EXPLANATION:

This step happens to be the shortest. Most of the work for this step has already been done. All we will need to do now is execute the "restart" method every time the restart button is clicked by the user.

First and lastly, we will execute the "restart" method in the "process" method with an if-else statement. If the string "!" is registered, then the "restart" method shall be executed. We will also have to create a button called restart at the end of the "setSLASHresetGUI" method before the contents of the grid are packed together. This restart button will process the string "!" (command lambda: self.process("!")) and execute the corresponding "restart" method within the "process" method.