Above
hello everyone! I'm classmate pear!
I hope you can support me! ha-ha
To thank everyone who cares about me: 💓 The project source code of each article is shared free of charge 💓 See the end of the text!
Many functions of csdn are still under research, and it's no wonder that Xiaobian's writing is not good. He will slowly improve and learn from you
Xiaobian has also been learning programming. If there are errors in the code applet, please leave a message in the comment area!
Finally - if the article helps you, remember to "pay attention", "like" and "comment"~
Foreword
Minesweeper is a popular puzzle game, which was released in 1992.
The goal of the game is to find out all non thunder grids according to the numbers in the click grid in the shortest time, and avoid stepping on thunder and stepping on one
Ray lost everything.
It's the first game many people come into contact with. It's probably the best game for office workers and net free students when they are bored, isn't it
Every time I see a villain wearing sunglasses, I have a sense of achievement? In those years when there was no net (cut-off net), minesweeping accompanied countless people
After their childhood. What's your best record? Xiaobian brushed a game for 30 seconds between work 😳).
So? How can I get through customs? This may not be possible in our lifetime. BUT we can rely on our Python
Automatic Minesweeper! Don't panic ~ let's officially start!
Automatic minesweeping
Environment configuration:
Python 3, pychar, Pygame and some built-in modules.
Installation of third-party library: pip  install pygame
Effect display:
Game start:
Â
Automatic minesweeping:
Â
Â
game over:
Â
Code demonstration:
1) Main program
The code is relatively simple. There are comments on each line. You can read it yourself. If you don't understand it, you can talk to me and learn together!
# -*- coding: utf-8 -*- import pygame from pygame.locals import * import numpy as np import random import sys import time import copy # Screen size Screen_Size = (1200, 600) # Number of rows Rows = 20 # Number of columns Colums = 40 # Number of Mines numOfMines = 80 # winning probability VictoryRate=0 class Sweep(object): """docstring for Sweep""" def __init__(self): # Initialize a page self.Screen = pygame.display.set_mode(Screen_Size) # typeface self.myfont = pygame.font.SysFont('Immature', 25) # Lattice size self.gwide = int(Screen_Size[0] / Colums) self.gheight = int(Screen_Size[1] / Rows) self.board = np.zeros((Rows, Colums)) # Store the optional location for the next step self.NBS = [] # NBS auxiliary container is used to judge whether NBS has changed self.NBSTool = [] # Judge whether to conduct probability selection minesweeping self.GO = False # Traversing storage containers self.container = [] # Label mine storage container self.mineContainer = [] # Actual mine location storage container self.Mines = [] # Digital storage container self.numbers = [] # Load picture self.LoadImg() # Draw grid self.DrawGrid() # Buried mine self.HideMines() def LoadImg(self): # Load mine picture self.mine = pygame.image.load('image/mine.jpg').convert_alpha() self.mine = pygame.transform.scale( self.mine, (self.gwide, self.gheight)) # Load flag picture self.flag = pygame.image.load('image/flag.jpg').convert_alpha() self.flag = pygame.transform.scale( self.flag, (self.gwide, self.gheight)) # Load mine explosion picture self.boom = pygame.image.load('image/boom.png').convert_alpha() self.boom = pygame.transform.scale( self.boom, (self.gwide, self.gheight)) # Load digital picture self.num1 = pygame.image.load('image/1.png') self.num1 = pygame.transform.scale( self.num1, (self.gwide, self.gheight)) self.num2 = pygame.image.load('image/2.png') self.num2 = pygame.transform.scale( self.num2, (self.gwide, self.gheight)) self.num3 = pygame.image.load('image/3.png') self.num3 = pygame.transform.scale( self.num3, (self.gwide, self.gheight)) self.num4 = pygame.image.load('image/4.png') self.num4 = pygame.transform.scale( self.num4, (self.gwide, self.gheight)) self.num5 = pygame.image.load('image/5.png') self.num5 = pygame.transform.scale( self.num5, (self.gwide, self.gheight)) self.num6 = pygame.image.load('image/6.png') self.num6 = pygame.transform.scale( self.num6, (self.gwide, self.gheight)) self.num7 = pygame.image.load('image/7.png') self.num7 = pygame.transform.scale( self.num7, (self.gwide, self.gheight)) self.num8 = pygame.image.load('image/8.png') self.num8 = pygame.transform.scale( self.num8, (self.gwide, self.gheight)) # Setting background image after loading access self.back = pygame.image.load('image/back.jpg') self.back = pygame.transform.scale( self.back, (self.gwide, self.gheight)) # Failed to load game background self.gameOver=pygame.image.load('image/gameover.jpg') self.gameOver=pygame.transform.scale(self.gameOver,Screen_Size) # Load game victory background self.victoryOver=pygame.image.load('image/victory.jpg') self.victoryOver=pygame.transform.scale(self.victoryOver,Screen_Size) def HideMines(self): """Buried mine""" for i in range(numOfMines): while True: y = random.randint(0, Colums - 1) x = random.randint(0, Rows - 1) if self.board[x][y] == 0: self.board[x][y] = -1 self.Mines.append((x, y)) break def ShowAllMines(self): """ Show the location of all mines """ for i in range(Rows): for j in range(Colums): if self.board[i][j] == -1: self.Screen.blit( self.mine, (self.gwide * j, self.gheight * i)) def DrawGrid(self): """ Draw background interface """ self.Screen.fill((191, 251, 255)) # Draw a horizontal line for i in range(1, Rows): pygame.draw.line( self.Screen, (0, 0, 0), (0, self.gheight * i), (Screen_Size[0], self.gheight * i)) # Draw a vertical line for i in range(1, Colums): pygame.draw.line(self.Screen, (0, 0, 0), (self.gwide * i, 0), (self.gwide * i, Screen_Size[1])) def NumOfPos(self, pos): """ Returns the number of mines around a point pos Map coordinates At the same time, set the number of mines at the corresponding position of the two-dimensional array """ n = 0 y, x = pos[0], pos[1] if x - 1 >= 0: if self.board[x - 1][y] == -1: n += 1 if y - 1 >= 0 and self.board[x - 1][y - 1] == -1: n += 1 if y + 1 <= Colums - 1 and self.board[x - 1][y + 1] == -1: n += 1 if x + 1 <= Rows - 1: if self.board[x + 1][y] == -1: n += 1 if y - 1 >= 0 and self.board[x + 1][y - 1] == -1: n += 1 if y + 1 <= Colums - 1 and self.board[x + 1][y + 1] == -1: n += 1 if y - 1 >= 0 and self.board[x][y - 1] == -1: n += 1 if y + 1 <= Colums - 1 and self.board[x][y + 1] == -1: n += 1 # self.board[x][y] = n return n def SetNumOfPos(self, pos): """ Set the number of mines around a safety point pos Is the map coordinates """ n = self.NumOfPos(pos) if n == 0: self.Screen.blit( self.back, (self.gwide * pos[0], self.gheight * pos[1])) if n == 1: self.Screen.blit( self.num1, (self.gwide * pos[0], self.gheight * pos[1])) if n == 2: self.Screen.blit( self.num2, (self.gwide * pos[0], self.gheight * pos[1])) if n == 3: self.Screen.blit( self.num3, (self.gwide * pos[0], self.gheight * pos[1])) if n == 4: self.Screen.blit( self.num4, (self.gwide * pos[0], self.gheight * pos[1])) if n == 5: self.Screen.blit( self.num5, (self.gwide * pos[0], self.gheight * pos[1])) if n == 6: self.Screen.blit( self.num6, (self.gwide * pos[0], self.gheight * pos[1])) if n == 7: self.Screen.blit( self.num7, (self.gwide * pos[0], self.gheight * pos[1])) if n == 8: self.Screen.blit( self.num8, (self.gwide * pos[0], self.gheight * pos[1])) return n def NeighborsOf(self, pos): """ Get the neighbor coordinates of a point pos Is the coordinates of a two-dimensional array """ x, y = pos[0], pos[1] neibors = [] if x - 1 >= 0: if y - 1 >= 0: neibors.append((x - 1, y - 1)) if y + 1 <= Colums - 1: neibors.append((x - 1, y + 1)) neibors.append((x - 1, y)) if x + 1 <= Rows - 1: if y - 1 >= 0: neibors.append((x + 1, y - 1)) if y + 1 <= Colums - 1: neibors.append((x + 1, y + 1)) neibors.append((x + 1, y)) if y - 1 >= 0: neibors.append((x, y - 1)) if y + 1 <= Colums - 1: neibors.append((x, y + 1)) return neibors def Boom(self, pos): """ pos Is a 2D array position """ self.Screen.blit( self.boom, (self.gwide * pos[1], self.gheight * pos[0])) # pygame.display.update() def Ergodic(self, pos): """ Diverge from one position to all around until it meets the position with thunder,Is a recursive function pos Is the coordinates of a two-dimensional array Convert 2D array pos The coordinates and the number of surrounding mines are stored in the container self.container in """ x, y = pos[0], pos[1] # If the number of mines around the location is not 0, stop if self.NumOfPos((y, x)) > 0 and self.board[x][y] != -1: self.numbers.append(pos) return # Store the two-dimensional array pos coordinates and the number of mines around in the container self In container if self.board[x][y] != -1: self.container.append(pos) # Upward traversal if x - 1 >= 0 and (x - 1, y) not in self.container: self.Ergodic((x - 1, y)) # Traversal down if x + 1 <= Rows - 1 and (x + 1, y) not in self.container: self.Ergodic((x + 1, y)) # Want to traverse left if y - 1 >= 0 and (x, y - 1) not in self.container: self.Ergodic((x, y - 1)) # Box right traversal if y + 1 <= Colums - 1 and (x, y + 1) not in self.container: self.Ergodic((x, y + 1)) def DrawContainer(self): # self.ShowAllMines() for pos in self.container: x, y = pos[0], pos[1] self.SetNumOfPos((y, x)) def DrawNumbers(self): for pos in self.numbers: self.SetNumOfPos((pos[1], pos[0])) def DrawFlags(self): for pos in self.mineContainer: self.Screen.blit( self.flag, (pos[1] * self.gwide, pos[0] * self.gheight)) def Removed(self): n = 0 for pos in self.mineContainer: if pos in self.Mines: n += 1 return n def AutoPlay(self): # Random position of two-dimensional array x = random.randint(0, Rows - 1) y = random.randint(0, Colums - 1) print("Step 1:",self.board[x][y]) if self.board[x][y]==-1: self.Boom((x,y)) pygame.display.update() self.GameOver() print(x, y) while True: for ev in pygame.event.get(): if ev.type == pygame.QUIT: sys.exit(0) if self.board[x][y] == -1: self.Boom((x, y)) time.sleep(3) sys.exit(0) # Draw grid self.DrawGrid() # Divergent traversal self.Ergodic((x, y)) # Draw the position that has been traversed and there is no thunder around (with white background) self.DrawContainer() # Draw the position that has been traversed but surrounded by thunder (in numbers) self.DrawNumbers() # Find out all possible positions for the next step self.NextSteps() # Draw the location of the marked mine (with a flag) self.DrawFlags() # Find out where the mine must be and mark it (with a flag) self.SetFlags() # Find out the location mark (number or blank) where there must be no thunder self.NoMines() # When NBS is 0, probability selection self.ChooseWithBigProbability() # Refresh pygame.display.update() # Print the number of marked mines print("Number of Mines marked:", len(self.mineContainer)) print("Number of Mines removed:", self.Removed()) if self.Removed()==numOfMines: time.sleep(3) self.Victory() def NextSteps(self): """ Find out the optional position for the next minesweeping Algorithm idea: Eight neighborhoods have been visited to find the location of each mine that has been marked with the number of surrounding mines These positions are the possible positions for the next step """ self.NBS.clear() for pos in self.numbers: for n in self.NeighborsOf(pos): if n not in self.NBS + self.container + self.numbers: self.NBS.append(n) if self.NBSTool == self.NBS: print(self.GO) self.GO = True self.NBSTool = copy.deepcopy(self.NBS) # print(self.NBS) def SetFlags(self): """ Find out where there must be thunder and mark it with a flag Algorithm idea: For each location marked with the number of mines, find out the location that has not been visited in the eight neighborhoods of the location, Find out the number of mines not found. If the number of mines not found around the location is greater than or equal to the allowable number The number of walking positions, then the remaining eight neighborhood walkable positions of the position must be all mines, and mark the position For the mine and put it in self.mineContainer container """ for pos in self.numbers: s = list(set(self.NeighborsOf(pos)) - set(self.container) - set(self.numbers) - set(self.mineContainer)) s1 = list(set(self.NeighborsOf(pos)) - set(self.container) - set(self.numbers)) # if self.NumOfPos((pos[1], pos[0])) == 1 and len(s) == 1: if self.NumOfPos((pos[1], pos[0])) - len(set(s1) & set(self.mineContainer)) >= len(s): if self.board[pos[0]][pos[1]] == -1: self.Boom(pos) time.sleep(3) sys.exit(0) for pos1 in s: self.mineContainer.append(pos1) self.Screen.blit( self.flag, ((self.gwide * pos1[1], self.gheight * pos1[0]))) # time.sleep(1) # pygame.display.update() def NoMines(self): """ Find a location where there are no mines Algorithm idea: For each location marked with the number of surrounding mines, find the remaining mines in the eight neighborhoods of the location Check if all the mines around the current location have been marked, If all of them have been marked, there are still unreachable locations in the eight neighborhoods of the location ,If the number of mines around the location is 0, use Ergodic()Function traversal, if If the number of mines around the location is not 0, indicate the number of mines at the location """ for pos in self.numbers: s = list(set(self.NeighborsOf(pos)) - set(self.container) - set(self.numbers) - set(self.mineContainer)) if self.NumOfPos((pos[1], pos[0])) == len(set(self.NeighborsOf(pos)) & set(self.mineContainer)): for pos1 in s: if self.board[pos1[0]][pos1[1]] == -1: self.mineContainer.append(pos) continue if self.NumOfPos((pos1[1], pos1[0])) == 0: self.container.append(pos1) self.Ergodic(pos1) self.Screen.blit( self.back, (pos1[1] * self.gwide, pos1[0] * self.gheight)) continue if self.NumOfPos((pos1[1], pos1[0])) > 0: self.SetNumOfPos((pos1[1], pos1[0])) self.numbers.append(pos1) # self.DrawContainer() # pygame.display.update() def ChooseWithBigProbability(self): """ Probability selection function Algorithm idea: When encountering the situation that it is uncertain whether there is thunder or no thunder, find the location that has not been visited Find out the sum of the number of mines at the locations marked with the number of mines in the eight neighborhoods of these locations, and use And divided by 8, these locations and their corresponding probabilities are stored in the container, and the probabilities are calculated from large to small Sequential sorting, if the probability of the position with the highest probability is greater than or equal to 0.75,Then the location Mark as mine if the probability is less than 0.75,Then find out if you haven't visited and are not in the next step The planned position is the position of the container. Select a position at random. If you step on the thunder, the game ends, If there are no mines around the location, call Ergodic()If there are mines around Then mark the number of mines at that location """ if self.GO == True: print("Enter probability selection environment") noSeen = [] # Quantity to be cleared leftmines=numOfMines-self.Removed() # Find the location that has not been traversed for i in range(Rows): for j in range(Colums): if (i, j) not in self.container + self.mineContainer + self.numbers: s = list(set(self.NeighborsOf((i, j))) & set(self.numbers)) numerator = 0 for s1 in s: numerator += self.NumOfPos((s1[1], s1[0])) # Calculation probability noSeen.append([(i, j), numerator / 8]) sorted(noSeen, key=lambda proba: proba[1], reverse=True) if noSeen != []: if noSeen[0][1] >= 0.75: pos = noSeen[0][0] self.mineContainer.append(pos) else: nos = [p[0] for p in noSeen] s = list(set(nos) - set(self.NBS)) index = 0 pos = (-1, -1) if len(s) > 1: index = random.randint(0, len(s) - 1) pos = s[index] elif len(s) == 1: pos = s[0] elif s == []: pos = noSeen[0][0] if self.board[pos[0]][pos[1]] == -1: self.Boom(pos) time.sleep(2) self.GameOver() elif self.NumOfPos((pos[1], pos[0])) > 0: self.numbers.append(pos) elif self.NumOfPos((pos[1], pos[0])) == 0: self.Ergodic(pos) noSeen.clear() self.GO = False def GameOver(self): for pos in self.Mines: self.Boom(pos) pygame.display.update() time.sleep(0.1) self.Screen.blit(self.gameOver,(0,0)) VictoryRate=content="Demining rate:%d"%((self.Removed()/numOfMines)*100) text=self.myfont.render(content+'%',True,(0,0,0),(255,255,255)) self.Screen.blit(text,(500,150)) pygame.display.update() time.sleep(5) sys.exit(0) def Victory(self): # if self.Removed()==numOfMines: VictoryRate=100 self.Screen.blit(self.victoryOver,(0,0)) pygame.display.update() time.sleep(5) sys.exit(0) def Show(self): self.DrawGrid() self.ShowAllMines() pygame.display.update() time.sleep(5) self.DrawGrid() pygame.display.update() time.sleep(3) while True: for ev in pygame.event.get(): if ev.type == pygame.QUIT: sys.exit(0) self.AutoPlay() pygame.display.update() if __name__ == '__main__': pygame.display.init() pygame.font.init() app = Sweep() app.Show()
ending
What's the saying - are there any people who can pass the customs manually without relying on AI mine clearance?
Automatic mine sweeping, there is a mine sweeping, these two source codes can find me to play by myself, ha!
Follow Xiaobian for more wonderful content!
It's not easy to make. Remember to click three times!! If you need packaged source code + materials, share them for free!! Portal
Â