Write small games in python

# -*- 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:

 

Guess you like

Origin blog.csdn.net/yydsdeni/article/details/132548514