# -*- coding: utf-8 -*- # __/author__by:Kevin_F/__ import tkinter.messagebox import random import time import pygame import tkinter import tkinter.messagebox num_w = 30 # Number of horizontal grids num_h = 16 # Vertical grids Number # Interface initialization def window_init(): pygame.init() global window # Grid size 30*30, status bar height 100, upper, lower, left and right borders 20 window = pygame.display.set_mode((30 * num_w + 20 * 2, 100 + 30 * num_h + 2 * 40)) pygame.display.set_caption('Minesweeper xp') window.fill((128, 138, 135)) # Background color: cool gray pygame.draw.rect(window, (192, 192, 192), (0, 0, 30 * num_w + 20 * 2, 100)) # Top status box for j in range(num_h): for i in range(num_w): # Grid coordinate block_x = 20 + i * 30 block_y = 100 + 20 + j * 30 list_block.append([block_x, block_y, 0, 0]) list_block_pos.append((block_x, block_y)) """ list_temp generates and stores the coordinate information block_x of the grid in each row: The x coordinate of the grid block_y: The y coordinate of the grid (the coordinate information is fixed and cannot be modified, so it is represented by a tuple) 0: Defines whether this grid is a thunder or a thunder: -1 Not a thunder: Indicates the number of adjacent non-ray grids in the surrounding area , first write the default value as 0 0: Define the marking status of the grid 0-unmarked, that is, the initial value 1-mark is thunder 2-mark question mark 3-left click to open """ pygame.draw.rect(window, ( 192, 192, 192), (block_x, block_y, 30, 30), 0) # Solid grid pygame.draw.rect(window, (220, 220, 220), (block_x, block_y, 30, 30), 2) # Grid edge pygame.display.flip() # The remaining number of mines in the status bar def bomb_les(): global count_bomb if count_bomb < 0: count_bomb = 0 # There is no possibility of marking mines exceeding 99, because the unmarked state can only be marked first Thunder-1, then right-click to unmark Thunder+1 pygame.draw.rect(window, (192, 192, 192), (0, 0, 150, 100), 0) font_bomb_num = pygame.font.SysFont('Microsoft YaHei ', 60, bold=True) bomb_num = font_bomb_num.render(str(count_bomb), True, (255, 0, 0)) window.blit(bomb_num, (20, 10)) pygame.display.update() # Status Bar status display def game_status(status): img_working = pygame.image.load('me.png') img_bad = pygame.image.load('yc.png') img_win = pygame.image.load('yes.png' ) if status == 'working': # The picture when the game starts window.blit(img_working, (15 * num_w + 20 - 45, 5)) elif status == 'loose': # The picture when the game fails window.blit( img_bad, (15 * num_w + 20 - 45, 5)) elif status == 'win': # Game victory picture window.blit(img_win, (15 * num_w + 20 - 45, 5)) else: pass pygame.display.update() # Game initialization (randomly generate a mine, initialize the position information and status information of each grid) def game_init(): # Randomly generate 99 mines a = random.randint(10, 100) global list_bomb_pos list_bomb_pos = random.sample(list_block_pos, a) # Take 99 non-repeating ones from all the grids, that is, get 99 position coordinates (x, y), and the resulting list is the coordinate list of all mines # Rewrite the grid in list_block The third value of is changed from 0 to -1, which means it is thunder. for i in range(len(list_bomb_pos)): for j in range(len(list_block)): if list_block[j][0] == list_bomb_pos[i ][0] and list_block[j][1] == list_bomb_pos[i][1]: list_block[j][2] = -1 # If the grid is not a mine, calculate the number of mines around the grid and write it in list_block for index in range(len(list_block)): # index is the subscript of list_block x = index % 30 y = index // 30 if list_block[index][2] == -1: continue else: list_beside = list_side( x, y) mark_num = 0 # Define a variable to store the number of grids surrounded by thunder for element in list_beside: if element[2] == -1: mark_num += 1 list_block[index][2 ] = mark_num # Write the number of surrounding mines into the third value in list_block # Initialize a list to store the coordinates of grids that are not mines for i in list_block_pos: if i not in list_bomb_pos: list_not_bomb.append(i) # Get a list that stores the adjacent grids around this grid (the return value of this function is defined to be this list) def list_side(x, y): if 1 <= x <= 28 and 1 <= y <= 14: list_side = [ list_block[x - 1 + (y - 1) * 30], list_block[x + (y - 1) * 30], list_block[x + 1 + (y - 1) * 30], list_block[x - 1 + y * 30], list_block[x + 1 + y * 30], list_block[x - 1 + (y + 1) * 30], list_block[x + (y + 1) * 30], list_block[x + 1 + (y + 1) * 30] ] elif x == 0 and 1 <= y <= 14: list_side = [ list_block[(y - 1) * 30], list_block[1 + (y - 1) * 30], list_block[1 + y * 30], list_block[(y + 1) * 30], list_block[1 + (y + 1) * 30] ] elif x == 29 and 1 <= y <= 14: list_side = [ list_block[28 + (y - 1) * 30], list_block[29 + (y - 1) * 30], list_block[28 + y * 30], list_block[28 + (y + 1) * 30], list_block[ 29 + (y + 1) * 30] ] elif 1 <= x <= 28 and y == 0: list_side = [ list_block[x - 1 + y * 30], list_block[x + 1 + y * 30], list_block[x - 1 + (y + 1) * 30], list_block[x + (y + 1) * 30], list_block[x + 1 + (y + 1) * 30] ] elif 1 <= x <= 28 and y == 15: list_side = [ list_block[x - 1 + (y - 1) * 30], list_block[x + (y - 1) * 30], list_block[x + 1 + (y - 1) * 30], list_block[x - 1 + y * 30], list_block[x + 1 + y * 30] ] elif x == 0 and y == 0: list_side = [list_block[1], list_block[30], list_block[31]] elif x == 0 and y == 15: list_side = [list_block[420], list_block[421], list_block[451]] elif x == 29 and y == 0: list_side = [list_block[28], list_block[58], list_block[59]] else: list_side = [list_block[448], list_block[449], list_block[478]] return list_side # 绘制鼠标点击后的格子 def draw_block(para, x, y): if para == 0: # 此格子周围格子都不是雷,此格子直接画个实心方块 pygame.draw.rect(window, (180, 180, 180), (x * 30 + 20, y * 30 + 120, 30, 30), 0) elif para in [1, 2, 3, 4, 5, 6, 7, 8]: # 此格子周围有雷,显示周围雷的数量 colors = { 1: (0, 0, 255), 2: (34, 139, 34), 3: (25, 25, 112), 4: (160, 32, 240), 5: (94, 38, 18), 6: (199, 97, 20), 7: (240, 230, 140), 8: (240, 230, 140) } num_font = pygame.font.SysFont('SimHei', 24, bold=True) text_num = num_font.render(str(para), True, colors[para]) w1, h1 = text_num.get_size() window.blit(text_num, (x * 30 + 35 - w1 / 2, y * 30 + 135 - h1 / 2)) elif para == 'bomb': # 左键点击到雷的时候,地雷爆炸(变红色) pygame.draw.circle(window, (0, 0, 0), (x * 30 + 35, y * 30 + 135), 12) elif para == 'mark': # 右键标记为雷时,画个红色实心圆表示地雷 pygame.draw.rect(window, (192, 192, 192), (x * 30 + 20, y * 30 + 120, 30, 30), 0) # 实心格子 pygame.draw.rect(window, (220, 220, 220), (x * 30 + 20, y * 30 + 120, 30, 30), 2) # 格子边线 pygame.draw.circle(window, (255, 0, 0), (x * 30 + 35, y * 30 + 135), 11) elif para == '?': # 右键标记?,格子上显示? num_font = pygame.font.SysFont('SimHei', 24) text_num = num_font.render('?', True, (255, 0, 0)) w1, h1 = text_num.get_size() pygame.draw.rect(window, (192, 192, 192), (x * 30 + 20, y * 30 + 120, 30 , 30), 0) # Solid grid pygame.draw.rect(window, (220, 220, 220), (x * 30 + 20, y * 30 + 120, 30, 30), 2) # Grid edge window. blit(text_num, (x * 30 + 35 - w1 / 2, y * 30 + 135 - h1 / 2)) elif para == 'blank': # When the right button is switched to the unmarked state, the grid pygame is drawn during initialization .draw.rect(window, (192, 192, 192), (x * 30 + 20, y * 30 + 120, 30, 30), 0) # Solid grid pygame.draw.rect(window, (220, 220 , 220), (x * 30 + 20, y * 30 + 120, 30, 30), 2) # Grid edge else: pass pygame.display.update() # Minesweeper left mouse click event def mouse_click_left(mouse_x, mouse_y ): global list_block, is_loose, count_click pos_x = (mouse_x - 20) // 30 pos_y = (mouse_y - 120) // 30 index = pos_x + pos_y * 30 # The subscript index of list_block # triggered the left click event at this location , you must first express the left-click event at this position if list_block[index][3] == 3: # If this grid has been opened by left-click, you cannot click pass again : # First determine whether the click is a thunder , if it is thunder, the game fails if list_block[index][2] == -1: # If the left mouse click is thunder, the game fails is_loose = True for x, y in list_bomb_pos: draw_block('bomb', (x - 20) / / 30, (y - 120) // 30) # Mark the currently clicked thunder in red pygame.draw.rect(window, (255, 0, 0), (20 + pos_x * 30, 120 + pos_y * 30 , 30, 30), 0) draw_block('bomb', pos_x, pos_y) game_status('loose') # The game has failed. Clicking the minesweeper area again at this time will be invalid # Stop the timer else: # If it is not a mine, then click again Determine whether the surrounding mine number of this grid is 0. If it is 0, continue to trigger the left click to open 8 grids around the grid. # In addition to drawing the left-click event of the current position, you also need to determine whether the current surrounding mine number is 0. # If it is 0, automatically trigger the left-click event of the 8 adjacent grids around this grid (because 0 means that the surrounding 8 grids are not mines, directly and automatically left-click to display the number of surrounding mines for each of these 8 grids) # If Among these 8 grids, if there are any surrounding thunder numbers of 0, then the function if list_block[index][2] == 0 is called recursively: draw_block(list_block[index][2], pos_x, pos_y) list_block[index][3 ] = 3 list_beside = list_side(pos_x, pos_y) for i in list_beside: x = (i[0] - 20) // 30 y = (i[1] - 120) // 30 if list_block[x + 30 * y ][3] == 0: # Determine the marking status of this position (the last parameter in list_block), 0-unmarked mouse_click_left(x * 30 + 20, y * 30 + 120) # Call the function draw_block(list_block[x + 30 * y][2], x, y) # Draw the shape after left-click list_block[x + 30 * y][3] = 3 # Calling the function means that a left-click occurred (even if it is automatically triggered by the computer, instead of human operation), change the mark status to 3 else: # There are no mines around the grid is 0, directly displays the number of surrounding mines of the grid. draw_block(list_block[index][2], pos_x, pos_y) list_block[index][3] = 3 count_click = 0 for i in list_block ; _ _ _ _ The total number of grids, the game wins # Right-click event of mouse in minesweeping area def mouse_click_right(mouse_x, mouse_y): global count_bomb pos_x = (mouse_x - 20) // 30 pos_y = (mouse_y - 120) // 30 index = pos_x + pos_y * 30 # List_block subscript index status = list_block[index][3] # The game is over, you can no longer right-click if is_loose: import tkinter.messagebox tkinter.messagebox.showinfo('Minesweeper xp','You are dead') # - *- conding:utf-8 -*- while True: # Check the music stream playback, return True if there is any, and False if not # If there is no music stream, choose to play if pygame.mixer.music.get_busy() == False: pygame. mixer.music.play() else: # Right click, the grid display status is 0-unmarked 1-marked 2-marked? Cycle switching between the three states if status == 0: # If this grid is currently in the unmarked state draw_block('mark', pos_x, pos_y) list_block[index][3] = 1 count_bomb -= 1 elif status == 1 : draw_block('?', pos_x, pos_y) list_block[index][3] = 2 count_bomb += 1 elif status == 2: draw_block('blank', pos_x, pos_y) list_block[index][3] = 0 else : # The position that has been left-clicked cannot be right-clicked (that is, status=3) pass # Middle mouse button event in the minesweeper area def mouse_click_mid(mouse_x, mouse_y): # Middle mouse click on the grid means scanning the surrounding areas of the grid. Adjacent grid # This grid can only be opened by left-clicking (list_block[index][3]==3), and the number of mines surrounding the grid (list_block[index][2]) = the total number of marked mines # Triggered by the middle button Automatically left-click to open surrounding non-mine grids (which have not been opened by left-clicking before). If left-clicked before, skip pos_x = (mouse_x - 20) // 30 pos_y = (mouse_y - 120) // 30 index = pos_x + pos_y * 30 # The subscript of list_block index status = list_block[index][3] list_beside = list_side(pos_x, pos_y) mark_bomb_sum = 0 for item in list_beside: if item[3] == 1: # item [3] is equivalent to list_block[index][3] If the value is 1, the mark is mark_bomb_sum += 1 if list_block[index][3] == 3 and list_block[index][2] == mark_bomb_sum and list_block [index][2] != 0: # This grid can only be opened by left-clicking (list_block[index][3]==3), and the number of mines around the grid (list_block[index][2]) = marked mines The total number of items, and not equal to 0 for item in list_beside: # The middle button triggers automatic left-clicking to open surrounding non-mine grids (which have not been left-clicked before). If left-clicked before, skip if item[3] == 3 or item[3] == 1 or item[3] == 2: # The status is 3, indicating that the left click has been opened, the status is 1, indicating that the mark is thunder, the status is 2, indicating doubt, these three situations cannot trigger the left mouse click eventcontinue else: mouse_click_left(item[0], item[1]) def main(): global is_loose, list_block, list_block_pos, list_bomb_pos, list_not_bomb, count_click, count_bomb, num_not_bomb, t_start list_block_pos = [] # Used to store the position of each grid Coordinate information (x, y) list_block = [] # Used to store the coordinates and status information of each grid, that is, each element = [x, y, 0, 0] list_bomb_pos = [] # Used to store the elements of mine Coordinates list_not_bomb = [] # Used to store the coordinates of grids that are not mines count_click = 0 # Used to record the number of grids opened by left-clicking window_init() game_status('working') game_init() is_loose = False num_not_bomb = len(list_block_pos) - len(list_bomb_pos) count_bomb = len(list_bomb_pos) while True: bomb_les() if 0 <= count_click < num_not_bomb and not is_loose: if count_click == 0: t_start = int(time.time()) # Inside the while True loop , if count_click=0, it means there is no left click of the mouse, and there is no timer at this time # At this time, because while True keeps looping, the value of t_start will always be refreshed and the current time will be continuously obtained # When count_click starts from 1, that is, once a left click occurs Click, if the above if condition count_click==0 is not established, the value of t_start will not be refreshed # The value of t_start is fixed at the value of the previous cycle before count_click=1, that is, the value of the last cycle before the left click, thus achieving Left-click to start timing t_show = int(time.time()) - t_start pygame.draw.rect(window, (192, 192, 192), (720, 0, 200, 100), 0) font_time = pygame.font. SysFont('Microsoft YaHei', 60, bold=True) text_time = font_time.render(str(t_show), True, (255, 0, 0)) window.blit(text_time, (920 - text_time.get_size()[0 ], 10)) # Display the time to the right pygame.display.update() else: # If the game succeeds (count_click = num_not_bomb) or the game fails (is_loose=True), stop the time display # !/usr/bin/python # - *- coding: UTF-8 -*- # Python2.x import method # Python3.x import method # from tkinter import * pass for event in pygame.event.get(): if event.type == pygame.QUIT: exit () elif event.type == pygame.MOUSEBUTTONDOWN: if is_loose: game_status('loose') continue elif count_click < num_not_bomb: mouse_x, mouse_y = pygame.mouse.get_pos() click = pygame.mouse.get_pressed() if 20 <= mouse_x <= 920 and 120 <= mouse_y <= 600: if click == (True, False, False): # mouse left click mouse_click_left(mouse_x, mouse_y) elif click == (False, True, False): # middle mouse button mouse_click_mid(mouse_x , mouse_y) elif click == (False, False, True): # Right mouse button mouse_click_right(mouse_x, mouse_y) else: # When count_click == num_not_bomb, it means that all non-mine grids have been clicked, and the game is won game_status(' win') elif event.type == pygame.MOUSEBUTTONUP: mouse_x1, mouse_y1 = pygame.mouse.get_pos() if 0 <= mouse_x1 - (15 * num_w + 20 - 45) <= 90 and 10 <= mouse_y1 <= 100 : # When the mouse is left-clicked on the status icon, it means the game has started return main() # The game starts or the game is restarted if __name__ == '__main__': import tkinter import PySimpleGUI as sg count = range(100) for i, item in enumerate(count): sg.one_line_progress_meter('Mine Sweeper xp', i + 1, len(count), 'Mine Sweeper xp progress') # Assume that this code part takes 0.05s time.sleep(0.000001) main()
Running screenshot: