[EN] Simple MineSweeper

This article is an experiment to create a Simple MineSweeper as shown in Figure 1, using an ESP32 microcontroller board with a 1.8″ REDTAB st7735 display. The display resolution is 128×160, the same hardware as Simple Tetris [Part 1, Part 2 and part 3] mentioned earlier, still using MicroPython as the main. The explanation starts step by step from screen generation, randomization, counting, motion control, scrolling the options frame turn off visibility, establishing a relationship between identifying where the bomb is likely to be, picking open and counting points at the end of the game.

Simple MineSweeper is one of the first games we’ve been imitating to study ideas and develop programming techniques since the DOS era and the GUI-based Windows operating system DOS, which was written and worked on the DOS operating system at the time, change the mode to graphics mode to contact with mouse and draw pixels by yourself (It’s the same thing as writing on the ESP32 microcontroller board, but it doesn’t have an operating system to use) So let’s get started.

Figure 1 simple mineSweeper

Start building

The written content has two main parts: the first part is the development of the back-end system of the game, which is the data structure for storing the location of the bombs, counting how many bombs there are around, drawing the screen to see the results of the work in the area of randomization and counting the number of bombs around it. And finish with moving by pressing the left, right, top and bottom switches to use for selecting the position of the grid.

Data structure

The design of the game on a 128×160 display with the font size 16×16 forced us to use an 8×6 grid as the game grid and create a variable for storing table data named table as follows

table = [
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0]
]

The data stored in the table contains numbers that have the following meanings:

  • 0 means an empty space or there’s no bombs around.
  • 1-8 means the surrounding area with 1, 2, 3, 4, 5, 6, 7 or 8 bombs according to the specified value.
  • 9 means the location of the bomb

Random the bomb

From the table for collecting the location of the bomb by specifying that if there’s a bomb, let that field store a value of 9 and for ease of display testing. We set the bomb to be displayed as a red square and put a * symbol as shown in Figures 2 and 3.

Figure 2 Random the bomb location
Figure 3 Random the bomb location #2

The randomization algorithm is as follows.

  1. Set the number of successfully random bombs to 0.
  2. Random x and y values. If no bombs are found in the table in row y, column x, then that cell will store 9 and increase the number of successful bombs.
  3. Return to 1 until the required number of bombs is obtained.

Code

    table = [
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0]
    ] 
    counter = 0
    while (counter < 10):
        x = random.randint(1,maxCol)-1
        y = random.randint(1,maxRow)-1
        if (table[y][x] == 0):
            # print("Bomb no.{} at ({},{}).".format(counter+1,x,y))
            table[y][x] = 9
            counter+=1

Counting the bombs around the cell

When the number of bombs in the table is reached as specified. The next step is to count how many bombs are around that position. As an example of the counting result in Figure 4 (displays the location of the bomb as a solid red square).

Figure 4 Counting the bomb around the location

From Figure 4, if set to row 0, column 0 shows that there is no bomb around itself, so it reports a blank. (The number of bombs is 0) but in row 5, column 0, 2 bombs were found: 1 from the above row and 1 from the bottom. In the example of row 5, column 5 found 3 bombs from the left, top and below etc.

The bomb counting algorithm is carried out by dividing the cases of counting as follows:

  • The first row
    • The first column in the first row, Let’s look at it from the right, bottom, and bottom right.
    • The last column in the first row, Let’s look at it from the left, bottom left, and below.
    • The other columns in the first row, look from the left, right, bottom left, bottom, and bottom right.
  • The last row
    • The first column in the last row, Let’s look at it from the top, top right, and right side.
    • is the last column in the last row, Let’s look at it from the left, top left, and above.
    • are the other columns in the last row, Let’s look at it from the left, top left, top, top right, and right.
  • other rows
    • is the first column, Let’s look at it from the top, top right, right, bottom right, and bottom.
    • is the last column, Let’s look at it from the left, top left, top, bottom, and bottom left.
    • Other columns are viewed from the left, top left, top, top right, right, bottom right, bottom and bottom left.

Code

    ## เติมตัวเลข
    for row in range(maxRow):
        for col in range(maxCol):
            sum = 0
            if (table[row][col] != 9):
                if (row == 0): # first row
                    if col == 0: # first col
                        if (table[row][col+1]==9): # right
                            sum += 1
                        if (table[row+1][col]==9): # bottom
                            sum += 1
                        if (table[row+1][col+1]==9): # bottom right
                            sum += 1
                    elif col == maxCol-1: # last col
                        if (table[row][col-1]==9): # left
                            sum += 1
                        if (table[row+1][col-1]==9): # bottpm left
                            sum += 1
                        if (table[row+1][col]==9): # bottom
                            sum += 1
                    else: # other cols
                        if (table[row][col-1]==9): # left
                            sum += 1
                        if (table[row][col+1]==9): # right
                            sum += 1
                        if (table[row+1][col-1]==9): # bottom left
                            sum += 1
                        if (table[row+1][col]==9): # bottom
                            sum += 1
                        if (table[row+1][col+1]==9): # bottom right
                            sum += 1
                elif (row == maxRow-1): # last row
                    if col == 0: # คอลัมน์แรก
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row-1][col+1]==9): # top right
                            sum += 1
                        if (table[row][col+1]==9): # right
                            sum += 1
                    elif col == maxCol-1: # last col
                        if (table[row-1][col-1]==9): # top left
                            sum += 1
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row][col-1]==9): # left
                            sum += 1
                    else: # คอลัมน์อื่น ๆ
                        if (table[row-1][col-1]==9): # top left
                            sum += 1
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row-1][col+1]==9): # top right
                            sum += 1
                        if (table[row][col-1]==9): # left
                            sum += 1
                        if (table[row][col+1]==9): # right
                            sum += 1
                else:
                    if col == 0: # คอลัมน์แรก
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row-1][col+1]==9): # top right
                            sum += 1
                        if (table[row][col+1]==9): # right
                            sum += 1
                        if (table[row+1][col]==9): # bottom
                            sum += 1
                        if (table[row+1][col+1]==9): # bottom right
                            sum += 1
                    elif col == maxCol-1: # last col
                        if (table[row-1][col-1]==9): # top left
                            sum += 1
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row][col-1]==9): # left
                            sum += 1
                        if (table[row+1][col-1]==9): # bottom left
                            sum += 1
                        if (table[row+1][col]==9): # bottom
                            sum += 1
                    else: # คอลัมน์อื่น ๆ
                        if (table[row-1][col-1]==9): # top left
                            sum += 1
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row-1][col+1]==9): # top right
                            sum += 1
                        if (table[row][col-1]==9): # left
                            sum += 1
                        if (table[row][col+1]==9): # right
                            sum += 1
                        if (table[row+1][col-1]==9): # bottom left
                            sum += 1
                        if (table[row+1][col]==9): # bottom
                            sum += 1
                        if (table[row+1][col+1]==9): # bottom right
                            sum += 1
                table[row][col] = sum

Screen drawing to test

Drawing data from the table on the display as shown in Figure 5 is as follows.

    w = 20
    h = 20
    for row in range(6):
        y = row*h+4+2
        for col in range(8):
            x = col*w+2
            if table[row][col]:
                if (table[row][col]== 9):
                    scr.fill_rect(x,y,w-4,h-4, bgColor)
                    scr.text(font,"*",x,y,tft.YELLOW,bgColor)
                else:
                    scr.fill_rect(x,y,w-4,h-4, tft.BLUE)
                    scr.text(font,"{}".format(table[row][col]),x,y,tft.WHITE,tft.BLUE)                
            else:
                scr.fill_rect(x,y,w-4,h-4, tft.BLUE)
Figure 5 Example of showing the location of the bomb and counting the number of bombs

Movement

The movement is performed by pressing the left, right, top, or bottom switches to move the position of the rectangle as shown in Figure 6. The principle of operation is based on memorizing the last position of the current box with the variables posX and posY, as well as writing a draw/delete function. rectangular frame as follows:

def cursor(marked=True):
    w = 20
    h = 20
    if marked:
        scr.rect(posX*w,posY*h+4,w,h,tft.WHITE)
    else:
        scr.rect(posX*w,posY*h+4,w,h,tft.BLACK)

The code part of the four direction switch response is written as follows:

        
    ####################################################### 
    ##### Input : move to the left
    ####################################################### 
    if keL.value() == 0:
        #updated = True
        if (posX > 0):
            cursor(False)
            posX -= 1
            cursor()

    ####################################################### 
    ##### Input : move to the right
    ####################################################### 
    if keR.value() == 0:
        #updated = True
        if (posX < maxCol-1):
            cursor(False)
            posX += 1
            cursor()
            
    ####################################################### 
    ##### Input : move to the top
    ####################################################### 
    if keU.value() == 0:
        #updated = True
        if (posY > 0):
            cursor(False)
            posY -= 1
            cursor()

    ####################################################### 
    ##### Input : move to bottom
    ####################################################### 
    if keD.value() == 0:
        #updated = True
        if (posY < maxRow-1):
            cursor(False)
            posY += 1
            cursor()

Example code 1

Code

#################################################################
# mineSweep Part 1
# JarutEx 2021-11-12
# 128x160
#################################################################
import gc
import os
import sys
import time
import machine as mc
from machine import Pin,SPI, Timer
import math
import st7735 as tft
import vga1_16x16 as font
import random
#################################################################
###### setting ##################################################
#################################################################
gc.enable()
gc.collect()

mc.freq(240000000)

spi = SPI(2, baudrate=26000000,
          sck=Pin(14), mosi=Pin(12),
          polarity=0, phase=0)
#### Key
keL = Pin(39, Pin.IN, Pin.PULL_UP)
keU = Pin(34, Pin.IN, Pin.PULL_UP)
keD = Pin(35, Pin.IN, Pin.PULL_UP)
keR = Pin(32, Pin.IN, Pin.PULL_UP)

swM1 = Pin(33, Pin.IN, Pin.PULL_UP)
swM2 = Pin(25, Pin.IN, Pin.PULL_UP)
swA = Pin(26, Pin.IN, Pin.PULL_UP)
swB = Pin(27, Pin.IN, Pin.PULL_UP)

spk = Pin(19,Pin.OUT)
spk.on()
time.sleep(0.1)
spk.off()

# dc, rst, cs
scr = tft.ST7735(spi, 128, 160, dc=Pin(15, Pin.OUT), reset=Pin(13,Pin.OUT), cs=Pin(2, Pin.OUT), rotation=3)
scr.initr()

Tmr = Timer(0)
Render = Timer(1)
bgColor = tft.color565(0x96,0x24,0x24)
updated = False
gameOver = False
maxRow = const(6)
maxCol = const(8)
table = [
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0]
]
posX = 0
posY = 0

#################################################################
###### sub modules ##############################################
#################################################################
def splash():
    scr.fill(bgColor)
    scr.text(font,"mine", 20, 42, tft.YELLOW, bgColor)
    for i in range(200):
        color = tft.color565(55+i,55+i,55+i)
        scr.text(font,"Sweep", 56, 60, color, bgColor)
        time.sleep_ms(10)
    time.sleep_ms(2000)

def randomTable():
    global table
    table = [
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0]
    ] 
    counter = 0
    while (counter < 10):
        x = random.randint(1,maxCol)-1
        y = random.randint(1,maxRow)-1
        if (table[y][x] == 0):
            # print("Bomb no.{} at ({},{}).".format(counter+1,x,y))
            table[y][x] = 9
            counter+=1
    ## เติมตัวเลข
    for row in range(maxRow):
        for col in range(maxCol):
            sum = 0
            if (table[row][col] != 9):
                if (row == 0): # first row
                    if col == 0: # first col
                        if (table[row][col+1]==9): # right
                            sum += 1
                        if (table[row+1][col]==9): # bottom
                            sum += 1
                        if (table[row+1][col+1]==9): # bottom right
                            sum += 1
                    elif col == maxCol-1: # last col
                        if (table[row][col-1]==9): # left
                            sum += 1
                        if (table[row+1][col-1]==9): # bottom left
                            sum += 1
                        if (table[row+1][col]==9): # bottom
                            sum += 1
                    else: # คอลัมน์อื่น ๆ
                        if (table[row][col-1]==9): # left 
                            sum += 1
                        if (table[row][col+1]==9): # right
                            sum += 1
                        if (table[row+1][col-1]==9): # bottom left
                            sum += 1
                        if (table[row+1][col]==9): # bottom
                            sum += 1
                        if (table[row+1][col+1]==9): # bottom right
                            sum += 1
                elif (row == maxRow-1): # last row
                    if col == 0: # คอลัมน์แรก
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row-1][col+1]==9): # top right
                            sum += 1
                        if (table[row][col+1]==9): # right
                            sum += 1
                    elif col == maxCol-1: # last col
                        if (table[row-1][col-1]==9): # top left
                            sum += 1
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row][col-1]==9): # left
                            sum += 1
                    else: # คอลัมน์อื่น ๆ
                        if (table[row-1][col-1]==9): # top left
                            sum += 1
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row-1][col+1]==9): # top right
                            sum += 1
                        if (table[row][col-1]==9): # left
                            sum += 1
                        if (table[row][col+1]==9): # right
                            sum += 1
                else:
                    if col == 0: # first col
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row-1][col+1]==9): # top right
                            sum += 1
                        if (table[row][col+1]==9): # right
                            sum += 1
                        if (table[row+1][col]==9): # bottom
                            sum += 1
                        if (table[row+1][col+1]==9): # bottom right
                            sum += 1
                    elif col == maxCol-1: # last col
                        if (table[row-1][col-1]==9): # top left
                            sum += 1
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row][col-1]==9): # left
                            sum += 1
                        if (table[row+1][col-1]==9): # bottom left
                            sum += 1
                        if (table[row+1][col]==9): # bottom
                            sum += 1
                    else: # คอลัมน์อื่น ๆ
                        if (table[row-1][col-1]==9): # top left
                            sum += 1
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row-1][col+1]==9): # top right
                            sum += 1
                        if (table[row][col-1]==9): # left
                            sum += 1
                        if (table[row][col+1]==9): # right
                            sum += 1
                        if (table[row+1][col-1]==9): # bottom left
                            sum += 1
                        if (table[row+1][col]==9): # bottom
                            sum += 1
                        if (table[row+1][col+1]==9): # bottom right
                            sum += 1
                table[row][col] = sum

def cbInput(x):
    global updated, posX, posY
    ####################################################### 
    ##### Input
    ####################################################### 
    if (swM2.value() == 0):
        randomTable()
        updated = True
        
    ####################################################### 
    ##### Input : move to the left
    ####################################################### 
    if keL.value() == 0:
        #updated = True
        if (posX > 0):
            cursor(False)
            posX -= 1
            cursor()

    ####################################################### 
    ##### Input : move to the right
    ####################################################### 
    if keR.value() == 0:
        #updated = True
        if (posX < maxCol-1):
            cursor(False)
            posX += 1
            cursor()
            
    ####################################################### 
    ##### Input : move to top
    ####################################################### 
    if keU.value() == 0:
        #updated = True
        if (posY > 0):
            cursor(False)
            posY -= 1
            cursor()

    ####################################################### 
    ##### Input : move to bottom
    ####################################################### 
    if keD.value() == 0:
        #updated = True
        if (posY < maxRow-1):
            cursor(False)
            posY += 1
            cursor()

def cbRender(x):
    global updated
    ####################################################### 
    ##### screen updated
    ####################################################### 
    if (updated):
        draw()
        updated = False
        

def draw():
    w = 20
    h = 20
    for row in range(6):
        y = row*h+4+2
        for col in range(8):
            x = col*w+2
            if table[row][col]:
                if (table[row][col]== 9):
                    scr.fill_rect(x,y,w-4,h-4, bgColor)
                    scr.text(font,"*",x,y,tft.YELLOW,bgColor)
                else:
                    scr.fill_rect(x,y,w-4,h-4, tft.BLUE)
                    scr.text(font,"{}".format(table[row][col]),x,y,tft.WHITE,tft.BLUE)                
            else:
                scr.fill_rect(x,y,w-4,h-4, tft.BLUE)

def cursor(marked=True):
    w = 20
    h = 20
    if marked:
        scr.rect(posX*w,posY*h+4,w,h,tft.WHITE)
    else:
        scr.rect(posX*w,posY*h+4,w,h,tft.BLACK)


#################################################################
###### main program #############################################
#################################################################
#splash()
randomTable()
scr.fill(tft.BLACK)
draw()
cursor()
Tmr.init( period=200, mode=Timer.PERIODIC, callback=cbInput)
Render.init( period=100, mode=Timer.PERIODIC, callback=cbRender)
while swM1.value():
    pass
scr.fill(0)
Tmr.deinit()
Render.deinit()
spi.deinit()

Adjustment

From the program code in the first part, it is called the function of the backend which allows program developers to see the data in the location. But if the players saw this information, there would be no challenge. Therefore, there must be a screen for closing the player not to see, as shown in Figure 6.

Data Structure 2

Figure 6 Display data from plate

To create a challenge and give the player an idea of ​​predicting the location of the bomb, a variable for holding the state of each cell has been created as a variable named plate, which has the following values:

  • 0 means it hasn’t been opened yet.
  • 1 means it has been opened
  • 2 means the location that the player determines to be the location of the bomb.

The data structure of the plate is as follows: when randomizing the location of the bomb, the plate will be set to 0 in all fields.

plate = [
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0]
]

Bomb marking

This example game design stipulates that if a location is where the player thinks it’s a bomb, press swB to change that cell’s state to the expected bomb location along with showing the mark ! As shown in Figure 7.

Figure 7 An example of a cell marked as explodin

From Figure 7 added the count of the bomb mark is stored in the markCounter variable and if the player presses the same position, it means canceling the position as the program code as follows:

    ####################################################### 
    ##### Input : maybe bomb
    ####################################################### 
    if swB.value() == 0:
        if (plate[posY][posX] == 0):
            if (markCounter < maxBomb): # less than the number of bomb
                plate[posY][posX] = 2
                markCounter += 1
                updated = True
        elif (plate[posY][posX] == 2):
            plate[posY][posX] = 0
            markCounter -= 1
            updated = True

Opening

Turning on changes the plate’s state to 1 and checks the value of the table variable at that position, and if it’s 9, it explodes, it’s game over. If not, it will display the value of the number of bombs as shown in Figures 1 and 8.

Figure 8 An example of the result of pressing swA to open the plate’s slot.

From Figure 8, the code for the SWA response is as follows:

    ####################################################### 
    ##### Input : choose
    ####################################################### 
    if swA.value() == 0:
        if (plate[posY][posX] == 0):
            if (table[posY][posX] == 9):
                gameOver = True
            plate[posY][posX] = 1
            updated = True

The display has been changed, if any plate is 0, it shows solid, if 1 it shows the value from the table, and if 2 it shows ! As shown in Figure 7, the program code is as follows.

    w = 20
    h = 20
    for row in range(6):
        y = row*h+4+2
        for col in range(8):
            x = col*w+2
            if plate[row][col]:
                if (plate[row][col] == 1):
                    if (table[row][col]== 9):
                        scr.fill_rect(x,y,w-4,h-4, bgColor)
                        scr.text(font,"*",x,y,tft.YELLOW,bgColor)
                    else:
                        scr.fill_rect(x,y,w-4,h-4, tft.BLUE)
                        if (table[row][col] > 0):
                            scr.text(font,"{}".format(table[row][col]),x,y,tft.WHITE,tft.BLUE)
                else:
                    scr.fill_rect(x,y,w-4,h-4, tft.GRAY)
                    scr.text(font,"!",x,y,tft.BLACK,tft.GRAY)
            else:
                scr.fill_rect(x,y,w-4,h-4, tft.GRAY)

Counting the scores.

The score is counted based on the number of bomb guesses the player has and displays the result to end the game as in the example in Figure 9. The concept is as follows in the program code, that is, if any of the plate’s fields have a value of 2 and match a table that holds a value of 9, which is the value of that position. Mark that it was a bomb with the locationon of the bomb. The score will be increased by 1 point.

score = 0
for i in range(maxRow):
    for j in range(maxCol):
        if ((plate[i][j] == 2) and (table[i][j] == 9)):
            score += 1
Figure 9 Display the score

Example Code

Code

#################################################################
# mineSweep Part2
# JarutEx 2021-11-12
# 128x160
#################################################################
import gc
import os
import sys
import time
import machine as mc
from machine import Pin,SPI, Timer
import math
import st7735 as tft
import vga1_16x16 as font
import random
#################################################################
###### setting ##################################################
#################################################################
gc.enable()
gc.collect()

mc.freq(240000000)

spi = SPI(2, baudrate=26000000,
          sck=Pin(14), mosi=Pin(12),
          polarity=0, phase=0)
#### Key
keL = Pin(39, Pin.IN, Pin.PULL_UP)
keU = Pin(34, Pin.IN, Pin.PULL_UP)
keD = Pin(35, Pin.IN, Pin.PULL_UP)
keR = Pin(32, Pin.IN, Pin.PULL_UP)

swM1 = Pin(33, Pin.IN, Pin.PULL_UP)
swM2 = Pin(25, Pin.IN, Pin.PULL_UP)
swA = Pin(26, Pin.IN, Pin.PULL_UP)
swB = Pin(27, Pin.IN, Pin.PULL_UP)

spk = Pin(19,Pin.OUT)
spk.on()
time.sleep(0.1)
spk.off()

# dc, rst, cs
scr = tft.ST7735(spi, 128, 160, dc=Pin(15, Pin.OUT), reset=Pin(13,Pin.OUT), cs=Pin(2, Pin.OUT), rotation=3)
scr.initr()

Tmr = Timer(0)
Render = Timer(1)
bgColor = tft.color565(0x96,0x24,0x24)
updated = False
gameOver = False
maxRow = const(6)
maxCol = const(8)
maxBomb = const(7)
table = [
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0]
]
plate = [
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0]
]
posX = 0
posY = 0
markCounter = 0

#################################################################
###### sub modules ##############################################
#################################################################
def splash():
    scr.fill(bgColor)
    scr.text(font,"mine", 20, 42, tft.YELLOW, bgColor)
    for i in range(200):
        color = tft.color565(55+i,55+i,55+i)
        scr.text(font,"Sweep", 56, 60, color, bgColor)
        time.sleep_ms(10)
    time.sleep_ms(2000)

def randomTable():
    global table,plate,markCounter
    table = [
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0]
    ] 
    plate = [
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0]
    ] 
    counter = 0
    markCounter=0
    while (counter < maxBomb):
        x = random.randint(1,maxCol)-1
        y = random.randint(1,maxRow)-1
        if (table[y][x] == 0):
            # print("Bomb no.{} at ({},{}).".format(counter+1,x,y))
            table[y][x] = 9
            counter+=1
    ## fill the number
    for row in range(maxRow):
        for col in range(maxCol):
            sum = 0
            if (table[row][col] != 9):
                if (row == 0): # first row
                    if col == 0: # first col
                        if (table[row][col+1]==9): # right
                            sum += 1
                        if (table[row+1][col]==9): # bottom
                            sum += 1
                        if (table[row+1][col+1]==9): # bottom right
                            sum += 1
                    elif col == maxCol-1: # last col
                        if (table[row][col-1]==9): # left
                            sum += 1
                        if (table[row+1][col-1]==9): # bottom left
                            sum += 1
                        if (table[row+1][col]==9): # bottom
                            sum += 1
                    else: # คอลัมน์อื่น ๆ
                        if (table[row][col-1]==9): # left
                            sum += 1
                        if (table[row][col+1]==9): # right
                            sum += 1
                        if (table[row+1][col-1]==9): # bottom left
                            sum += 1
                        if (table[row+1][col]==9): # bottom
                            sum += 1
                        if (table[row+1][col+1]==9): # bottom right
                            sum += 1
                elif (row == maxRow-1): # last row
                    if col == 0: # คอลัมน์แรก
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row-1][col+1]==9): # top right
                            sum += 1
                        if (table[row][col+1]==9): # right
                            sum += 1
                    elif col == maxCol-1: # last col
                        if (table[row-1][col-1]==9): # top left
                            sum += 1
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row][col-1]==9): # left
                            sum += 1
                    else: # other cols
                        if (table[row-1][col-1]==9): # top left
                            sum += 1
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row-1][col+1]==9): # top right
                            sum += 1
                        if (table[row][col-1]==9): # left
                            sum += 1
                        if (table[row][col+1]==9): # right
                            sum += 1
                else:
                    if col == 0: # first col
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row-1][col+1]==9): # top right
                            sum += 1
                        if (table[row][col+1]==9): # right
                            sum += 1
                        if (table[row+1][col]==9): # bottom
                            sum += 1
                        if (table[row+1][col+1]==9): # bottom right
                            sum += 1
                    elif col == maxCol-1: # last col
                        if (table[row-1][col-1]==9): # top left
                            sum += 1
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row][col-1]==9): # left
                            sum += 1
                        if (table[row+1][col-1]==9): # bottom left
                            sum += 1
                        if (table[row+1][col]==9): # bottom
                            sum += 1
                    else: # คอลัมน์อื่น ๆ
                        if (table[row-1][col-1]==9): # top left
                            sum += 1
                        if (table[row-1][col]==9): # top
                            sum += 1
                        if (table[row-1][col+1]==9): # top right
                            sum += 1
                        if (table[row][col-1]==9): # left
                            sum += 1
                        if (table[row][col+1]==9): # right
                            sum += 1
                        if (table[row+1][col-1]==9): # bottom left
                            sum += 1
                        if (table[row+1][col]==9): #  bottom
                            sum += 1
                        if (table[row+1][col+1]==9): # bottom right
                            sum += 1
                table[row][col] = sum

def cbInput(x):
    global updated, posX, posY, table, plate, gameOver, markCounter
    ####################################################### 
    ##### Input
    ####################################################### 
    if (swM2.value() == 0):
        randomTable()
        updated = True
        
    ####################################################### 
    ##### Input : move to the left
    ####################################################### 
    if keL.value() == 0:
        #updated = True
        if (posX > 0):
            cursor(False)
            posX -= 1
            cursor()

    ####################################################### 
    ##### Input : move to the right
    ####################################################### 
    if keR.value() == 0:
        #updated = True
        if (posX < maxCol-1):
            cursor(False)
            posX += 1
            cursor()
            
    ####################################################### 
    ##### Input : move to top
    ####################################################### 
    if keU.value() == 0:
        #updated = True
        if (posY > 0):
            cursor(False)
            posY -= 1
            cursor()

    ####################################################### 
    ##### Input : move to bottom
    ####################################################### 
    if keD.value() == 0:
        #updated = True
        if (posY < maxRow-1):
            cursor(False)
            posY += 1
            cursor()
            
    ####################################################### 
    ##### Input : choose
    ####################################################### 
    if swA.value() == 0:
        if (plate[posY][posX] == 0):
            if (table[posY][posX] == 9):
                gameOver = True
            plate[posY][posX] = 1
            updated = True

    ####################################################### 
    ##### Input : maybe bomb
    ####################################################### 
    if swB.value() == 0:
        if (plate[posY][posX] == 0):
            if (markCounter < maxBomb): # less than the bomb number
                plate[posY][posX] = 2
                markCounter += 1
                updated = True
        elif (plate[posY][posX] == 2):
            plate[posY][posX] = 0
            markCounter -= 1
            updated = True
            

def cbRender(x):
    global updated
    ####################################################### 
    ##### screen update
    ####################################################### 
    if (updated):
        draw()
        updated = False
        

def draw():
    w = 20
    h = 20
    for row in range(6):
        y = row*h+4+2
        for col in range(8):
            x = col*w+2
            if plate[row][col]:
                if (plate[row][col] == 1):
                    if (table[row][col]== 9):
                        scr.fill_rect(x,y,w-4,h-4, bgColor)
                        scr.text(font,"*",x,y,tft.YELLOW,bgColor)
                    else:
                        scr.fill_rect(x,y,w-4,h-4, tft.BLUE)
                        if (table[row][col] > 0):
                            scr.text(font,"{}".format(table[row][col]),x,y,tft.WHITE,tft.BLUE)
                else:
                    scr.fill_rect(x,y,w-4,h-4, tft.GRAY)
                    scr.text(font,"!",x,y,tft.BLACK,tft.GRAY)
            else:
                scr.fill_rect(x,y,w-4,h-4, tft.GRAY)

def cursor(marked=True):
    w = 20
    h = 20
    if marked:
        scr.rect(posX*w,posY*h+4,w,h,tft.WHITE)
    else:
        scr.rect(posX*w,posY*h+4,w,h,tft.BLACK)
        
    

#################################################################
###### main program #############################################
#################################################################
#splash()
randomTable()
scr.fill(tft.BLACK)
draw()
cursor()
Tmr.init( period=150, mode=Timer.PERIODIC, callback=cbInput)
Render.init( period=33, mode=Timer.PERIODIC, callback=cbRender)
while (swM1.value() and (gameOver==False)):
    pass
Tmr.deinit()
Render.deinit()
if (gameOver):
    draw()
score = 0
for i in range(maxRow):
    for j in range(maxCol):
        if ((plate[i][j] == 2) and (table[i][j] == 9)):
            score += 1
            
scr.fill(tft.BLACK)
scr.text(font,"Score={}".format(score),8,8,tft.WHITE,tft.BLACK)

spi.deinit()

Conclusion

From this article, you will find that Simple MineSweeper still needs to improve one important task. If the player selects and hits an empty area or keeps the value 0, the game must open all adjacent empty areas to be visible and collect statistics for playing. As for the main work of this example, it will make it easy for those who lead to further studies to improve. Finally, we hope that the example of this article was helpful and gave some ideas to those who are interested in developing simple and easy-to-make games on their own. Have fun programming.

(C) 2020-2022, By Jarut Busarathid and Danai Jedsadathitikul
Updated 2022-01-20