Article \ | wild guest

Source: Python Technology “ID: pythonall”

Minesweeper is a puzzle game that was first released by Microsoft on Windows in 1992. The game is suitable for all ages. The rules are simple: find all the non-lightning grids in the shortest time and do not step on the mines in the process.

In this article we use Python to implement minesweeper games, the main Python library is PyGame.

implementation

The game is composed of relatively simple, mainly including: small squares, timers, mines and so on.

First, we initialize some constants, such as the number of vertical and horizontal squares, the number of mines, mouse clicks, etc., as shown below:

BLOCK_WIDTH = 30
BLOCK_HEIGHT = 16# block SIZE SIZE =20# Number of mines MINE_COUNT =66# no click normal =1# Opened =2# mine =3# Flag mine =4# mark with question mark ask =5# Step on a landmine bomb =6# double click around hint =7# double-click double = by mouse button8
readied = 1,
started = 2,
over = 3,
win = 4
Copy the code

Then define a mine class, which defines some basic attributes (such as coordinates, states, etc.) and get, set methods, the code implementation is as follows:

class Mine:
    def __init__(self, x, y, value=0):
        self._x = x
        self._y = y
        self._value = 0
        self._around_mine_count = - 1
        self._status = normal
        self.set_value(value)
    def __repr__(self):
        return str(self._value)
    def get_x(self):
        return self._x
    def set_x(self, x):
        self._x = x
    x = property(fget=get_x, fset=set_x)
    def get_y(self):
        return self._y
    def set_y(self, y):
        self._y = y
    y = property(fget=get_y, fset=set_y)
    def get_value(self):
        return self._value
    def set_value(self, value):
        if value:
            self._value = 1
        else:
            self._value = 0
    value = property(fget=get_value, fset=set_value, doc='0: non-mine 1: mine ')
    def get_around_mine_count(self):
        return self._around_mine_count
    def set_around_mine_count(self, around_mine_count):
        self._around_mine_count = around_mine_count
    around_mine_count = property(fget=get_around_mine_count, fset=set_around_mine_count, doc='Number of mines around')
    def get_status(self):
        return self._status
    def set_status(self, value):
        self._status = value
    status = property(fget=get_status, fset=set_status, doc='BlockStatus')
Copy the code

We then define a MineBlock class that handles the basic minesweeping logic as follows:

class MineBlock:
    def __init__(self):
        self._block = [[Mine(i, j) for i in range(BLOCK_WIDTH)] for j in range(BLOCK_HEIGHT)] # minefor i in random.sample(range(BLOCK_WIDTH * BLOCK_HEIGHT), MINE_COUNT):
            self._block[i // BLOCK_WIDTH][i % BLOCK_WIDTH].value = 1
    def get_block(self):
        return self._block
    block = property(fget=get_block)
    def getmine(self, x, y):
        returnSelf._block[y][x] def open_mine(self, x, y)if self._block[y][x].value:
            self._block[y][x].status = bomb
            return_block[y][x]. Status = Opened around = _get_around(x, y) _sum =0
        for i, j in around:
            if self._block[j][i].value:
                _sum += 1Self._block[y][x]. Around_mine_count = _sum #8I'm going to recurse over all of themif _sum == 0:
            for i, j in around:
                if self._block[j][i].around_mine_count == - 1:
                    self.open_mine(i, j)
        return True
    def double_mouse_button_down(self, x, y):
        if self._block[y][x].around_mine_count == 0:
            returnTrue self._block[y][x]. Status = double around = _get_around(x, y) #0
        for i, j in _get_around(x, y):
            if self._block[j][i].status == flag:
                sumflag += 1# all surrounding mines have been marked result = Trueif sumflag == self._block[y][x].around_mine_count:
            for i, j in around:
                if self._block[j][i].status == normal:
                    if not self.open_mine(i, j):
                        result = False
        else:
            for i, j in around:
                if self._block[j][i].status == normal:
                    self._block[j][i].status = hint
        return result
    def double_mouse_button_up(self, x, y):
        self._block[y][x].status = opened
        for i, j in _get_around(x, y):
            if self._block[j][i].status == hint:
                self._block[j][i].status = normal
Copy the code

Next, we initialize the interface. First, a panel composed of small squares is generated. The main code is as follows:

for row in block.block:
 for mine in row:
  pos = (mine.x * SIZE, (mine.y + 2) * SIZE)
  if mine.status == opened:
   screen.blit(img_dict[mine.around_mine_count], pos)
   opened_count += 1
  elif mine.status == double:
   screen.blit(img_dict[mine.around_mine_count], pos)
  elif mine.status == bomb:
   screen.blit(img_blood, pos)
  elif mine.status == flag:
   screen.blit(img_flag, pos)
   flag_count += 1
  elif mine.status == ask:
   screen.blit(img_ask, pos)
  elif mine.status == hint:
   screen.blit(img0, pos)
  elif game_status == over and mine.value:
   screen.blit(img_mine, pos)
  elif mine.value == 0 and mine.status == flag:
   screen.blit(img_error, pos)
  elif mine.status == normal:
   screen.blit(img_blank, pos)
Copy the code

Take a look at the results:

Then add the head part of the panel, including: display the number of thunder, restart button (smiling face), display time, the main code implementation is as follows:

print_text(screen, font1, 30, (SIZE * 2 - fheight) // 2 - 2, '%02d' % (MINE_COUNT - flag_count), red)
if game_status == started:
 elapsed_time = int(time.time() - start_time)
print_text(screen, font1, SCREEN_WIDTH - fwidth - 30, (SIZE * 2 - fheight) // 2 - 2, '%03d' % elapsed_time, red)
if flag_count + opened_count == BLOCK_WIDTH * BLOCK_HEIGHT:
 game_status = win
if game_status == over:
 screen.blit(img_face_fail, (face_pos_x, face_pos_y))
elif game_status == win:
 screen.blit(img_face_success, (face_pos_x, face_pos_y))
else:
 screen.blit(img_face_normal, (face_pos_x, face_pos_y))
Copy the code

Take a look at the results:

Then add various click events, the code implementation is as follows:

for event in pygame.event.get():
 if event.type == QUIT:
  sys.exit()
 elif event.type == MOUSEBUTTONDOWN:
  mouse_x, mouse_y = event.pos
  x = mouse_x // SIZE
  y = mouse_y // SIZE - 2
  b1, b2, b3 = pygame.mouse.get_pressed()
  ifGame_status == started: # Hold down the left and right mouse keys at the same time, if all mines have been marked, then open a circle around them; If not all mines have been marked, there will be an effect where all around are pressed simultaneouslyif b1 and b3:
    mine = block.getmine(x, y)
    if mine.status == opened:
     if not block.double_mouse_button_down(x, y):
      game_status = over
 elif event.type == MOUSEBUTTONUP:
  if y < 0:
   if face_pos_x <= mouse_x <= face_pos_x + face_size \
     and face_pos_y <= mouse_y <= face_pos_y + face_size:
    game_status = readied
    block = MineBlock()
    start_time = time.time()
    elapsed_time = 0
    continue
  if game_status == readied:
   game_status = started
   start_time = time.time()
   elapsed_time = 0
  ifGame_status == started: mine = block.getmine(x, y) #if b1 and not b3:
    if mine.status == normal:
     ifNot block.open_mine(x, y): game_status = over #if mine.status == normal:
     mine.status = flag
    elif mine.status == flag:
     mine.status = ask
    elif mine.status == ask:
     mine.status = normal
   elif b1 and b3:
    if mine.status == double:
     block.double_mouse_button_up(x, y)
Copy the code

Let’s take a look at the final implementation:

conclusion

In this article, we have implemented a simple minesweeper game in Python. If you are interested, you can put it into practice and see if you can remove all mines.

PS: Reply “Python” within the public number to enter the Python novice learning exchange group, together with the 100-day plan!

Old rules, brothers still remember, the lower right corner of the “watching” click, if you feel the content of the article is good, remember to share moments to let more people know!

[Code access ****]

Identify the qr code at the end of the article, reply: 201021